https://llvm.org/bugs/show_bug.cgi?id=27158
Bug ID: 27158 Summary: AArch64InstrInfo::optimizeCompareInstr incorrectly removes compare instructions Product: libraries Version: trunk Hardware: PC OS: Linux Status: NEW Severity: normal Priority: P Component: Backend: AArch64 Assignee: unassignedb...@nondot.org Reporter: eas...@yandex.ru CC: llvm-bugs@lists.llvm.org Classification: Unclassified Incorrect code is generated when the following test is compiled with -O3: ------------ test.c -------- // clang --target=aarch64-none-eabi -O3 -S test.c #include <stdio.h> static char c = 2; static char d[4] = {1}; int main() { c = d[3]; unsigned short f = d[1] << d[2]; if ((&c == &d[3]) <= f) c = printf("checksum = 0\n"); } ------------------------------ When the produced binary is executed 'checksum = 0' is not printed. It should be printed because the condition of the if statement should always be true (the two addresses cannot be equal, so the inner comparison is false, which gets converted to (int)0, and f is 0 because a and b are both 0). When the program is compiled with O2 it works as expected. With -O2 the generated code is ------------------------------ main: // @main // BB#0: // %entry adrp x8, d add x8, x8, :lo12:d ldrb w9, [x8, #3]! adrp x12, c add x12, x12, :lo12:c ldurb w10, [x8, #-2] ldurb w11, [x8, #-1] cmp x8, x12 strb w9, [x12] cset w9, eq lsl w8, w10, w11 and w8, w8, #0xffff cmp w8, w9 b.lo .LBB0_2 ------------------------------ With -O3 the generated code is ------------------------------ main: // @main // BB#0: // %entry adrp x8, .L_MergedGlobals add x8, x8, :lo12:.L_MergedGlobals ldrb w9, [x8, #4] ldrb w10, [x8, #2] ldrb w11, [x8, #3] strb w9, [x8] lsl w8, w10, w11 tst w8, #0xffff b.lo .LBB0_2 ------------------------------ The O3 code is incorrect because CMP and TST set the carry flag to different values. As a result Bcc which checks the carry flag is not working as expected. The problem function is AArch64InstrInfo::optimizeCompareInstr from AArch64InstrInfo.cpp. It tries to remove a compare instruction. One case is comparison with 0: CmpInst r, 0. It removes CmpInst and modifies the instruction defining r to the S version. It is not checked that the S version and CmpInst produce the same flags. In case of the test above the following code: %vreg7<def> = ANDWri %vreg6<kill>, 15; GPR32sp:%vreg7 GPR32:%vreg6 %vreg8<def> = SUBSWri %vreg7<kill>, 0, 0, %NZCV<imp-def>; GPR32:%vreg8 GPR32sp:%vreg7 Bcc 3, <BB#2>, %NZCV<imp-use> is transformed into %vreg7<def> = ANDSWri %vreg6<kill>, 15, %NZCV<imp-def>; GPR32common:%vreg7 GPR32:%vreg6 Bcc 3, <BB#2>, %NZCV<imp-use> I have a fix of the bug. It was submitted for review as http://reviews.llvm.org/D18318. It was recommended to split it into smaller parts to simplify reviewing of it. It is split into parts: Part1 - refactoring of AArch64InstrInfo::optimizeCompareInstr http://reviews.llvm.org/D18609 Part2 will contain the fix. -- You are receiving this mail because: You are on the CC list for the bug.
_______________________________________________ llvm-bugs mailing list llvm-bugs@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs