|
|
Subscribe / Log in / New account

LFCS: The LLVMLinux project

LFCS: The LLVMLinux project

Posted May 14, 2013 5:08 UTC (Tue) by foom (subscriber, #14868)
In reply to: LFCS: The LLVMLinux project by nlewycky
Parent article: LFCS: The LLVMLinux project

> Here's another “static const char *x = "abc"; bool test { return __builtin_constant_p(x); }” that returns false even at -O2. Why?

I don't believe your explanation.

To start with, x isn't const in your example: it can be modified. However, it seems that the optimizer *is* smart enough to figure out that a variable not declared const is actually never modified, and treat it as if it was const. That's good and sensible, and thus not actually the issue here.

So, even with:
static const char * const x = "abc";
gcc still returns false for __builtin_constant_p.

This actually makes perfect sense, because you're actually asking if the pointer itself is a constant value, but said pointer value isn't known until link time. And __builtin_constant_p's contract is to return true only if it is a compile-time-constant (and thus if expressions containing it could be constant-folded).

This appears to have nothing to do with builtin_strlen, which *does* in fact evaluate to a constant 3 as one might expect.


to post comments

LFCS: The LLVMLinux project

Posted May 14, 2013 7:16 UTC (Tue) by nlewycky (guest, #63373) [Link]

Sorry, I didn't mean to say that the only reason builtin_constant_p returned false for that example is because of its contract with builtin_strlen. I have no idea why it returns false in that case. I was trying to point out that these undocumented contracts exist.

>And __builtin_constant_p's contract is to return true only if it is a compile-time-constant (and thus if expressions containing it could be constant-folded).

Counterexample, __builtin_constant_p("string literal") is true, even though the address of that string isn't known at compile time. You already pointed out that the equivalent program written with a variable instead of a literal is not considered constant, which is surprising because it makes no difference to the optimizer or any program semantics. For more fun, try &"asd"[0] and &"asd"[1].

So if it does return true for some pointers, why not the one in your example? I thought it's because some builtins are guaranteed to fold when their arguments are literals but not when their arguments are variables, even const variables, hence builtin_constant_p must be conservative enough to work with all builtins—but also aggressive enough to run after inlining or else user code will break once again. I thought "some builtins" included builtin_strlen, but apparently I'm mistaken.

I remembered my glibc example a little wrong. The parts I'm thinking of are bits/string2.h, from the #define strncmp (which uses strlen and builtin_constant_p) and ultimately calls down into the #define'd __strcmp_gc which in turn dereferences string[0] through string[3]. And consider a user's program:

static unsigned char BOM[] = { 0xEF, 0xBB, 0xBF };
bool test() { return strncmp(..., (char *) BOM, 3)); }
The only thing preventing that from reading off the end of BOM is a contract between builtin_constant_p and strlen (really builtin_strlen through more macros) that it won't return true for any pointers unless builtin_strlen can analyze them.

By the way, if glibc simply didn't #define strncmp, gcc would recognize the function by name and do all the right optimizations itself, better than it can with these builtin_constant_p-using macros in the way.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds