As a subtle consequence of the recent load-op fusion, popcnt of a value that came from a load.i32 was compiling into a 64-bit load. This is a result of the way in which x86 infers the width of loads: it is a consequence of the instruction containing the memory reference, not the memory reference itself. So the `input_to_reg_mem()` helper (convert an instruction input into a register or memory reference) was providing the appropriate memory reference for the result of a load.i32, but never encoded the assumption that it would only be used in a 32-bit instruction. It turns out that popcnt.i32 uses a 64-bit instruction to load this RM op, hence widening a 32-bit to 64-bit load (which is problematic when the offset is (memory_length - 4)). Separately, popcnt was using the RM operand twice, resulting in two loads if we merged a load. This isn't a correctness bug in practice because only a racy sequence (store interleaving between the loads) would produce incorrect results, but we decided earlier to treat loads as effectful for now, neither reordering nor duplicating them, to deliberately reduce complexity. Because of the second issue, the fix is just to force the operand into a register always, so any source load will not be merged. Discovered via fuzzing with oss-fuzz.
This crate contains the core Cranelift code generator. It translates code from an intermediate representation into executable machine code.