https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90469
Bug ID: 90469 Summary: -ftree-vrp optimizaion causes 'signed overflow' and 'unreachable code' assumptions without warning. Product: gcc Version: 8.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: prg.j.a.h at centrum dot cz Target Milestone: --- Compiling with and without -ftree-vrp produces different code. Although the code mixes signed and unsigned conversions and the code is disputable I think that the compiler should at least issue warnings. e.g. "warning: assuming signed overflow does not occur when assuming that X < (c - Y) is always false [-Wstrict-overflow]" and "warning: expression is always true..." The discussed code is in the conversion.c: ``` #include <stdbool.h> #include <stdint.h> bool convert(int32_t *ptr_data, int32_t offset_f); bool convert(int32_t *ptr_data, int32_t offset_f) { bool result = false; uint32_t data_uns = *((uint32_t*)ptr_data); if (offset_f >= 0) { // TODO } else { if (data_uns <= (uint32_t)(INT32_MAX - offset_f)) { result = true; *ptr_data = (int32_t)data_uns + offset_f; } } return result; } ``` "Unit" test: ``` #include <stdbool.h> #include <stdint.h> #include <stdio.h> extern bool convert(int32_t *ptr_data, int32_t offset_f); int main(void) { int32_t data = -300; int32_t offset = -INT32_MAX; const int32_t expected_data = 2147483349; const bool expected_result = true; bool result = convert(&data, offset); printf("Data: %d ?= %d\n", data, expected_data); printf("Result: %s ?= %s\n", result ? "true" : "false", expected_result ? "true" : "false"); return 0; } ``` The code is compiled with command: - for X86 gcc 8.3.0: gcc-8 -std=c99 -save-temps=obj -O3 -Wall -Werror -o conversion.c.obj -c conversion.c gcc-8 -std=c99 -O3 -o main main.c conversion.c.obj - for ARM cortex-m7 gcc 8.2.1: arm-none-eabi-gcc -std=c99 -mthumb -mcpu=cortex-m7 -save-temps=obj -O3 -Wall -Werror -o conversion.c.obj -c conversion.c Workaround: - option 1: replace 'if (data_uns <= (uint32_t)(INT32_MAX - offset_f))' with 'if (data_uns <= ((uint32_t)INT32_MAX - (uint32_t)offset_f))' - option 2: use -fno-tree-vrp - it works on gcc 7.3.0 (x86) and gcc 7.3.1 (arm) The dissassembly for x86: ``` --- bad-x86.s 2019-05-13 17:20:19.655385900 +0200 +++ good-x86.s 2019-05-13 17:20:58.491385900 +0200 @@ -6,23 +6,25 @@ convert: .LFB0: .cfi_startproc xorl %eax, %eax testl %esi, %esi js .L6 .L1: ret .p2align 4,,10 .p2align 3 .L6: - movl (%rdi), %edx - testl %edx, %edx - js .L1 - addl %edx, %esi + movl $2147483647, %edx + movl (%rdi), %ecx + subl %esi, %edx + cmpl %ecx, %edx + jb .L1 + addl %ecx, %esi movl $1, %eax movl %esi, (%rdi) ret .cfi_endproc .LFE0: .size convert, .-convert .ident "GCC: (Ubuntu 8.3.0-6ubuntu1~18.04) 8.3.0" .section .note.GNU-stack,"",@progbits ``` Disassembly for ARM: ``` --- bad-st.s 2019-05-13 17:17:40.345885900 +0200 +++ good-st.s 2019-05-13 17:18:31.964385900 +0200 @@ -22,21 +22,23 @@ convert: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. cmp r1, #0 blt .L6 .L4: movs r3, #0 mov r0, r3 bx lr .L6: - ldr r3, [r0] - cmp r3, #0 - blt .L4 - add r1, r1, r3 + mvn r3, #-2147483648 + ldr r2, [r0] + subs r3, r3, r1 + cmp r3, r2 + bcc .L4 + add r1, r1, r2 movs r3, #1 str r1, [r0] mov r0, r3 bx lr .size convert, .-convert .ident "GCC: (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.1 20181213 (release) [gcc-8-branch revision 267074]" ```