The function CodeGenFunction::EmitBuiltinExpr emit builtin call (including math library builtin call), there is some comment that
There are LLVM math intrinsics/instructions corresponding
to math library functions except the LLVM op will never set
errno while the math library might.
...
ConstAttr is enabled in fast-math mode. In fast-math mode,
math-errno is disabled.
Base on the above comment, the math library functions will access some global variables, so they are not always match to attribute((const)) , so it should be improved with -ffast-mode ? (gcc has more radical optimization even without -ffast-mode)
Oh, I find function Sema::AddKnownFunctionAttributes will add const attribute for implicitly-declared builtins , but we still don’t get some difference between with/without the -ffast-math.
llvm: When built with O3, use 2 load to get num[i] before and after the call expf
gcc: Only one load for num[i] because it use the callee save register
float foo (float num[], float r2inv, int n) {
float sum = 0.0;
for (int i=0; i < 1000; i++) {
float a = num[i];
// const float r = a / std::sqrt (r2inv);
const float expm2 = std::exp (a);
float tmp = expm2 * num[i];
sum += tmp * tmp;
}
return sum;
}
GCC seems to know that errno and num (or num[i]) can’t alias.
While “const” would imply this, it is not correct due to the potential errno write.
We should make the memory attribute more descriptive, or stopgap this by teaching (some) AA about math calls.
Thanks @jdoerfert .
I think the math calls don’t access the errno when we compile source with -ffast-math , so it can be added with const attribute in that case, does it right?
I’m actually if errno set by math functions being used anywhere beside tests. Like on Darwin matherrhandling is set to floating point exception only I think.
As far as I can tell, the only reason we know that exp() doesn’t alias num[i] here is that the access is via a float. If num were an array of int, then it might have been defined as num = &errno.
So possibly this can be solved by emitting “int” TBAA metadata on FP libcalls? Or at least, I think there has to be some interaction with TBAA metadata here.
When I try to simplify the test case, I’m surprised to find that there are difference between with/without the -ffast-math base on the small case Compiler Explorer
At least in this example, the suggested min-max-object size would suffice to classify this as non-alias; no TBAA needed.
We would need to know that errno is of size “int”, but some knowledge about math functions was always going to be required.
The access to num[i] is known to access an object of at least 1000 * sizeof(int) which can’t alias with a single int. Similar reasoning would help us with a lot of loop conditions that are read, e.g., from globals.