Checked range of variables is forgotten after a slightly non-trivial condition (original) (raw)

#include <assert.h>

int choose(int v[], int len, int a, int b, int cond) { if (a >= len || b >= len) { return 0; }

int res = v[a] > cond || v[b] > cond ? a : b;
assert(res < len);
return res;

}

I would expect assert to be optimized out, because the only possible values for res are either a or b, and both had their range checked at the beginning of the function.

What is really weird about this is that changing || to | makes this optimization work (int res = v[a] > cond | v[b] > cond ? a : b). I originally thought it was related to reading two different memory locations, but in this minimized example it seems to be caused by having an extra branch in the short-circuiting condition.

https://gcc.godbolt.org/z/jx8zje6v8