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

    <tr>
        <th>Summary</th>
        <td>
            [RISC] Unprofitable zext icmp combine on vectors
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            backend:RISC-V
      </td>
    </tr>

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

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

<pre>
    InstCombine will combine this zext of an icmp where the source has a single bit set to a lshr plus trunc:

```llvm
define <vscale x 1 x i8> @f(<vscale x 1 x i64> %x) {
  %1 = and <vscale x 1 x i64> %x, splat (i64 8)
  %2 = icmp ne <vscale x 1 x i64> %1, splat (i64 0)
  %3 = zext <vscale x 1 x i1> %2 to <vscale x 1 x i8>
  ret <vscale x 1 x i8> %3
}
```

```llvm
define <vscale x 1 x i8> @f(<vscale x 1 x i64> %x) #0 {
  %1 = and <vscale x 1 x i64> %x, splat (i64 8)
  %.lobit = lshr exact <vscale x 1 x i64> %1, splat (i64 3)
  %2 = trunc nuw nsw <vscale x 1 x i64> %.lobit to <vscale x 1 x i8>
  ret <vscale x 1 x i8> %2
}
```

In a loop, this ends up being unprofitable for RISC-V because the codegen now goes from:

```asm
f: # @f
        .cfi_startproc
# %bb.0:
        vsetvli a0, zero, e64, m1, ta, ma
        vand.vi v8, v8, 8
        vmsne.vi        v0, v8, 0
        vsetvli zero, zero, e8, mf8, ta, ma
        vmv.v.i v8, 0
        vmerge.vim      v8, v8, 1, v0
        ret
```

To a series of narrowing vnsrl.wis:

```asm
f:                                      # @f
        .cfi_startproc
# %bb.0:
        vsetvli a0, zero, e64, m1, ta, ma
        vand.vi v8, v8, 8
        vsetvli zero, zero, e32, mf2, ta, ma
        vnsrl.wi        v8, v8, 3
        vsetvli zero, zero, e16, mf4, ta, ma
        vnsrl.wi        v8, v8, 0
        vsetvli zero, zero, e8, mf8, ta, ma
        vnsrl.wi        v8, v8, 0
        ret
```

In the original form, the vmv.v.i is loop invariant and is hoisted out, and the vmerge.vim usually gets folded away into a masked instruction, so you usually just end up with a vsetvli + vmsne.vi.

The truncate requires multiple instructions and introduces a vtype toggle for each one, and is measurably slower on the BPI-F3.

I think we have enough information to reverse the combine somewhere.

I noticed this while working on #132180 when trying to widen AnyOf reductions.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMVl1vqzgT_jXOzajIGJLCRS7S9o2Uq3e1X7crAwP41NisP6A5v35lQ9qqyeke7Ye0FSqBYZ6xn5l5PNxa0SnEPdk-kO3ThnvXa7OX_hlleb-pdHPen5R1j3qohEKYhZRQrw-uFxa-4osD3QJXIOphhLlHE0wIVntTI_TcAgcrVCcRKuHAogOngYO0vYFRegvOeFWT7EBovHZ0uaScBkIPDbYhHMkeJ1tzifACKbyAKEj2PyA5bQkrroy7PFrZ9oWwEsj9A6EHCM8pkOwJuGquAd_7PIIdJXdAWCF2ORSElRcEFhHibm8t6xUlvUKh71CyiBLpu4JIVwQWiLq574hi8IZvsfpmgcn7p_d8_nv0soz-sxwnUodaCTCxTPCF1zc2-wnX2VXGYpWB8jMoO3-Ctcb-69Szb1F_UqHstR7DamP7oGos-BEqFKoDr0ajW-F4JRFabeDH00-Pd79ChTX3dmmrWjfYoQKlZ-g0WmiNHq57h9uQ25Zkh5CdJY_hizKpW_Gbddy40eg6vAtmtq2qhF5gysmim6QgtOQ0rPUrGh3uuMvDbYh0Ox5_89WFqyaZgstUhPfL_2I1DlbhaqVvVvox2iXOa7z42dAWN-INUzIlb_EuWAOaLoQaPqwkLnlavzLorrPzcxAli0agDYqmuDF6DmmZlDUymYX9lObv-vsv5OLbbGdsoZvdgFw5-ICZ_Slmulsw8-_G_FtV8SnkzbSfVOwrbUQnFJeh74alPxHWIgNhY9uCUBM3gisXxU1Y6LWwDhvQ3gWf8Hbxu1QheOu5lGfo0FlotWywAT7zMwgVT8GB22dsQCjrjK-d0CpKmYaz9q_OX7x1QSuCVMzC9cBhpQcIe4BLeyVrIfe4iB13CAZ_98KghcFLJ0aJ70PZZR_KGd34GsNJPbnziOB0160ahLzuQSu87E9YGJBbb3glz2ClntGAXkh8-OF0d8zWZZyCxKlnmMMQMCGg0r7rQajAMA_hg8YanNC8atsyWVg9YBwkXpGUdqLGZhHNuRcSYdbmOXSnVqGr0oylBQ3jhwJnzsHgNMyiQQUHdf5_CwabddPJptlnTZmVfIP79D5nebHL83LT77c8b9N6h_e7nFdY7qpmWxVlxpqmwapIi43YM8q2NGM03VGa5UmGJa14TrdlRemuRJJTHLiQSThdE226jbDW4z7NGMu3G8krlDaOW4xVvH5G1ZDssOg8YSwMYWYffO8q31mSUymss29oTjgZx7XgQrZP8Mv7MyOOE3EyuVCpFUxYO23sxhu5750bo4yxI2HHTrjeV0mtB8KOcRxYbnej0V-wdoQd4-otYcd1A9Oe_REAAP__zdAHTA">