Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
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.