https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95448
Bug ID: 95448 Summary: Missing optimization: pointer untag, re-tag should be no-op Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: dancol at dancol dot org Target Milestone: --- Consider the following code. make_vector2() ought to be equivalent to just "return make_vector_val()", and under Clang (10.0), it is. But GCC generates this code for make_vector2: make_vector2: sub rsp, 8 call make_vector_val add rsp, 8 and rax, -8 or rax, 1 ret The assume() in the code ought to be sufficient for convincing GCC that it doesn't need to munge the return value of make_vector_val(). Emacs uses patterns like this one pretty frequently. --- #include <stdint.h> #include <stddef.h> #include <stdbool.h> #define assume(x) do { if(!(x)) __builtin_unreachable(); } while(0) enum { tagbits = 3 }; #define TAG_MASK (((uintptr_t)(1)<<tagbits) - 1) #define TAG_VECTOR ((uintptr_t) 1) typedef struct vector { double x; } vector; typedef struct val { uintptr_t v; } val; static inline void *PTR_OF(val v) { return (void *)(v.v & ~TAG_MASK); } static inline val TAG(void *v, uintptr_t tag) { uintptr_t l = (uintptr_t) v; assume((l & TAG_MASK) == 0); return (val){l | tag}; } extern val make_vector_val(void); val make_vector2(void) { val v = make_vector_val(); assume((v.v & TAG_MASK) == TAG_VECTOR); struct vector *vs = PTR_OF(v); return TAG(vs, TAG_VECTOR); }