Skip to content

Possible wrong code generation when building glibc ldbl-128 powl #173080

@zatrazz

Description

@zatrazz

After enabling experimental clang build support on glibc, the _Float128 powl support shows some regressions:

$ math/test-float128-pow
Failure: pow (-0x1.000002p+0, 0xf.ffffffffffff8p+1020): Exception "Underflow" set
Failure: pow (-0x1.000002p+0, 0xf.ffffffffffffbffffffffffffcp+1020): Exception "Underflow" set
Failure: pow (-0x1.000002p+0, 0xf.fffffffffffffffffffffffffff8p+16380): Exception "Underflow" set
Failure: pow (-0x1.000002p+0, 0xf.fffffffffffffffp+16380): Exception "Underflow" set
Failure: pow (-0x1.000002p+0, 0xf.fffffp+124): Exception "Underflow" set
Failure: pow (-0x1.00000ep+0, 0xf.ffffffffffff8p+1020): Exception "Underflow" set
Failure: pow (-0x1.00000ep+0, 0xf.ffffffffffffbffffffffffffcp+1020): Exception "Underflow" set
Failure: pow (-0x1.00000ep+0, 0xf.fffffffffffffffffffffffffff8p+16380): Exception "Underflow" set
Failure: pow (-0x1.00000ep+0, 0xf.fffffffffffffffp+16380): Exception "Underflow" set
Failure: pow (-0x1.00000ep+0, 0xf.fffffp+124): Exception "Underflow" set
[...]
Test suite completed:
Maximum error found of `2' ulp
4 max error test cases,
11912 input tests,

  • with 47792 tests for exception flags,
  • with 9350 tests for errno executed.
    680 errors occurred.

The issues seems that clang is moving out the the multiplication used to raise overflow/underflow (hugehuge and tinytiny) before the check 'iy' check [1]:

  /* |y| is huge.
     2^-16495 = 1/2 of smallest representable value.
     If (1 - 1/131072)^y underflows, y > 1.4986e9 */
  if (iy > 0x401d654b)
    {
      /* if (1 - 2^-113)^y underflows, y > 1.1873e38 */
      if (iy > 0x407d654b)
        {
          if (ix <= 0x3ffeffff)
            return (hy < 0) ? huge * huge : tiny * tiny;
          if (ix >= 0x3fff0000)
            return (hy > 0) ? huge * huge : tiny * tiny;
        }
      /* over/underflow if x is not close to one */
      if (ix < 0x3ffeffff)
        return (hy < 0) ? sgn * huge * huge : sgn * tiny * tiny;
      if (ix > 0x3fff0000)
        return (hy > 0) ? sgn * huge * huge : sgn * tiny * tiny;
    }

If I force the multiplication to be optimized away with the math_opt_barrier barrier, it works as expected.

To reproduce it build the commit be48ae12b10b0556895e356c3ae34b8ca229e61b or higher with clang-18 or higher. Currently only x86_64 and aarch64 is supported, but both exports the implementation (either by powl on aarch64 or powf128 on x86_64). Keep in mind that glibc explicit builds libm and all tests with -ftrapping-math.

I will try to come-up with a more contrieved example.

[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/ldbl-128/e_powl.c;h=4e20616705633885c661f4bda3175aac7adc0375;hb=HEAD#l276

Metadata

Metadata

Assignees

No one assigned

    Labels

    diverges-from:gccDoes the clang frontend diverge from gcc on this issuefloating-pointFloating-point mathmiscompilationneeds-reductionLarge reproducer that should be reduced into a simpler form

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions