errno is not nothrow

Neia Neutuladh neia at ikeran.org
Sun May 13 05:52:02 UTC 2018


On Friday, 11 May 2018 at 19:01:05 UTC, H. S. Teoh wrote:
> This sounds scary.  So my (strongly!) pure function that 
> returns floating-point can return different results when passed 
> the same parameters, if somebody in between changes 
> floating-point flags?  That doesn't sound good at all.

This is an ugly problem, and I'm not sure what the best solution 
would be. The current one is simple to understand and only has a 
little surprising behavior (multiple invocations to the same pure 
function with the same parameters might yield the same results, 
even if floating point flags have changed).

I'd like to hear about any reasonable alternatives. Here are a 
few unreasonable ones I thought up:

1. The compiler could have the function store its FPU flag state 
somewhere. It would involve adding a preamble to each pure 
function:

---
static bool fpeInitialized = false;
static fenv_t fpeEnv;
fenv_t previous;
if (fegetenv(&previous)) assert(0, "failed to get FPU 
environment");
scope (exit) if (fesetenv(&previous)) assert(0, "failed to 
restore FPU environment");
if (fpeInitialized)
{
     fesetenv(&fpeEnv);
}
else
{
     fpeEnv = previous;
     fpeInitialized = true;
}
---

On my machine, that's an overhead of about 2.5 microseconds per 
function call. On top of a trivial pure function, it's a 47× 
overhead.

But ignoring the performance cost, is that even vaguely 
desirable? Whatever you first call the pure function with, it's 
always going to use the same FPU environment. Accidentally call 
it inside a static constructor and you set your FPU flags in 
main() ? Your intent is silently ignored. And should the FPU 
environment be thread-local? If it isn't, I might see different 
results if I run the same code in different threads. If it is, 
then the compiler might need to use atomic variables or locking, 
and that would be horribly slow. Plus a surprising runtime 
dependency, probably, that prevents pure functions from working 
with -betterC.

2. Pure functions could require you to inform the compiler of 
your desired FPU flags. This means the compiler, not the runtime, 
needs to know about how to set FPU flags on every supported 
architecture. It also means it's a lot harder to use pure 
functions, and they're less portable. They will also all have 
overhead from setting FPU flags and resetting them after, but it 
fixes all  the other problems from the first option.

3. You could tell the compiler to watch out for people changing 
the FPU environment, and then it won't try to omit duplicate 
function calls. This means any function that the compiler is not 
going to emit into the same object file, or that might be 
overridden in another object file. It eats into the promise that 
adding `pure` means your code becomes faster automatically.


More information about the Digitalmars-d mailing list