Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 64 additions & 87 deletions compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,25 @@ impl Context<'_, '_, '_> {
return self.numeric_constant(pow, NumericType::NativeField);
}

let to_bits = self.context.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little));
let max_exponent_bits = self.context.dfg.get_value_max_num_bits(exponent).ilog2() + 1;
// When shifting, for instance, `u32` values the maximum allowed value is 31, one less than the bit size.
// Representing the maximum value requires 5 bits, which is log2(32), so any `u32` exponent will require
// at most 5 bits. Similarly, `u64` values will require at most 6 bits, etc.
// Using `get_value_max_num_bits` here could work, though in practice:
// - constant exponents are handled in the `if` above
// - if a smaller type was upcasted, for example `u8` to `u32`, an `u8` can hold values up to 256
// which is even larger than the largest unsigned type u128, so nothing better can be done here
// - the exception would be casting a `u1` to a larger type, where we know the exponent can be
// either zero or one, which we special-case here
let max_exponent_bits = if self.context.dfg.get_value_max_num_bits(exponent) == 1 {
1
} else {
self.context.dfg.type_of_value(exponent).bit_size().ilog2()
};
let result_types = vec![Type::Array(Arc::new(vec![Type::bool()]), max_exponent_bits)];

// A call to ToBits can only be done with a field argument (exponent is always u8 here)
let exponent_as_field = self.insert_cast(exponent, NumericType::NativeField);
let to_bits = self.context.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little));
let exponent_bits = self.insert_call(to_bits, vec![exponent_as_field], result_types);

let exponent_bits = exponent_bits[0];
Expand Down Expand Up @@ -416,14 +429,14 @@ mod tests {
v3 = lt v1, u32 32
constrain v3 == u1 1, "attempt to bit-shift with overflow"
v5 = cast v1 as Field
v7 = call to_le_bits(v5) -> [u1; 6]
v9 = array_get v7, index u32 5 -> u1
v7 = call to_le_bits(v5) -> [u1; 5]
v9 = array_get v7, index u32 4 -> u1
v10 = not v9
v11 = cast v9 as Field
v12 = cast v10 as Field
v14 = mul Field 2, v11
v15 = add v12, v14
v17 = array_get v7, index u32 4 -> u1
v17 = array_get v7, index u32 3 -> u1
v18 = not v17
v19 = cast v17 as Field
v20 = cast v18 as Field
Expand All @@ -432,7 +445,7 @@ mod tests {
v23 = mul v21, Field 2
v24 = mul v23, v19
v25 = add v22, v24
v27 = array_get v7, index u32 3 -> u1
v27 = array_get v7, index u32 2 -> u1
v28 = not v27
v29 = cast v27 as Field
v30 = cast v28 as Field
Expand All @@ -441,7 +454,7 @@ mod tests {
v33 = mul v31, Field 2
v34 = mul v33, v29
v35 = add v32, v34
v37 = array_get v7, index u32 2 -> u1
v37 = array_get v7, index u32 1 -> u1
v38 = not v37
v39 = cast v37 as Field
v40 = cast v38 as Field
Expand All @@ -450,7 +463,7 @@ mod tests {
v43 = mul v41, Field 2
v44 = mul v43, v39
v45 = add v42, v44
v47 = array_get v7, index u32 1 -> u1
v47 = array_get v7, index u32 0 -> u1
v48 = not v47
v49 = cast v47 as Field
v50 = cast v48 as Field
Expand All @@ -459,20 +472,11 @@ mod tests {
v53 = mul v51, Field 2
v54 = mul v53, v49
v55 = add v52, v54
v57 = array_get v7, index u32 0 -> u1
v58 = not v57
v59 = cast v57 as Field
v60 = cast v58 as Field
v61 = mul v55, v55
v62 = mul v61, v60
v63 = mul v61, Field 2
v64 = mul v63, v59
v65 = add v62, v64
v66 = cast v0 as Field
v67 = mul v66, v65
v68 = truncate v67 to 32 bits, max_bit_size: 64
v69 = cast v68 as u32
return v69
v56 = cast v0 as Field
v57 = mul v56, v55
v58 = truncate v57 to 32 bits, max_bit_size: 64
v59 = cast v58 as u32
return v59
}
"#);
}
Expand Down Expand Up @@ -540,14 +544,14 @@ mod tests {
v3 = lt v1, u32 32
constrain v3 == u1 1, "attempt to bit-shift with overflow"
v5 = cast v1 as Field
v7 = call to_le_bits(v5) -> [u1; 6]
v9 = array_get v7, index u32 5 -> u1
v7 = call to_le_bits(v5) -> [u1; 5]
v9 = array_get v7, index u32 4 -> u1
v10 = not v9
v11 = cast v9 as Field
v12 = cast v10 as Field
v14 = mul Field 2, v11
v15 = add v12, v14
v17 = array_get v7, index u32 4 -> u1
v17 = array_get v7, index u32 3 -> u1
v18 = not v17
v19 = cast v17 as Field
v20 = cast v18 as Field
Expand All @@ -556,7 +560,7 @@ mod tests {
v23 = mul v21, Field 2
v24 = mul v23, v19
v25 = add v22, v24
v27 = array_get v7, index u32 3 -> u1
v27 = array_get v7, index u32 2 -> u1
v28 = not v27
v29 = cast v27 as Field
v30 = cast v28 as Field
Expand All @@ -565,7 +569,7 @@ mod tests {
v33 = mul v31, Field 2
v34 = mul v33, v29
v35 = add v32, v34
v37 = array_get v7, index u32 2 -> u1
v37 = array_get v7, index u32 1 -> u1
v38 = not v37
v39 = cast v37 as Field
v40 = cast v38 as Field
Expand All @@ -574,7 +578,7 @@ mod tests {
v43 = mul v41, Field 2
v44 = mul v43, v39
v45 = add v42, v44
v47 = array_get v7, index u32 1 -> u1
v47 = array_get v7, index u32 0 -> u1
v48 = not v47
v49 = cast v47 as Field
v50 = cast v48 as Field
Expand All @@ -583,18 +587,9 @@ mod tests {
v53 = mul v51, Field 2
v54 = mul v53, v49
v55 = add v52, v54
v57 = array_get v7, index u32 0 -> u1
v58 = not v57
v59 = cast v57 as Field
v60 = cast v58 as Field
v61 = mul v55, v55
v62 = mul v61, v60
v63 = mul v61, Field 2
v64 = mul v63, v59
v65 = add v62, v64
v66 = cast v65 as u32
v67 = div v0, v66
return v67
v56 = cast v55 as u32
v57 = div v0, v56
return v57
}
"#);
}
Expand Down Expand Up @@ -644,14 +639,14 @@ mod tests {
v4 = lt v2, u32 31
constrain v4 == u1 1, "attempt to bit-shift with overflow"
v6 = cast v1 as Field
v8 = call to_le_bits(v6) -> [u1; 6]
v10 = array_get v8, index u32 5 -> u1
v8 = call to_le_bits(v6) -> [u1; 5]
v10 = array_get v8, index u32 4 -> u1
v11 = not v10
v12 = cast v10 as Field
v13 = cast v11 as Field
v15 = mul Field 2, v12
v16 = add v13, v15
v18 = array_get v8, index u32 4 -> u1
v18 = array_get v8, index u32 3 -> u1
v19 = not v18
v20 = cast v18 as Field
v21 = cast v19 as Field
Expand All @@ -660,7 +655,7 @@ mod tests {
v24 = mul v22, Field 2
v25 = mul v24, v20
v26 = add v23, v25
v28 = array_get v8, index u32 3 -> u1
v28 = array_get v8, index u32 2 -> u1
v29 = not v28
v30 = cast v28 as Field
v31 = cast v29 as Field
Expand All @@ -669,7 +664,7 @@ mod tests {
v34 = mul v32, Field 2
v35 = mul v34, v30
v36 = add v33, v35
v38 = array_get v8, index u32 2 -> u1
v38 = array_get v8, index u32 1 -> u1
v39 = not v38
v40 = cast v38 as Field
v41 = cast v39 as Field
Expand All @@ -678,7 +673,7 @@ mod tests {
v44 = mul v42, Field 2
v45 = mul v44, v40
v46 = add v43, v45
v48 = array_get v8, index u32 1 -> u1
v48 = array_get v8, index u32 0 -> u1
v49 = not v48
v50 = cast v48 as Field
v51 = cast v49 as Field
Expand All @@ -687,20 +682,11 @@ mod tests {
v54 = mul v52, Field 2
v55 = mul v54, v50
v56 = add v53, v55
v58 = array_get v8, index u32 0 -> u1
v59 = not v58
v60 = cast v58 as Field
v61 = cast v59 as Field
v62 = mul v56, v56
v63 = mul v62, v61
v64 = mul v62, Field 2
v65 = mul v64, v60
v66 = add v63, v65
v67 = cast v0 as Field
v68 = mul v67, v66
v69 = truncate v68 to 32 bits, max_bit_size: 64
v70 = cast v69 as i32
return v70
v57 = cast v0 as Field
v58 = mul v57, v56
v59 = truncate v58 to 32 bits, max_bit_size: 64
v60 = cast v59 as i32
return v60
}
"#);
}
Expand Down Expand Up @@ -753,14 +739,14 @@ mod tests {
v4 = lt v2, u32 31
constrain v4 == u1 1, "attempt to bit-shift with overflow"
v6 = cast v1 as Field
v8 = call to_le_bits(v6) -> [u1; 6]
v10 = array_get v8, index u32 5 -> u1
v8 = call to_le_bits(v6) -> [u1; 5]
v10 = array_get v8, index u32 4 -> u1
v11 = not v10
v12 = cast v10 as Field
v13 = cast v11 as Field
v15 = mul Field 2, v12
v16 = add v13, v15
v18 = array_get v8, index u32 4 -> u1
v18 = array_get v8, index u32 3 -> u1
v19 = not v18
v20 = cast v18 as Field
v21 = cast v19 as Field
Expand All @@ -769,7 +755,7 @@ mod tests {
v24 = mul v22, Field 2
v25 = mul v24, v20
v26 = add v23, v25
v28 = array_get v8, index u32 3 -> u1
v28 = array_get v8, index u32 2 -> u1
v29 = not v28
v30 = cast v28 as Field
v31 = cast v29 as Field
Expand All @@ -778,7 +764,7 @@ mod tests {
v34 = mul v32, Field 2
v35 = mul v34, v30
v36 = add v33, v35
v38 = array_get v8, index u32 2 -> u1
v38 = array_get v8, index u32 1 -> u1
v39 = not v38
v40 = cast v38 as Field
v41 = cast v39 as Field
Expand All @@ -787,7 +773,7 @@ mod tests {
v44 = mul v42, Field 2
v45 = mul v44, v40
v46 = add v43, v45
v48 = array_get v8, index u32 1 -> u1
v48 = array_get v8, index u32 0 -> u1
v49 = not v48
v50 = cast v48 as Field
v51 = cast v49 as Field
Expand All @@ -796,27 +782,18 @@ mod tests {
v54 = mul v52, Field 2
v55 = mul v54, v50
v56 = add v53, v55
v58 = array_get v8, index u32 0 -> u1
v59 = not v58
v60 = cast v58 as Field
v61 = cast v59 as Field
v62 = mul v56, v56
v63 = mul v62, v61
v64 = mul v62, Field 2
v65 = mul v64, v60
v66 = add v63, v65
v67 = cast v66 as i32
v69 = lt v0, i32 0
v70 = cast v69 as Field
v71 = cast v0 as Field
v72 = add v70, v71
v73 = truncate v72 to 32 bits, max_bit_size: 33
v74 = cast v73 as i32
v75 = div v74, v67
v76 = cast v69 as i32
v77 = unchecked_sub v75, v76
v78 = truncate v77 to 32 bits, max_bit_size: 33
return v78
v57 = cast v56 as i32
v59 = lt v0, i32 0
v60 = cast v59 as Field
v61 = cast v0 as Field
v62 = add v60, v61
v63 = truncate v62 to 32 bits, max_bit_size: 33
v64 = cast v63 as i32
v65 = div v64, v57
v66 = cast v59 as i32
v67 = unchecked_sub v65, v66
v68 = truncate v67 to 32 bits, max_bit_size: 33
return v68
}
"#);
}
Expand Down
6 changes: 6 additions & 0 deletions test_programs/execution_success/regression_9541/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "regression_9541"
type = "bin"
authors = [""]

[dependencies]
3 changes: 3 additions & 0 deletions test_programs/execution_success/regression_9541/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
a = 1
b = 26
return = 67108864
3 changes: 3 additions & 0 deletions test_programs/execution_success/regression_9541/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main(a: u32, b: u8) -> pub u32 {
a << (b as u32)
}
Loading
Loading