From Andre@G||||bert @end|ng |rom chu-rouen@|r  Fri Oct  1 18:14:57 2021
From: Andre@G||||bert @end|ng |rom chu-rouen@|r (GILLIBERT, Andre)
Date: Fri, 1 Oct 2021 16:14:57 +0000
Subject: [Rd] 
 [External] Re: Workaround very slow NAN/Infinities arithmetic?
In-Reply-To: <CAD4oTHE7MeOYG3MRbHbwHS76HpHj783__ku0GoNQN9iqOvvxUg@mail.gmail.com>
References: <3eebe90a11cc42e1a14a41b407e40690@chu-rouen.fr>
 <1810868025.554414.1633004867238@mail.yahoo.com>
 <alpine.DEB.2.22.394.2109301143220.2872@luke-Latitude-7480>
 <CAD4oTHE7MeOYG3MRbHbwHS76HpHj783__ku0GoNQN9iqOvvxUg@mail.gmail.com>
Message-ID: <ac7871d0bf6249fa9946e9be5e084679@chu-rouen.fr>


> Mildly related (?) to this discussion, if you happen to be in a situation
> where you know something is a C NAN, but need to check if its a proper R
> NA, the R_IsNA function is surprisingly (to me, at least) expensive to do
> in a tight loop because it calls the (again, surprisingly expensive to me)
> isnan function.  

What is your platform? CPU, OS, compiler?
How much expensive? 5-10 times slower than the improved code you wrote, or 100-200 times slower?

I analyzed the C and assembly source code of R_IsNA on a x86_64 GNU/Linux computer (Celeron J1900) with GCC 5.4 and found that it was somewhat expensive, but the main problems did not seem to come from isnan.

isnan was only responsible of a ucomisd xmm0, xmm0 instruction followed by a conditional jump on x86_64. This instruction is slower on NAN than on normal FP, but it seems to have an acceptable speed.
On x86_32, the isnan is  responsible of a fld mem64, fst mem64, fucomip and conditional jump : it is suboptimal, but things could be worse.

On x86_64, the first problem I noticed is that R_IsNA is not inlined, and the registry-based x86_64 Linux calling convention is not necessarily good for that problem, with added loads/unloads from memory to registry.
Second problem (the worst part) : the write of a 64-bits double followed by the read of a 32-bits integer in the ieee_double union confuses the compiler, that generates very poor code, with unnecessary load/stores.

The second problem can be solved by using a union with a uint64_t and a double fields, and using &0xFFFFFFFF to extract the low part of the uint64_t. This works well for x86_64, but also for x86_32, where GCC avoids useless emulation of 64-bits integers, directly reading the 32-bits integer.

-- 
Sincerely
Andr? GILLIBERT


[Rd] [External] Re: Workaround very slow NAN/Infinities arithmetic?
GILLIBERT, Andre