if (somebitboard64 & (Rank6 | Rank7 | Rank8)) {
// do something
}
Is it 100% safe to assume the c++ compiler will never OR those 3 bitboards together every time it executes that code, but instead inserts a 64bit constant that is the result of (Rank6 | Rank7 | Rank8) to avoid calculate it every time?
Apparently constexpr is required for the compiler to perform the optimization, which at first surprised me, but it makes sense – without seeing the rest of the program, the compiler can't determine whether or not Rank6–8 will be modified by other code. Case in point: if you move the Rank6–8 into the function, you can remove constexpr:
if (somebitboard64 & (Rank6 | Rank7 | Rank8)) {
// do something
}
Is it 100% safe to assume the c++ compiler will never OR those 3 bitboards together every time it executes that code, but instead inserts a 64bit constant that is the result of (Rank6 | Rank7 | Rank8) to avoid calculate it every time?
As of C++17 (gcc-7, clang-3.9 and visual c++ 2017) you can use an init-statement inside the if. So if you just define a local constexpr variable Rank678 that holds the bitwise-OR over all the bitboards, it's guaranteed by the compiler to never be evaulated at runtime. For C++11/C++14 you can define Rank678 just prior to the if-statement of course (but then it's scope is larger than needed).
if (constexpr auto Rank678 = Rank6 | Rank7 | Rank8; somebitboard64 & Rank678) {
// do something
} // Rank678 goes out of scope here!
Of course, most optimizing compilers will also do the constant-folding if you just have const instead of constexpr. But it's better to rely on the Standard's guarantee.
dangi12012 wrote:No one wants to touch anything you have posted. That proves you now have negative reputations since everyone knows already you are a forum troll.
Maybe you copied your stockfish commits from someone else too?
I will look into that.
expositor wrote: ↑Fri Sep 09, 2022 4:14 am
without seeing the rest of the program, the compiler can't determine whether or not Rank6–8 will be modified by other code.
constexpr functions/variables are always defined in the place they are declared, so they are always visible by the compiler (either in the source file itself or in a header).
this is why constant-folding is performed even without any optimization.
constexpr has no guarantee of constant-time evaluation. It merely guarantees that the value can be used in certain contexts such as template parameters and array sizes, but that doesn't mean that it has to constant-fold if it doesn't care to. consteval and constinit add yet more guarantees on top of this (for instance, anything constinit will be initialized before any code is run), but you still don't have a guarantee of constant folding. Heck, C++ doesn't even guarantee that “int x = 24;” won't be represented in assembler as a function computing the factorial of 4, recursively (and on certain platforms, larger constants will indeed need to be pieced together by combining multiple loads; are those constant or not? ). For many things, the easiest way to get the behavior the standard mandates is indeed to constant-fold, but the standard gives guarantees about program behavior, never about underlying machine code or optimizations.
E.g. here is MSVC (in non-optimizing mode) not inlining or constant-folding a constexpr function: https://gcc.godbolt.org/z/dETGo44cf — you need to turn on optimizations to get it to just return 7.
consteval: Function garuanteed to be evaluated at compiletime constexpr var: initialized at compiletime constexpr function: may or may not be evaluated at compiletime depending on the context
const: initialized at runtime. Immutable static: depends heavily on the context. Means constant address for most things.
You can take the address of a constexpr int.
You cannot take the address of a consteval function or a preprocessor macro.
Then you have also have fun like const class with mutable members...
Sesse wrote: ↑Wed Sep 14, 2022 12:11 am
constexpr has no guarantee of constant-time evaluation. It merely guarantees that the value can be used in certain contexts such as template parameters and array sizes, but that doesn't mean that it has to constant-fold if it doesn't care to. consteval and constinit add yet more guarantees on top of this (for instance, anything constinit will be initialized before any code is run), but you still don't have a guarantee of constant folding. Heck, C++ doesn't even guarantee that “int x = 24;” won't be represented in assembler as a function computing the factorial of 4, recursively (and on certain platforms, larger constants will indeed need to be pieced together by combining multiple loads; are those constant or not? ). For many things, the easiest way to get the behavior the standard mandates is indeed to constant-fold, but the standard gives guarantees about program behavior, never about underlying machine code or optimizations.
E.g. here is MSVC (in non-optimizing mode) not inlining or constant-folding a constexpr function: https://gcc.godbolt.org/z/dETGo44cf — you need to turn on optimizations to get it to just return 7.
But this wasn't the OP's question. Simply initializing a constexpr variable inside foo() and then returning that, will simplify the program at -O0 already. https://gcc.godbolt.org/z/d8YzshsTW
Sesse wrote: ↑Wed Sep 14, 2022 12:11 am
constexpr has no guarantee of constant-time evaluation. It merely guarantees that the value can be used in certain contexts such as template parameters and array sizes, but that doesn't mean that it has to constant-fold if it doesn't care to. consteval and constinit add yet more guarantees on top of this (for instance, anything constinit will be initialized before any code is run), but you still don't have a guarantee of constant folding. Heck, C++ doesn't even guarantee that “int x = 24;” won't be represented in assembler as a function computing the factorial of 4, recursively (and on certain platforms, larger constants will indeed need to be pieced together by combining multiple loads; are those constant or not? ). For many things, the easiest way to get the behavior the standard mandates is indeed to constant-fold, but the standard gives guarantees about program behavior, never about underlying machine code or optimizations.
E.g. here is MSVC (in non-optimizing mode) not inlining or constant-folding a constexpr function: https://gcc.godbolt.org/z/dETGo44cf — you need to turn on optimizations to get it to just return 7.
But this wasn't the OP's question. Simply initializing a constexpr variable inside foo() and then returning that, will simplify the program at -O0 already. https://gcc.godbolt.org/z/d8YzshsTW
Is it 100% safe to assume the c++ compiler will never OR those 3 bitboards together every time it executes that code, but instead inserts a 64bit constant that is the result of (Rank6 | Rank7 | Rank8) to avoid calculate it every time?
Clang GCC MSVC - 100% Yes!
Some embedded micropocessor C++ Compiler: Not 100% safe
You can FORCE the issue by using template parameters or macros.
So for all intents and purposes the compiler knows constexpr is immutable and will constant fold it away. 100% yes for clang GCC msvc