<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/59671>59671</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            SimplifyCFG `switch` removal should add no-wrap flags when possible
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          scottmcm
      </td>
    </tr>
</table>

<pre>
    Today, LLVM optimizes
```llvm
define noundef i8 @src(i8 noundef %x) unnamed_addr {
start:
  switch i8 %x, label %bb3 [
    i8 -1, label %bb1
    i8 0, label %bb5
    i8 1, label %bb2
  ]

bb3: ; preds = %start
 unreachable

bb5:                                              ; preds = %start
  br label %bb1

bb2: ; preds = %start
  br label %bb1

bb1: ; preds = %start, %bb5, %bb2
  %.0 = phi i8 [ -1, %bb2 ], [ 0, %bb5 ], [ 1, %start ]
  ret i8 %.0
}
```
down to
```llvm
start:
  %switch.offset = sub i8 0, %x
  ret i8 %switch.offset
```

That's a huge improvement, but it could be slightly better as a `sub nsw` instead: <https://alive2.llvm.org/ce/z/GZs_dj>

If I'm understanding things right, SimplifyCFG turns the switch into
```llvm
define noundef i8 @tgt(i8 noundef %x) unnamed_addr {
start:
  %switch.tableidx = sub i8 %x, -1
  %switch.idx.mult = mul i8 %switch.tableidx, -1
 %switch.offset = add i8 %switch.idx.mult, 1
  ret i8 %switch.offset
}
```
but it *could* (https://alive2.llvm.org/ce/z/XzPeQv) have those be `sub nsw`, `mul nsw`, and `add nsw`, to better preserve the knowledge of the limited input range -- or maybe special case switches that map `0` to `0` to just emit `mul nsw` (or `nuw`) when legal without the `sub`/`add`.

Then something else (instcombine?) could take advantage of those `nsw` flags to optimize down to just the `sub nsw i8, 0, %x`: <https://alive2.llvm.org/ce/z/tESh4R>.  But it looks like they got lost right now (https://llvm.godbolt.org/z/3dMW8j1sr), so maybe there'd be more work there too.  (If SimplifyCFG left off the `sub`/`add`, though, and just had the `mul nsw`, then InstCombine looks like it would already preserve the `nsw` to the `sub` <https://llvm.godbolt.org/z/9der4sraG>.)

---

Original rust exploration that led me here: https://rust.godbolt.org/z/EW1aba8Mr
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykVltv2zgT_TX0y8CGRPn64IfcXARo8V1abBf7UlDmSGJCkQI5suP--gUpKbZy2xYbBI415HDOnHOGkfBelQZxyxbXbHE7ES1V1m393hLV-3qSW3nafrNSnBi_gc-f__gCtiFVq5_oWXLLkiu2TLpfrQ91F5JYKINgbGskFqDWwOaJd3vG12r9HGZ88cT4BlpjRI3yh5DSAVtdd2d4Eo5YdtU9Afijon0Vz4p5N6BFjjo85XkGAX6_E8KmafpiSzpaTl6sLkarL3P5sMoWt33T8TPPM5ZdAcuuoXEoPbDsNmR02Luc1jgU-0rkGsepi5D6Wz8f1oHcvdHuUIz_I86P89MP8vnNwOHw7cwXX8ySuLupVNRucd1L022MjIanxXWnSXfSZXjYHYudFQBwSL0dZkmPdnX7wpO9H-3RANl3_frSa6FatNvMFoVHih34Nn92TrTgKxijnDeBdJ_fKkGMrzwIqNoSQdWNswes0UQy85ZAEextqyXkCF6rsiJ9ghyJ0IEIiWyZBEDGH9kyAWU8oZCdSDcVUeNDO3zH-E5odUA-C93OrCsZ3-2R8d1Pxnef_vI_5APL7i7R3Rdwz_iqhjClzpMwUpkSqFKm9OACloDyq6obrYrTze4TUOuMB6rweUrNB2y_eTtQSf_mdjizT2HSlHy61Gy4Mabp6_1KPs3qVnca160eazmcNsp-0x5CynHqcHBITX_NLO_YtzcE41fRE4wHCOtfVvnPn__F_x0Cl5U4IFBlPQZfjSwUXb1MAgHngDAyBENr5yDZwYiNQ48uHonwaOxRoywRbBEDWtWKUIIyTUvghCkRplOwDmpxCrZucK-Ehr3wg28wmEgQ1KIJdQMDodzF14fWE2Ad2LgEG_iwLsRM2-HcwLFCAxpLoeGoqLItRVhd13HPruuNLZPZeDzRgLc1RssDao_h_DBje1vnyiDLdqFCN6EkHhGEPAhDYug-MBzAdOAKLUof0A__OaG_kLp2zqhCN6DWgeXzNbNMfnes6e5rNf8_y-5mANedd7S1jx60eoxinaC0Ieapm2cw9vjaUvHo0srcaupLhNMz-eX7-iH1jvFNAOltLyhV6JDxVby0ausQjtY9dmEga2dh7Nb3xejq0FgQ2KJ4X5voucq2ZTVYMrJWCTnkjE1LQb574-mmE-uyd0VwjKIJ7VDI09jCZ8XIjvG8pv8dcjYS3dw78SmwHwi68NV0Or18_I9TpTJCg4uefmq0dYKUNd0MaJRQI0ROsysYVw8pb1S_-56KXKy_uIncZnKTbcQEt-lyla6W62y5mlTbFItE5ut8s0nyLJVJJlY8FTJfzQVHkc4nassTzlPOs2SeLJPVTCbzNBVyKbJ5KlKxZ_MEa6H0s_MmyvsWt4vNcpVO4huEH14m3TZsmuZt6dk80cqTP6eRIo3bSy8EuuM9EBh3WNuD0OCrTrBwB9np0Ymmn6c43431XuUaJ63T2zFHpaKqzWd7W_dy9X-mjbMPuCfGdxG5Z3wXwf8dAAD__30QSf0">