#include <stdlib.h> char foo(char* data, size_t len, size_t i, size_t j) { if (i < len && j <= i) { if (j < len) { return data[j]; } else { exit(1); } } else { return 0; } } compiles to: foo(char*, unsigned long, unsigned long, unsigned long): cmp rdx, rsi jnb .L4 cmp rdx, rcx jb .L4 cmp rsi, rcx jbe .L3 movzx eax, BYTE PTR [rdi+rcx] ret .L4: xor eax, eax ret .L3: push rax mov edi, 1 call exit The call to exit should be eliminated.
Clang compiles this to: foo(char*, unsigned long, unsigned long, unsigned long): # @foo(char*, unsigned long, unsigned long, unsigned long) xor eax, eax cmp rdx, rsi jae .LBB0_3 cmp rcx, rdx ja .LBB0_3 mov al, byte ptr [rdi + rcx] .LBB0_3: ret with -O2 -mllvm -enable-constraint-elimination
So VRP computes Visiting conditional with predicate: if (len_13 > j_14) With known ranges len_13: size_t [i_6(D) + 1, +INF] EQUIVALENCES: { len_7(D) } (1 elements) j_14: long unsigned int [0, i_6(D)] EQUIVALENCES: { j_8(D) } (1 elements) Predicate evaluates to: DON'T KNOW where I guess the issue is that we assume i_6(D) + 1 may overflow to zero (the [i_6(D) + 1, +INF] range is computed from len_7(D) > i_6(D) where we _know_ that i_6(D) + 1 cannot overflow. The representation of symbolic relations as ranges makes things awkward (we for sure cannot generally assume i_6(D) + 1 cannot overflow). We could possibly mark ranges as originally derived to not have overflowing bound computations somehow (maybe with a flag in on value-range). symbolic range VRP is most important for Ada so CCing Eric
We should be able to handle this in GCC 12 . The WIP relation support in ranger currently is showing: <bb 2> : _1 = i_6(D) < len_7(D); _2 = i_6(D) >= j_8(D); _3 = _1 & _2; if (_3 != 0) goto <bb 3>; [INV] else goto <bb 6>; [INV] =========== BB 3 ============ len_7(D) size_t [1, +INF] j_8(D) size_t VARYING Relational : (i_6(D) >= j_8(D)) Relational : (i_6(D) < len_7(D)) <bb 3> : if (len_7(D) > j_8(D)) goto <bb 4>; [INV] else goto <bb 5>; [INV] So once I get the transitive queries of relations working, we should be able to recognize len_7 > i_6 >= j_8 and then the condition will fold trivially eliminating the call to exit().
Fixed on the trunk by some of the improvements to VRP (range).