Identifying GCC in the preprocessor

Ian Pilcher arequipeno@gmail.com
Tue Nov 11 14:52:43 GMT 2025


On 11/10/25 7:00 AM, David Brown wrote:
> I would expect a function like this to be marked as "always_inline", 
> rather than "noinline" - you would want this check to be done with 
> minimum overhead.  Marking a function as "noinline" might not prevent 
> compiler knowledge of things like nonnull (or other range or constant 
> propagation information) being passed around, especially in the face of 
> higher level optimisations like LTO.  Perhaps I am overly paranoid, but 
> I do not like to rely on "making things an independent function" as any 
> kind of barrier to optimisation information.

I've removed the noinline.  It's redundant with "O0" or Clang's
"optnone".  (Based on Jonathan's recommendation, I've also switched to
-fno-delete-null-pointer-checks, rather than O0, so it's up to the
compiler to inline the function or not.

(Also, I don't particularly care about the performance of this function.
It is only called when a data structure (hash table) is being created,
so it shouldn't be called in any sort of performance-critical path.)

> As far as I can see, you have the "volatile" in the wrong place. Writing 
> "volatile const void * vp" means "vp" is a pointer to a volatile const 
> void - you are promising not to change anything via vp, but something 
> external may change what vp points to.  If, on the other hand, you write 
> "const void * volatile vp", you are making "vp" itself volatile.  This 
> means that even if the compiler "knows" that the parameter "p" is null, 
> by the time you are getting to the "if (vp == NULL)" check, something 
> external may have changed "vp" and the check cannot be optimised away.  
> Thus you have something that is safe for the purpose you have here, 
> regardless of any optimisations a compiler may use.

You ar correct.  Thanks for catching that!

> My suggestion for your code would be:
> 
> #if 1    // Checking on godbolt.org
> __attribute__((nonnull(1)))
> #else    // Real code
> __attribute__((always_inline)) static inline
> #endif
> void sht_assert_nonnull(const void *p, const char *msg)
> {
> #ifdef __GNUC__
>      const void * vp = p;
>      __asm__ ("" : "+g" (vp));
> #else
>      const void * volatile vp = p;
> #endif
>      if (__builtin_expect(vp == NULL, 0))
>          sht_abort(msg);
> }

For now, I'm going to stick with what I can actually understand.  :-D
(As I mentioned above, I'm more interested in than the readability of
this code than raw performance.)

#ifdef __clang__
SHT_FNATTR(optnone)
#else
SHT_FNATTR(optimize("-fno-delete-null-pointer-checks"))
#endif
static void sht_assert_nonnull(const void *p, const char *msg)
{
	const void *volatile vp = p;

	if (vp == NULL)
		sht_abort(msg);
}

Thanks for the feedback (and for catching the misplaced volatile)!

-- 
========================================================================
If your user interface is intuitive in retrospect ... it isn't intuitive
========================================================================


More information about the Gcc-help mailing list