<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - After r307529, sinl() test failures in FreeBSD's libm"
   href="https://bugs.llvm.org/show_bug.cgi?id=34080">34080</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>After r307529, sinl() test failures in FreeBSD's libm
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>dimitry@andric.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>I recently imported a clang 5.0.0 snapshot (from just before the release_50
branch) into FreeBSD 12.0-CURRENT, and soon after we noticed that one of our
libm regression tests was failing, in particular the sinl(3) test.

It turns out that this failure was introduced by r307529 ("This patch
completely replaces the scheduling information for the SandyBridge architecture
target by modifying the file X86SchedSandyBridge.td located under the X86
Target"), see also <a href="https://reviews.llvm.org/D35019">https://reviews.llvm.org/D35019</a>.

I did a bit of investigation, and it turned out that r307529 changes the x87
instruction order, but I do not yet know if this is due to some sort of
undefined behavior in the sinl code, or a bug in LLVM.

The code in question can be found here:
<a href="https://github.com/freebsd/freebsd/blob/master/lib/msun/ld80/e_rem_pio2l.h">https://github.com/freebsd/freebsd/blob/master/lib/msun/ld80/e_rem_pio2l.h</a>

The part that seems to be miscompiled is the for loop from line 137 onwards,
looking like:

    43  static const double
    44  zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
    45  two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
...
    77          long double z,w,t,r,fn;
    78          double tx[3],ty[2];
    79          int e0,ex,i,j,nx,n;
...
   136          z = u1.e;
   137          for(i=0;i<2;i++) {
   138                  tx[i] = (double)((int32_t)(z));
   139                  z     = (z-tx[i])*two24;
   140          }
   141          tx[2] = z;

Before r307529, this loop is unrolled to:

        #DEBUG_VALUE: sinl:z <- [DW_OP_LLVM_fragment 0 80] %FP1
        #DEBUG_VALUE: sinl:x <- %FP0
        .loc    1 0 6                   #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:0:6
        fstp    %st(0)
        .loc    1 84 7 is_stmt 1        #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:84:7
        shll    $16, %ebx
        .loc    1 135 19                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:135:19
        movq    %rax, -96(%rbp)
        movw    $16406, -88(%rbp)       # imm = 0x4016
        fldt    -96(%rbp)
.Ltmp44:
        #DEBUG_VALUE: __ieee754_rem_pio2l:z <- %FP0
        #DEBUG_VALUE: __ieee754_rem_pio2l:u1 <- [DW_OP_LLVM_fragment 0 80] %FP0
        .loc    1 138 20                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        fnstcw  -68(%rbp)
        movzwl  -68(%rbp), %eax
        movw    $3199, -68(%rbp)        # imm = 0xC7F
        fldcw   -68(%rbp)
        movw    %ax, -68(%rbp)
        fistl   -72(%rbp)
        fldcw   -68(%rbp)
        .loc    1 138 11 is_stmt 0      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:11
        cvtsi2sdl       -72(%rbp), %xmm0
        .loc    1 138 9                 #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:9
        movsd   %xmm0, -48(%rbp)
        .loc    1 139 10 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:10
        movsd   %xmm0, -152(%rbp)
        .loc    1 139 9 is_stmt 0       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:9
        fsubl   -152(%rbp)
        .loc    1 139 16                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:16
        flds    .LCPI0_1(%rip)
        fmul    %st(0), %st(1)
        #DEBUG_VALUE: __ieee754_rem_pio2l:z <- %FP0
        .loc    1 138 20 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        fnstcw  -66(%rbp)
        movzwl  -66(%rbp), %eax
        movw    $3199, -66(%rbp)        # imm = 0xC7F
        fldcw   -66(%rbp)
        movw    %ax, -66(%rbp)
        fxch    %st(1)
        fistl   -76(%rbp)
        fldcw   -66(%rbp)
        .loc    1 138 11 is_stmt 0      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:11
        xorps   %xmm0, %xmm0
        cvtsi2sdl       -76(%rbp), %xmm0
        .loc    1 138 9                 #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:9
        movsd   %xmm0, -40(%rbp)
        .loc    1 139 10 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:10
        movsd   %xmm0, -144(%rbp)
        .loc    1 139 9 is_stmt 0       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:9
        fsubl   -144(%rbp)
        .loc    1 139 16                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:16
        fmulp   %st(1)
.Ltmp45:
        .loc    1 141 8 is_stmt 1       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:141:8
        fstpl   -32(%rbp)

After r307529, it becomes:

        #DEBUG_VALUE: sinl:z <- [DW_OP_LLVM_fragment 0 80] %FP1
        #DEBUG_VALUE: sinl:x <- %FP0
        .loc    1 0 6                   #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:0:6
        fstp    %st(0)
        .loc    1 135 19 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:135:19
        movq    %rax, -96(%rbp)
        movw    $16406, -88(%rbp)       # imm = 0x4016
        fldt    -96(%rbp)
.Ltmp44:
        #DEBUG_VALUE: __ieee754_rem_pio2l:z <- %FP0
        #DEBUG_VALUE: __ieee754_rem_pio2l:u1 <- [DW_OP_LLVM_fragment 0 80] %FP0
        .loc    1 138 20                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        fnstcw  -68(%rbp)
        movzwl  -68(%rbp), %eax
        movw    $3199, -68(%rbp)        # imm = 0xC7F
        fldcw   -68(%rbp)
        movw    %ax, -68(%rbp)
        fistl   -72(%rbp)
        fldcw   -68(%rbp)
        .loc    1 138 11 is_stmt 0      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:11
        cvtsi2sdl       -72(%rbp), %xmm0
        .loc    1 138 9                 #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:9
        movsd   %xmm0, -48(%rbp)
        .loc    1 139 10 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:10
        movsd   %xmm0, -152(%rbp)
        .loc    1 139 9 is_stmt 0       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:9
        fsubl   -152(%rbp)
        .loc    1 138 20 is_stmt 1      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        fnstcw  -66(%rbp)
        .loc    1 139 16                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:16
        flds    .LCPI0_1(%rip)
        .loc    1 138 20                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        movzwl  -66(%rbp), %eax
        movw    $3199, -66(%rbp)        # imm = 0xC7F
        fldcw   -66(%rbp)
        .loc    1 139 16                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:16
        fmul    %st(0), %st(1)
        #DEBUG_VALUE: __ieee754_rem_pio2l:z <- %FP0
        .loc    1 138 20                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:20
        movw    %ax, -66(%rbp)
        fxch    %st(1)
        fistl   -76(%rbp)
        fldcw   -66(%rbp)
        .loc    1 138 11 is_stmt 0      #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:11
        xorps   %xmm0, %xmm0
        cvtsi2sdl       -76(%rbp), %xmm0
.Ltmp45:
        .loc    1 84 7 is_stmt 1        #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:84:7
        shll    $16, %ebx
.Ltmp46:
        .loc    1 138 9                 #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:138:9
        movsd   %xmm0, -40(%rbp)
        .loc    1 139 10                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:10
        movsd   %xmm0, -144(%rbp)
        .loc    1 139 9 is_stmt 0       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:9
        fsubl   -144(%rbp)
        .loc    1 139 16                #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:139:16
        fmulp   %st(1)
.Ltmp47:
        .loc    1 141 8 is_stmt 1       #
/usr/src/lib/msun/src/../ld80/e_rem_pio2l.h:141:8
        fstpl   -32(%rbp)

Viewed as a context diff this looks as follows:

@@ -179,7 +179,6 @@
        jbe     .LBB0_9
 .LBB0_14:                               # %if.end80.i
        fstp    %st(0)
-       shll    $16, %ebx
        movq    %rax, -96(%rbp)
        movw    $16406, -88(%rbp)       # imm = 0x4016
        fldt    -96(%rbp)
@@ -194,18 +193,19 @@
        movsd   %xmm0, -48(%rbp)
        movsd   %xmm0, -152(%rbp)
        fsubl   -152(%rbp)
-       flds    .LCPI0_1(%rip)
-       fmul    %st(0), %st(1)
        fnstcw  -66(%rbp)
+       flds    .LCPI0_1(%rip)
        movzwl  -66(%rbp), %eax
        movw    $3199, -66(%rbp)        # imm = 0xC7F
        fldcw   -66(%rbp)
+       fmul    %st(0), %st(1)
        movw    %ax, -66(%rbp)
        fxch    %st(1)
        fistl   -76(%rbp)
        fldcw   -66(%rbp)
        xorps   %xmm0, %xmm0
        cvtsi2sdl       -76(%rbp), %xmm0
+       shll    $16, %ebx
        movsd   %xmm0, -40(%rbp)
        movsd   %xmm0, -144(%rbp)
        fsubl   -144(%rbp)

E.g., apart from the moving around of 'shll $16, %ebx', which does not
influence the end result, the loading of the LCPI0_1 constant and multiplying
it is moved further into the code, and that definitely does influence the
result.

I would like to get to the bottom of this before 5.0.0 is released, if
possible, otherwise I would propose to revert r307529, at least in the
release_50 branch.  But it should still be fixed somehow.

Currently I have a small test case which is derived from the libm code in
e_rem_pio2l.h, but it does not seem to exhibit the same problem, for some
reason that I do not know yet:

#include <stdio.h>

__attribute__((noinline)) void g(double *tx) {
  printf("tx[0]=%.20a tx[1]=%.20a tx[2]=%.20a\n", tx[0], tx[1], tx[2]);
}

static const double two24 = 1.67772160000000000000e+07;

__attribute__((noinline)) void f(long double z) {
  int i;
  double tx[3];
  for (i = 0; i < 2; i++) {
    tx[i] = (double)((int)(z));
    z = (z - tx[i]) * two24;
  }
  tx[2] = z;
  g(tx);
}

int main(void)
{
  f(0x1.b2f3ee96e76003260000p+23);
  return 0;
}

The correct values this should print are:

tx[0]=0x1.b2f3ee00000000000000p+23, tx[1]=0x1.2dcec000000000000000p+22,
tx[2]=0x1.93000000000000000000p+16</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>