Conversation

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.

3
0
0
@keithp Linux uses some compiler option to avoid this hoisting for integer stuff, not sure if it's the same for FP. I know it's there because I told Will there was a race condition in the mmiowb emulation code, but he told me the option prevented the reordering -- I know that thread was public, but I forgot if our discussion was...
0
0
0

@keithp

STDC do what you're told and don't try to be smart

maybe we can propose the addition to the standard 8-D

1
1
0

@oblomov Surely there are people who have figured this out though; otherwise you couldn't use llvm for floating point at all?

0
0
0

@keithp oh, for LLVM it's actually easy, -ftrapping-math or STDC FENV_ACCESS on

1
0
0

@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; }

1
0
0

@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.

1
0
0

@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?

1
0
0

@keithp it seems using the pragma yields a warning on soft-float; it's possible to guard the pragma with __SOFTFP__, but this FTM is arm-specific :/

1
0
0

@amonakov I can guard it with FE_OVERFLOW as that's what I'm really trying to preserve.

1
0
0

@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

1
1
0

@amonakov And presumably I should replace

clang_barrier_float(x * two25)

with

clang_barrier_float(x) * two25

a few lines further along?

1
0
0

@keithp yes, same idea (or make the load of two25 constant non-hoistable)

0
1
0