<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 - miscompilation of small integer bit math"
   href="https://bugs.llvm.org/show_bug.cgi?id=34349">34349</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>miscompilation of small integer bit math
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

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

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

        <tr>
          <th>OS</th>
          <td>Linux
          </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>Scalar Optimizations
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>andrew.b.adams@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Sometime in between 311774 and 311796 the following ll started producing
different results with and without running opt. Perhaps r311789 uncovered
something? It's a routine to do unsigned 8-bit int division by 201 using bit
tricks. I do not believe it exploits any UB.

Before opt:

define i8 @fast_div_201(i8 %p) {
entry:
  %v3 = zext i8 %p to i16
  %v4 = mul i16 %v3, 71
  %v5 = lshr i16 %v4, 8
  %v6 = trunc i16 %v5 to i8
  %v7 = sub i8 %p, %v6
  %v8 = lshr i8 %v7, 1
  %v9 = zext i8 %p to i16
  %v10 = mul i16 %v9, 71
  %v11 = lshr i16 %v10, 8
  %v12 = trunc i16 %v11 to i8
  %v13 = add i8 %v12, %v8
  %v14 = lshr i8 %v13, 7
  ret i8 %v14
}

opt -O3 with trunk unconditionally returns zero:

define i8 @fast_div_201(i8 %p) local_unnamed_addr #0 {
entry:
  ret i8 0
}

opt -O3 with llvm 3.8 just cleans up the common subexpressions:

define i8 @fast_div_201(i8 %p) #0 {
entry:
  %v3 = zext i8 %p to i16
  %v4 = mul nuw nsw i16 %v3, 71
  %v5 = lshr i16 %v4, 8
  %v6 = trunc i16 %v5 to i8
  %v7 = sub i8 %p, %v6
  %v8 = lshr i8 %v7, 1
  %v13 = add nuw i8 %v8, %v6
  %v14 = lshr i8 %v13, 7
  ret i8 %v14
}

As an example for why zero is the wrong output, I'll plug in the largest
possible value of the input (255) and see what each value is:

define i8 @fast_div_201(i8 %p) {
entry:
  %v3 = zext i8 %p to i16     // u16(255)
  %v4 = mul i16 %v3, 71       // u16(18105)
  %v5 = lshr i16 %v4, 8       // u16(70)
  %v6 = trunc i16 %v5 to i8   // u8(70)
  %v7 = sub i8 %p, %v6        // u8(185)
  %v8 = lshr i8 %v7, 1        // u8(92)
  %v9 = zext i8 %p to i16     // u16(255)
  %v10 = mul i16 %v9, 71      // u16(18105)
  %v11 = lshr i16 %v10, 8     // u16(70)
  %v12 = trunc i16 %v11 to i8 // u8(70)
  %v13 = add i8 %v12, %v8     // u8(162)
  %v14 = lshr i8 %v13, 7      // u8(1)
  ret i8 %v14                 // 255/201 == 1
}</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>