Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: replace bitwise ANDs used for truncation with `Instruction::Tru…
…ncate` (#4327) … # Description ## Problem\* Resolves <!-- Link to GitHub Issue --> ## Summary\* It's common for us to have new Noir developers to perform bitwise operations in order to truncate a value before they cast to a smaller type, leading to programs such as the below: ```rust fn main(num: u72) -> pub [u8; 8] { let mut out: [u8; 8] = [0; 8]; for i in 0..8 { out[i] = (num >> (56 - (i * 8)) as u72 & 0xff) as u8; } out } ``` This is expensive and unnecessary as we perform truncation on casts anyway. This PR then adds an optimisation which converts any bitwise AND of the form `lhs & 0xff` into an equivalent truncation instruction. ``` Before acir fn main f0 { b0(v0: u72): v277 = div v0, u72 2⁵⁶ v278 = and v277, u72 255 v279 = truncate v278 to 8 bits, max_bit_size: 72 v280 = cast v279 as u8 v281 = div v0, u72 2⁴⁸ v282 = and v281, u72 255 v283 = truncate v282 to 8 bits, max_bit_size: 72 v284 = cast v283 as u8 v285 = div v0, u72 2⁴⁰ v286 = and v285, u72 255 v287 = truncate v286 to 8 bits, max_bit_size: 72 v288 = cast v287 as u8 v289 = div v0, u72 2³² v290 = and v289, u72 255 v291 = truncate v290 to 8 bits, max_bit_size: 72 v292 = cast v291 as u8 v293 = div v0, u72 2²⁴ v294 = and v293, u72 255 v295 = truncate v294 to 8 bits, max_bit_size: 72 v296 = cast v295 as u8 v297 = div v0, u72 2¹⁶ v298 = and v297, u72 255 v299 = truncate v298 to 8 bits, max_bit_size: 72 v300 = cast v299 as u8 v301 = div v0, u72 2⁸ v302 = and v301, u72 255 v303 = truncate v302 to 8 bits, max_bit_size: 72 v304 = cast v303 as u8 v305 = and v0, u72 255 v306 = truncate v305 to 8 bits, max_bit_size: 72 v307 = cast v306 as u8 return [v280, v284, v288, v292, v296, v300, v304, v307] } +--------------+----------------------+ | ACIR Opcodes | Backend Circuit Size | +--------------+----------------------+ | 70 | 5617 | +--------------+----------------------+ After acir fn main f0 { b0(v0: u72): v242 = div v0, u72 2⁵⁶ v243 = truncate v242 to 8 bits, max_bit_size: 72 v244 = cast v243 as u8 v245 = div v0, u72 2⁴⁸ v246 = truncate v245 to 8 bits, max_bit_size: 72 v247 = cast v246 as u8 v248 = div v0, u72 2⁴⁰ v249 = truncate v248 to 8 bits, max_bit_size: 72 v250 = cast v249 as u8 v251 = div v0, u72 2³² v252 = truncate v251 to 8 bits, max_bit_size: 72 v253 = cast v252 as u8 v254 = div v0, u72 2²⁴ v255 = truncate v254 to 8 bits, max_bit_size: 72 v256 = cast v255 as u8 v257 = div v0, u72 2¹⁶ v258 = truncate v257 to 8 bits, max_bit_size: 72 v259 = cast v258 as u8 v260 = div v0, u72 2⁸ v261 = truncate v260 to 8 bits, max_bit_size: 72 v262 = cast v261 as u8 v263 = truncate v0 to 8 bits, max_bit_size: 72 v264 = cast v263 as u8 return [v244, v247, v250, v253, v256, v259, v262, v264] } +--------------+----------------------+ | ACIR Opcodes | Backend Circuit Size | +--------------+----------------------+ | 61 | 3801 | +--------------+----------------------+ ``` The ANDs then completely disappear as the truncation instructions they get converted into are merged into the existing truncations. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** 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.
- Loading branch information