https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80006
Bug ID: 80006 Summary: loss of range information after widening conversion Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- This bug is the cause of bug 79356 (discussed here: https://gcc.gnu.org/ml/gcc-patches/2017-02/msg00684.html). When the following test case is compiled for some targets (such as powerpc64) it emits a diagnostic for the call to ff in f as expected. This is thanks the range of the x variable is correctly represented as the anti-range ~[-3, 7], which means that valid (i.e., non-negative) argument to the allocation function is greater greater than 7 (negative argument are considered invalid). However, the same warning is not issued for the call to gg, or even for ff on on other targets (such as x86_64). The reason is that VRP appears to "lose" the range of the signed char variable x when it's converted to int. On x86_64, this conversion from signed char to int is for some reason performed even in function f, so the test program triggers no warnings. On powerpc64, the conversion is not done in f but it is done in g where it is explicit. In summary, it seems as though there are two problems: 1) the spurious signed char to int conversion on x86_64 inserted (very early on -- as can be seen in the tree-original dump) 2) the loss of range info when converting a signed char variable to signed int. $ cat t.c && /build/powerpc64le-linux-gnu/gcc-trunk/gcc/xgcc -B /build/powerpc64le-linux-gnu/gcc-trunk/gcc -O2 -S -Wall -Wextra -Wpedantic -Walloc-size-larger-than=7 -fdump-tree-vrp=/dev/stdout t.c void* f (signed char x) { extern void* ff (signed char) __attribute__ ((alloc_size (1))); if (-3 <= x && x <= 7) x = -4; return ff (x); } void* g (signed char x) { extern void* gg (int) __attribute__ ((alloc_size (1))); if (-3 <= x && x <= 7) x = -4; return gg (x); } ;; Function f (f, funcdef_no=0, decl_uid=2492, cgraph_uid=0, symbol_order=0) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 3 4 ;; 2 succs { 3 4 } ;; 3 succs { 4 } ;; 4 succs { 1 } Adding assert for x_4(D) from (unsigned char) x_4(D) + 3 Adding assert for x_4(D) from (unsigned char) x_4(D) + 3 SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j x_8 -> { x_4(D) } x_9 -> { x_4(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 6 Number of blocks to update: 4 ( 67%) Value ranges after VRP: x.0_1: [0, +INF] _2: [0, +INF] x_3: ~[-3, 7] EQUIVALENCES: { } (0 elements) x_4(D): VARYING _7: VARYING x_8: [-3, 7] EQUIVALENCES: { x_4(D) } (1 elements) x_9: ~[-3, 7] EQUIVALENCES: { x_4(D) } (1 elements) Removing basic block 3 f (signed char x) { unsigned char x.0_1; unsigned char _2; void * _7; <bb 2> [100.00%]: x.0_1 = (unsigned char) x_4(D); _2 = x.0_1 + 3; if (_2 <= 10) goto <bb 4>; [54.00%] else goto <bb 3>; [46.00%] <bb 3> [46.00%]: <bb 4> [100.00%]: # x_3 = PHI <x_4(D)(3), -4(2)> _7 = ff (x_3); return _7; } ;; Function f (f, funcdef_no=0, decl_uid=2492, cgraph_uid=0, symbol_order=0) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 3 4 ;; 2 succs { 3 4 } ;; 3 succs { 4 } ;; 4 succs { 1 } Adding assert for x_4(D) from (unsigned char) x_4(D) + 3 Adding assert for x_4(D) from (unsigned char) x_4(D) + 3 SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j x_8 -> { x_4(D) } x_9 -> { x_4(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 6 Number of blocks to update: 4 ( 67%) Value ranges after VRP: x.0_1: [0, +INF] _2: [0, +INF] x_3: ~[-3, 7] EQUIVALENCES: { } (0 elements) x_4(D): VARYING _7: VARYING x_8: [-3, 7] EQUIVALENCES: { x_4(D) } (1 elements) x_9: ~[-3, 7] EQUIVALENCES: { x_4(D) } (1 elements) Removing basic block 3 f (signed char x) { unsigned char x.0_1; unsigned char _2; void * _7; <bb 2> [100.00%]: x.0_1 = (unsigned char) x_4(D); _2 = x.0_1 + 3; if (_2 <= 10) goto <bb 4>; [54.00%] else goto <bb 3>; [46.00%] <bb 3> [46.00%]: <bb 4> [100.00%]: # x_3 = PHI <x_4(D)(3), -4(2)> _7 = ff (x_3); return _7; } t.c: In function ‘f’: t.c:8:10: warning: argument 1 range [8, 127] exceeds maximum object size 7 [-Walloc-size-larger-than=] return ff (x); ^~~~~~ t.c:3:16: note: in a call to allocation function ‘ff’ declared here extern void* ff (signed char) __attribute__ ((alloc_size (1))); ^~ ;; Function g (g, funcdef_no=1, decl_uid=2498, cgraph_uid=1, symbol_order=1) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 3 4 ;; 2 succs { 3 4 } ;; 3 succs { 4 } ;; 4 succs { 1 } Adding assert for x_5(D) from (unsigned char) x_5(D) + 3 Adding assert for x_5(D) from (unsigned char) x_5(D) + 3 SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j x_9 -> { x_5(D) } x_10 -> { x_5(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 6 Number of blocks to update: 4 ( 67%) Value ranges after VRP: x.1_1: [0, +INF] _2: [0, +INF] _3: [-128, 127] x_4: ~[-3, 7] EQUIVALENCES: { } (0 elements) x_5(D): VARYING _8: VARYING x_9: [-3, 7] EQUIVALENCES: { x_5(D) } (1 elements) x_10: ~[-3, 7] EQUIVALENCES: { x_5(D) } (1 elements) Removing basic block 3 g (signed char x) { unsigned char x.1_1; unsigned char _2; int _3; void * _8; <bb 2> [100.00%]: x.1_1 = (unsigned char) x_5(D); _2 = x.1_1 + 3; if (_2 <= 10) goto <bb 4>; [54.00%] else goto <bb 3>; [46.00%] <bb 3> [46.00%]: <bb 4> [100.00%]: # x_4 = PHI <x_5(D)(3), -4(2)> _3 = (int) x_4; _8 = gg (_3); return _8; } ;; Function g (g, funcdef_no=1, decl_uid=2498, cgraph_uid=1, symbol_order=1) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 3 4 ;; 2 succs { 4 3 } ;; 3 succs { 4 } ;; 4 succs { 1 } Adding assert for x_5(D) from (unsigned char) x_5(D) + 3 SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j x_4 -> { x_5(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 5 Number of blocks to update: 2 ( 40%) Value ranges after VRP: x.1_1: [0, +INF] _2: [0, +INF] x_4: ~[-3, 7] EQUIVALENCES: { x_5(D) } (1 elements) x_5(D): VARYING _8: VARYING _9: [-128, 127] prephitmp_10: [-128, 127] g (signed char x) { unsigned char x.1_1; unsigned char _2; void * _8; int _9; int prephitmp_10; <bb 2> [100.00%]: x.1_1 = (unsigned char) x_5(D); _2 = x.1_1 + 3; if (_2 <= 10) goto <bb 4>; [54.00%] else goto <bb 3>; [46.00%] <bb 3> [46.00%]: _9 = (int) x_5(D); <bb 4> [100.00%]: # prephitmp_10 = PHI <_9(3), -4(2)> _8 = gg (prephitmp_10); return _8; }