Skip to content

Commit 2ca9b05

Browse files
authored
fix: use 128 bits for constant bit shift (#3586)
1 parent 9b9ed89 commit 2ca9b05

File tree

2 files changed

+30
-26
lines changed
  • compiler/noirc_evaluator/src/ssa/function_builder
  • tooling/nargo_cli/tests/execution_success/bit_shifts_comptime/src

2 files changed

+30
-26
lines changed

compiler/noirc_evaluator/src/ssa/function_builder/mod.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -282,32 +282,34 @@ impl FunctionBuilder {
282282
) -> ValueId {
283283
let base = self.field_constant(FieldElement::from(2_u128));
284284
let typ = self.current_function.dfg.type_of_value(lhs);
285-
let (max_bit, pow) = if let Some(rhs_constant) =
286-
self.current_function.dfg.get_numeric_constant(rhs)
287-
{
288-
// Happy case is that we know precisely by how many bits the the integer will
289-
// increase: lhs_bit_size + rhs
290-
let (rhs_bit_size_pow_2, overflows) =
291-
2_u32.overflowing_pow(rhs_constant.to_u128() as u32);
292-
if overflows {
293-
let zero = self.numeric_constant(FieldElement::zero(), typ);
294-
return InsertInstructionResult::SimplifiedTo(zero).first();
295-
}
296-
let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2 as u128), typ);
297-
(bit_size + (rhs_constant.to_u128() as u32), pow)
298-
} else {
299-
// we use a predicate to nullify the result in case of overflow
300-
let bit_size_var =
301-
self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone());
302-
let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var);
303-
let one = self.numeric_constant(FieldElement::one(), Type::unsigned(1));
304-
let predicate = self.insert_binary(overflow, BinaryOp::Eq, one);
305-
let predicate = self.insert_cast(predicate, typ.clone());
306-
307-
let pow = self.pow(base, rhs);
308-
let pow = self.insert_cast(pow, typ);
309-
(FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow))
310-
};
285+
let (max_bit, pow) =
286+
if let Some(rhs_constant) = self.current_function.dfg.get_numeric_constant(rhs) {
287+
// Happy case is that we know precisely by how many bits the the integer will
288+
// increase: lhs_bit_size + rhs
289+
let (rhs_bit_size_pow_2, overflows) =
290+
2_u128.overflowing_pow(rhs_constant.to_u128() as u32);
291+
if overflows {
292+
assert!(bit_size < 128, "ICE - shift left with big integers are not supported");
293+
if bit_size < 128 {
294+
let zero = self.numeric_constant(FieldElement::zero(), typ);
295+
return InsertInstructionResult::SimplifiedTo(zero).first();
296+
}
297+
}
298+
let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2), typ);
299+
(bit_size + (rhs_constant.to_u128() as u32), pow)
300+
} else {
301+
// we use a predicate to nullify the result in case of overflow
302+
let bit_size_var =
303+
self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone());
304+
let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var);
305+
let one = self.numeric_constant(FieldElement::one(), Type::unsigned(1));
306+
let predicate = self.insert_binary(overflow, BinaryOp::Eq, one);
307+
let predicate = self.insert_cast(predicate, typ.clone());
308+
309+
let pow = self.pow(base, rhs);
310+
let pow = self.insert_cast(pow, typ);
311+
(FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow))
312+
};
311313

312314
let instruction = Instruction::Binary(Binary { lhs, rhs: pow, operator: BinaryOp::Mul });
313315
if max_bit <= bit_size {

tooling/nargo_cli/tests/execution_success/bit_shifts_comptime/src/main.nr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ fn main(x: u64) {
1313

1414
//regression for 3481
1515
assert(x << 63 == 0);
16+
17+
assert_eq((1 as u56) << (32 as u56), 0x0100000000);
1618
}
1719

1820
fn regression_2250() {

0 commit comments

Comments
 (0)