Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 26 Feb 2019 14:55:24 +1100 (AEDT)
From: Damian McGuckin <damianm@....com.au>
To: musl@...ts.openwall.com
Subject: Re: FE Exception triggered by comparison


Hi Markus,

Thanks for taking the time to reply in depth.

Where I am coming from is some research writing low level routines for a 
language other than C/C++, learning lessons from that, and then wanting to 
contribute that back some of what I have learnt in a fashion that can be 
used in MUSL. The metrics/goals/style in that other programming language 
are somewhat different to MUSL so I only want to give back what integrates 
well into MUSL's metrics/goals/style. That way, I do not waste anyone's 
time.

On Mon, 25 Feb 2019, Markus Wichmann wrote:

> On Mon, Feb 25, 2019 at 08:50:52AM +1100, Damian McGuckin wrote:

>> The context of this is that I want a coding style which means I can 
>> compare numbers without affecting the exception state. And it must have 
>> zero overhead, and not affect the readability of the code, i.e. no 
>> function calls.
>
> Yet another problem brought to you by premature optimization. What you
> want to know is if a certain number is NaN. There's a perfectly
> acceptable idiom for that:
>
> if (isnan(x)) {
> }

I understand this. But, at least on an X86 architecture, that involves a 
write-to+read-from memory and I want to avoid that.

> This (the exception stuff) is the reason why the special cases are
> always front-loaded in musl. So they can be sorted out without raising
> spurious exceptions.

Front-loading often results in more lines of code and regularly, less 
lines of code means faster execution so with careful avoidance of the 
front-loading is feasible, I prefer it.

> The only reason the above may not be acceptable to you is that it looks
> like a function call. But it isn't. isnan() is a macro that doesn't
> always revert to a function call.

All of the fpclassify() and friends routines are quite heavy, even if they 
are macros and are done in line so I avoid them. That is just my opinion. 
Do I have a better solution for usage by the masses - No, well not in 
C/C++. See my later comments on builtins.

>> I want to know that
>>
>> 	x != x
>>
>> will always detect any NaN with affecting the exception status and that
>> comparisons like
>>
>> 	if (x == x) { ... }
>> 	else if (x > y) { .... }
>> 	else if (x < y) { .... }
>> 	else { x or y are NaN }
>>
>> will similarly also not modify the exception status, and in the last 
>> section let me process how I interpret the NaNs.

> Well, sorry, but these instructions do not work that way. Any operation
> on a NaN, including comparison, even comparison for equality, will raise
> IE, at least if it is an sNaN.

Table 5.1 of the 20X8 standard, as I read it, and as confirmed by Kahan's 
lecture notes, says that neither equality nor inequality is supposed to 
raise an IE on a qNaN. As you rightly say, Kahan's lecture notes, the 1985 
standard and Table 5.2 in the 2008 and the 2018(draft) standards says that 
any comparison with a '<' or '>' as part (or all) of the predicate should 
raise IE.

However, on experiments on GCC, the if/else/else/else above does not raise 
an IE. Is this an optimizer bug? For a while there, I questioned my whole 
understanding of the standard in terms of comparison until I went back to 
it and re-read it. Something is weird with GCC. And either you or I has 
the wrong understanding of what Table 5.1 implies for both an equality and 
an inequality comparison. And at least mine agrees with Kahan's lecture 
notes. It is not the latest GCC but one that I, and clients, need to use.

Note that if I manually create an sNaN and use it in the comparisons, then 
GCC behaves as the standard says. I wish I knew what creates an sNaN. The
only optimization I use is -O3.

> Honestly, though, I wonder what the big deal is. In most cases, if you 
> see a NaN, someone probably just made an invalid operation, or chose to 
> start another invalid operation with your function. In which case 
> raising IE is not spurious at all.

I agree that in most cases it is not a big deal. And the raising of an IE 
is not spurious in most cases. But there are cases where it is. I tried to 
rewrite frexp so it can be done in line but I get an IE which is a no-no 
for this routine. I know that frexp is supposed to be builtin in GCC/G++ 
but I kept seeing the function call in the assembler so I have no idea why 
GCC says it is builtin. Hence my original reason for doing frexp.

>> Otherwise, avoidance of creating spurious exceptions forces you to 
>> start working at the IEEE 754 encoding level.
>
> Or you could just use the interface provided by the C standard:
>
> if (!isnormal(x) || !isnormal(y)) {
>    guard clause here;
>    return;
> }

Again, memory access is the killer. Also, there is a lot of duplication in 
those macros that does not always get optimized away unless you rely on a 
built-in. And I try and stay away from things that one or another compiler 
thinks is a built-in.

I do need to deal with subnormals but I can handle that. Besides, any 
comparison of subnormals does not trigger an exception unless there are 
arithmetic expressions as either a LHS or RHS of the comparison operator. 
Mind you, I once saw some code where it looks like the author did think 
that an underflow exception got triggered during the comparison of a 
possibly subnormal number against a constant which was not subnormal.

> Musl strives to minimize the numeric error while also delivering good 
> performance, and that means that often a lot of boundary conditions can 
> be detected at the same time with a single comparison (e.g. you can 
> detect "x < 0 || x > 2**limit || isinf(x)" by detecting if the exponent 
> and sign bit together exceed a certain limit.)

What MUSL's strives to do is indeed what I also seek. That said, I have 
found that you often get less lines of code and better performance if you 
can postpone the inspection of the IEEE 754 encoding as late as possible 
within a routine. It is only at that point do you think about extracting 
the exponent and sign cheaply.

Just my 2c.

Regards - Damian

Pacific Engineering Systems International, 277-279 Broadway, Glebe NSW 2037
Ph:+61-2-8571-0847 .. Fx:+61-2-9692-9623 | unsolicited email not wanted here
Views & opinions here are mine and not those of any past or present employer

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.