|
|
Message-ID: <20260820123722.GK3542221@port70.net>
Date: Thu, 20 Aug 2026 14:37:22 +0200
From: Szabolcs Nagy <nsz@...t70.net>
To: Rich Felker <dalias@...c.org>
Cc: musl@...ts.openwall.com, Sergey Davidoff <shnatsel@...il.com>
Subject: Re: [PATCH v4 2/2] math: fmaf rewrite
* Rich Felker <dalias@...c.org> [2026-08-19 19:09:58 -0400]:
> On Wed, Aug 19, 2026 at 11:05:59PM +0200, Szabolcs Nagy wrote:
> > * Rich Felker <dalias@...c.org> [2026-08-19 15:53:43 -0400]:
> > > On Wed, Aug 19, 2026 at 05:28:28PM +0200, Szabolcs Nagy wrote:
> > > > + if (!halfway && !tiny)
> > >
> > > Shouldn't this just be:
> > >
> > > if ((!halfway && !tiny) || e == 0x7ff)
> > >
> > > so that the rest of the function doesn't have to be conditional? Or am
> > > I missing something?
> >
> > yeah that works too.
> >
> > i was trying to keep the hot path clearly separate
> > and it was easier to place comments
> >
> > and i think gcc is also more likely to move the
> > e==0x7ff check out of the straight line hot path
>
> I would expect that it first evaluates (!halfway && !tiny) and reaches
> the normal hot path without even comparing e with 0x7ff. With CSE, I
> wouldn't even be surprised if both versions of the code generate
> identical asm. This is how I noticed it -- I was looking for "what's
> different in the slow path where the value is inf/nan?" and found
> "nothing".
>
> And as written, !halfway is true for inf and most nan, and !tiny is
> true for all inf and nan, so only very specific nans get to the
> explicit check for e != 0x7ff.
(on many implementations float to double conv keeps the
nan payload in the top bits, so e==0x7ff cannot be halfway,
but this is impl defined in ieee754)
fwiw clang generates the same code either way
(likes to compute all the conditionals then do a signle
branch, for optimal codegen it needs __builtin_expect),
gcc on x86_64:
your:
...
27: and $0x1fffffff,%ecx
2d: and $0x7ff,%eax
32: cmp $0x10000000,%rcx
39: lea -0x36a(%rax),%esi
3f: sete %cl
42: cmp $0x17,%esi
45: setbe %sil
49: or %sil,%cl
4c: je 7d <fmaf+0x7d> // !(halfway|tiny)
4e: cmp $0x7ff,%eax
53: je 7d <fmaf+0x7d> // nan
...
7d: cvtsd2ss %xmm0,%xmm0
81: ret
...
mine:
...
27: and $0x1fffffff,%ecx
2d: and $0x7ff,%eax
32: cmp $0x10000000,%rcx
39: je 4b <fmaf+0x4b> // halfway
3b: lea -0x36a(%rax),%ecx
41: cmp $0x17,%ecx
44: jbe 4b <fmaf+0x4b> // tiny
46: cvtsd2ss %xmm0,%xmm0
4a: ret
4b: cmp $0x7ff,%eax
50: je 46 <fmaf+0x46> // nan
...
mine happens to be pretty much optimal (straight, short
hot path) measurable with microbenching on my old laptop
but not a huge diff (3 vs 3.3ns/call with no deps between
calls, i.e. throughput, and 9.4 vs 9.6ns/call with deps,
i.e. latency).
> > with my code, so hot code is tighter together.
> > but it's a bit random what compilers do, so i'm
> > fine either way.
>
> I don't have a strong opinion on it, but I wonder if the version I
> suggested makes more sense.
it's a code style issue so i let you decide, attached
v5:
- move the e==0x7ff check
View attachment "v5-0002-math-fmaf-rewrite.patch" of type "text/x-diff" (5631 bytes)
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.