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