From eec3a6152493e56866ec5338ff52f823c530778e Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Fri, 27 Sep 2024 13:29:36 -0400 Subject: [PATCH] feat(ssa): Simplify signed casts (#6166) # Description ## Problem\* Resolves Small optimization I noticed while working on other tasks. ## Summary\* We currently simplify when casting to a field or an unsigned type. We can also simplify when casting to a signed type. This is an initial version that is quite conservative in the simplification. If we we have a constant that is below `2^(bit_size-1)` when casting to a signed type we return the constant with the new signed type. I also added the case of signed -> field as this can be the same as going unsigned -> field. ## Additional Context ## Documentation\* Check one: - [X] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [X] I have tested the changes locally. - [X] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .../src/ssa/ir/instruction/cast.rs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs index d0ed5a1fa9c..ed588def1d7 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs @@ -27,10 +27,10 @@ pub(super) fn simplify_cast( SimplifiedTo(value) } ( - Type::Numeric(NumericType::Unsigned { .. }), + Type::Numeric(NumericType::Unsigned { .. } | NumericType::Signed { .. }), Type::Numeric(NumericType::NativeField), ) => { - // Unsigned -> Field: redefine same constant as Field + // Unsigned/Signed -> Field: redefine same constant as Field SimplifiedTo(dfg.make_constant(constant, dst_typ.clone())) } ( @@ -48,6 +48,24 @@ pub(super) fn simplify_cast( let truncated = FieldElement::from_be_bytes_reduce(&truncated.to_bytes_be()); SimplifiedTo(dfg.make_constant(truncated, dst_typ.clone())) } + ( + Type::Numeric( + NumericType::NativeField + | NumericType::Unsigned { .. } + | NumericType::Signed { .. }, + ), + Type::Numeric(NumericType::Signed { bit_size }), + ) => { + // Field/Unsigned -> signed + // We only simplify to signed when we are below the maximum signed integer of the destination type. + let integer_modulus = BigUint::from(2u128).pow(*bit_size - 1); + let constant_uint: BigUint = BigUint::from_bytes_be(&constant.to_be_bytes()); + if constant_uint < integer_modulus { + SimplifiedTo(dfg.make_constant(constant, dst_typ.clone())) + } else { + None + } + } _ => None, } } else if *dst_typ == dfg.type_of_value(value) {