llvm-project
llvm-project copied to clipboard
miscompile of a frozen poison by AArch64 backend
Here's a slightly modified version of a function found in the LLVM test suite:
define i32 @f(i32 %0) {
%2 = ashr i32 %0, 32
%3 = freeze i32 %2
%4 = ashr i32 %3, 3
%5 = mul i32 %3, %4
ret i32 %5
}
It's a bit of a pain to demonstrate how it gets miscompiled, so please bear with me. %2
is poison so then %3
is an arbitrary i32
, %4
is an arbitrary i32
that has 4 signbits and then %5
is (%3 * (%3 >>a 3))
. This function can return any i32
that satisfies this equation.
On the AArch64 side, this is the generated code:
f:
asr w8, w8, #3
mul w0, w8, w8
ret
Notice that it multiplies the shifted value by itself, instead of multiplying the shifted value by the unshifted value, which is what the original code does. This leads to returning impossible values such as 0x4676cf69
that are not solutions to the equation above.
A correct backend can return a constant satisfying the equation (such as 0) or it could generate code similar to this that faithfully performs the math:
f:
asr w9, w8, #3
mul w0, w8, w9
ret
cc @nunoplopes @ryan-berger @nbushehri @Hatsunespica
@llvm/issue-subscribers-backend-aarch64
SelectionDAG is correct. It's the translation to MachineIR where we lose the freeze and start propagating undef.
*** MachineFunction at end of ISel ***
# Machine code for function f: IsSSA, TracksLiveness
bb.0 (%ir-block.1):
%2:gr32 = IMPLICIT_DEF
%1:gr32 = COPY killed %2:gr32
%3:gr32 = SAR32ri %1:gr32(tied-def 0), 3, implicit-def dead $eflags
%4:gr32 = IMUL32rr %1:gr32(tied-def 0), killed %3:gr32, implicit-def dead $eflags
$eax = COPY %4:gr32
RET 0, $eax
# End machine code for function f.
x86 is also the same:
f: # @f
sar eax, 3
imul eax, eax
ret