With this patch the float -> __bf16 conversion still gives a different
result with and without AVX512BF16 for the same float input:
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math -march=x86-64" } */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/* Both functions are just "return a;". FOO is compiled for plain
x86-64, so it uses the inline expansion; BAR uses vcvtneps2bf16. */
__attribute__ ((noipa, noinline))
static __bf16
foo (float a)
{
return a;
}
__attribute__ ((noipa, noinline, target ("avx512vl,avx512bf16")))
static __bf16
bar (float a)
{
return a;
}
static uint16_t
bits16 (__bf16 x)
{
uint16_t r;
memcpy (&r, &x, sizeof (r));
return r;
}
int
main (void)
{
uint32_t v[] = { 0x007f8000, 0x807f8000, 0x007fffff, 0x807fffff,
0x007f7fff, 0x00367000, 0x00800000 };
for (unsigned i = 0; i < sizeof v / sizeof v[0]; i++)
{
float f;
memcpy (&f, &v[i], sizeof (f));
uint16_t a = bits16 (foo (f));
uint16_t b = bits16 (bar (f));
printf ("0x%08x foo=0x%04x bar=0x%04x %s\n",
v[i], a, b, a == b ? "same" : "DIFFER");
}
return 0;
}
On AVX512BF16 hardware this prints:
0x007f8000 foo=0x0080 bar=0x0000 DIFFER
0x807f8000 foo=0x8080 bar=0x8000 DIFFER
0x007fffff foo=0x0080 bar=0x0000 DIFFER
0x807fffff foo=0x8080 bar=0x8000 DIFFER
0x007f7fff foo=0x0000 bar=0x0000 same
0x00367000 foo=0x0000 bar=0x0000 same
0x00800000 foo=0x0080 bar=0x0080 same
These are SFmode denormals: vcvtneps2bf16 returns a sign preserving zero,
the inline expansion returns +-0x0080, i.e. +-2^-126. Sweeping the whole
SFmode denormal range, 65536 inputs differ, the 32768 mantissas in
[0x7f8000, 0x7fffff] for each sign.
The reason is that the flush test is applied to the rounded result rather
than to the input:
> + /* TMP1 is zero or denormal if (TMP1 & 0x7f80) == 0. */
> + tmp0 = expand_simple_binop (SImode, AND, tmp1, GEN_INT(0x7f80),
> + nullptr, 0, OPTAB_DIRECT);
Testing REG1_SI & 0x7f800000 instead makes the two agree for all 2^32
non-NaN inputs.
________________________________________
From: H.J. Lu <[email protected]>
Sent: Sunday, 23 August 2026 23:20:50
To: GCC Patches; Uros Bizjak; Liu, Hongtao
Subject: [v2 PATCH] x86: Expand the default truncsfbf2 like vcvtneps2bf16
On Wed, Aug 19, 2026 at 9:51 PM H.J. Lu <[email protected]> wrote:
>
> Expand the default truncsfbf2 like vcvtneps2bf16, which doesn't honor
> SNAN, turns sNAN into qNAN quietly, it always rounds to nearest even
> and flushes denormals to zero, with
>
> (fromi + 0x7fff + ((fromi >> 16) & 1)) >> 16
>
> and flush denormals to zero.
>
> gcc/
>
> PR target/126933
> * config/i386/i386-expand.cc (ix86_expand_truncsfbf2): New.
> * config/i386/i386-protos.h (ix86_expand_truncsfbf2): Likewise.
> * config/i386/i386.md (truncsfbf2): Changed to define_expand.
> (truncsfbf2_vcvtneps2bf16): New.
>
> gcc/testsuite/
>
> PR target/126933
> * gcc.target/i386/truncsfbf-1.c (dg-options): Add
> -mno-avxneconvert -mno-avx512bf16 -fno-asynchronous-unwind-tables.
> Use check-function-bodies to check updated codegen.
> * gcc.target/i386/truncsfbf-2.c (dg-options): Add
> -mno-avxneconvert -mno-avx512bf16.
> (foo): Make it static with __attribute__ ((noipa, noinline)).
> (CALC): Add __attribute__ ((noipa, noinline)). Flush denormal
> to zero.
> * gcc.target/i386/truncsfbf-3.c: New test.
> * gcc.target/i386/truncsfbf-4.c: Likewise.
> * gcc.target/i386/truncsfbf-5.c: Likewise.
> * gcc.target/i386/truncsfbf-6.c: Likewise.
>
truncsfbf2 should behave the same with -funsafe-math-optimizations
regardless if AVXNECONVERT or AVX512BF16 are available or not.
Changes in v2:
1. Remove duplicated codes in ix86_expand_truncsfbf2
2. Scan cmov, instead of branch, in gcc.target/i386/truncsfbf-1.c.
--
H.J.