https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120360
--- Comment #2 from Linus Torvalds <torva...@linux-foundation.org> --- Btw, for a similar - but different - comparison optimization failure case, we had a discussion about our error pointer comparisons in the kernel. We have this model where we return a pointer or error code in the same word, with error pointers having values from -MAX_ERR to -1. So we have a "IS_ERR_OR_NULL()" thing, which is the obvious thing and generates testq %rdi, %rdi je .L189 cmpq $-4096, %rdi ja .L189 for gcc, and clang does this: testq %rdi, %rdi sete %al cmpq $-4095, %rdi # imm = 0xF001 setae %cl orb %al, %cl je .LBB3_1 to avoid multiple conditional branches. But for the case where we know it's a kernel pointer (which is always a negative value on x86-64) we could just add MAX_ERR and check that it's now positive. And by "add MAX_ERR", I mean "subtract -MAX_ERR and turn it into just a comparison". But I *cannot* get gcc to do that. I can get gcc to generate this: addq $4095, %rdi jns .L7 which looks superficially fine, but is actually quite bad because it generates that extra result, which then results in more register pressure because you need to keep the original pointer around, of course. Why doesn't gcc know that an add with a compare and a dead result is the same as subtract with the negative value, which can be written as "cmp"? IOW, the code I *tried* to get gcc to generate was cmpq $-4095, %rdi jns .L7 but gcc just refuses to do that. As with https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49095, I feel like there should be an obvious peephole optimization where you go "oh, I can turn this add-with-only-CC to just a cmp". Stupid test-case: /* * Compile with -fwrapv, or cast to 'unsigned long' and then to 'long' */ #define MY_MAX_ERRNO 4095 #define MY_IS_ERR_OR_NULL(ptr) ((long)(ptr) + MY_MAX_ERRNO >= 0) extern void do_something(void); void failure(void *); void failure(void *ptr) { if (MY_IS_ERR_OR_NULL(ptr)) do_something(); }