Argh. How do I get llvm to respect the conditionals in my code which avoid raising exceptions?
For something like this expression:
if (isinf(x)) return x + x;
llvm is happy to hoist the addition *above* the conditional branch:
0x19300 <frexpf+32>: cmp r3, r1
0x19304 <frexpf+36>: vaddcc.f32 s0, s0, s0
0x19308 <frexpf+40>: bxcc lr
Right now, I'm just inserting 'volatile' keywords at strategic points in the code, but I sure wish there were a compiler option to dtrt.
@oblomov Surely there are people who have figured this out though; otherwise you couldn't use llvm for floating point at all?
@amonakov Neither of those appear to work on armv7a at least. https://godbolt.org/z/sP3M8oGMa
@keithp ah, Arm backend doesn't implement LLVM constrained FP intrinsics yet, so 'x + x' gets lowered into 'noexcept VADDS' and then hoisted.
Until it does, you may want to use a helper like this:
static inline float
fp_env_barrier(float x)
{
asm volatile ("" : "+t"(x)); // constraint letter is target-dependent
return x;
}
and then { x = fp_env_barrier(x); return x + x; }
@amonakov Thanks for the help! I'm currently using this helper:
static inline float
opt_barrier_float(float x)
{
volatile float y = x;
return y;
}
which has been reliable for clang so far. I'd prefer to avoid target-specific assembly if possible, but if this won't work, I could switch.
The other issue is that -ftrapping-math is not a valid option for soft-float targets, which makes it difficult to use in a multilib build.
@keithp yes, the volatile round-trip also works, with the drawback that it results in extra instructions (store-load via stack)
does the pragma work for soft-float targets?
@keithp I noticed you have
clang_barrier_float(x + x)
in picolibc, but Clang still can hoist x + x from there, it works because the hoisting is deemed unprofitable, not because dependencies block it
my version above doesn't have this pitfall; musl uses
fp_barrier(x) + x
which is also correct, but less efficient
@amonakov And presumably I should replace
clang_barrier_float(x * two25)
with
clang_barrier_float(x) * two25
a few lines further along?
@keithp yes, same idea (or make the load of two25 constant non-hoistable)