[llvm-bugs] [Bug 45191] New: clang generates incorrect X86-64 code optimization for integer assignment-comparison
via llvm-bugs
llvm-bugs at lists.llvm.org
Thu Mar 12 18:35:07 PDT 2020
https://bugs.llvm.org/show_bug.cgi?id=45191
Bug ID: 45191
Summary: clang generates incorrect X86-64 code optimization for
integer assignment-comparison
Product: clang
Version: 9.0
Hardware: PC
OS: Linux
Status: NEW
Severity: release blocker
Priority: P
Component: -New Bugs
Assignee: unassignedclangbugs at nondot.org
Reporter: hzhuang at gmail.com
CC: htmldeveloper at gmail.com, llvm-bugs at lists.llvm.org,
neeilans at live.com, richard-llvm at metafoo.co.uk
We've found the following issue in clang 6 through 9, in x86_64 Linux as well
as MacOS. And might have spanned more releases. This happens consistently for
certain source code arrangement when optimization is enabled (-O1 ~ -O3).
Unoptimized code seems to be fine. Since this bug is a contradiction to
C-language's definition and the C source code is a very common way of writing,
I'd consider it a severe bug that has existed for a few years and many programs
may have been impacted without noticing the issue, if the tests haven't covered
the case.
For the short C program below ('volatile' is to prevent optimizer from directly
short-circuiting the while-loop. In real cases the assignment in the loop can
be function calls.):
#include <stdio.h>
#include <stdint.h>
int32_t volatile g_a = 0x7fffffff;
int32_t volatile g_b = 16;
int main()
{
int32_t overflown = g_a;
int32_t m;
while ((m = overflown - g_a) <= 0)
{
overflown = g_a + g_b;
putchar('.');
}
printf("m = %d\n", m);
return 0;
}
If compiled without optimization, e.g., clang-9 -Wall source.c, the resultant
executable runs fine, printing ".m = 16" and exit. But if it is compiled with
optimization, e.g., clang-9 -Wall -O3 source.c, the generated code will loop
forever printing '.'. Disassembly the main function of the optimized code
shows:
(gdb) disass main
Dump of assembler code for function main:
0x0000000000401140 <+0>: push %rbx
0x0000000000401141 <+1>: mov 0x2ef1(%rip),%ebx # 0x404038
<g_a>
0x0000000000401147 <+7>: sub 0x2eeb(%rip),%ebx # 0x404038
<g_a>
0x000000000040114d <+13>: jg 0x401175 <main+53>
0x000000000040114f <+15>: nop
0x0000000000401150 <+16>: mov 0x2ee2(%rip),%ebx # 0x404038
<g_a>
0x0000000000401156 <+22>: add 0x2ee0(%rip),%ebx # 0x40403c
<g_b>
0x000000000040115c <+28>: mov 0x2edd(%rip),%rsi # 0x404040
<stdout@@GLIBC_2.2.5>
0x0000000000401163 <+35>: mov $0x2e,%edi
0x0000000000401168 <+40>: callq 0x401040 <putc at plt>
0x000000000040116d <+45>: sub 0x2ec5(%rip),%ebx # 0x404038
<g_a>
0x0000000000401173 <+51>: jle 0x401150 <main+16>
0x0000000000401175 <+53>: mov $0x402004,%edi
0x000000000040117a <+58>: mov %ebx,%esi
0x000000000040117c <+60>: xor %eax,%eax
0x000000000040117e <+62>: callq 0x401030 <printf at plt>
0x0000000000401183 <+67>: xor %eax,%eax
0x0000000000401185 <+69>: pop %rbx
0x0000000000401186 <+70>: retq
End of assembler dump.
(gdb) q
Apparently after 'sub' (main+7, +45), a 'test %ebx,%ebx' or 'cmp #0,%ebx' is
missing. Therefore the branch instructions uses the result of 'sub' operation
instead of the result of 'sub'.
Code like this is commonly used for integer comparison on the integer-ring,
e.g., timer timeout, TCP Sequence numbers, etc. The impact of this bug is big.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200313/3599f643/attachment.html>
More information about the llvm-bugs
mailing list