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

    <tr>
        <th>Summary</th>
        <td>
            32x32->64 unsigned multiplication vectorization unnecessarily needs SSE4.2
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    I was looking at the following piece of Rust code:

```rust
pub fn mult(xy: [u64; 2]) -> [u64; 2] {
    let [x, y] = xy;
    let m0 = (x as u32) as u64 * (x >> 32 as u32) as u64;
 let m1 = (y as u32) as u64 * (y >> 32 as u32) as u64;
    [m0, m1]
}
```

With `sse4.2` set as target feature it optimizes nicely:

```asm
example::mult:
        mov     rax, rdi
 movdqu  xmm0, xmmword ptr [rsi]
        movdqa  xmm1, xmm0
 psrlq   xmm1, 32
        pmuludq xmm1, xmm0
        movdqu  xmmword ptr [rdi], xmm1
        ret
```

Without the SSE4.2 feature flag the output is not vectorized. But unless I'm mistaken, none of the above instructions require SSE4.2! `pmuludq xmm xmm` is in SSE2, as is `psrlq xmm, imm`.

Rust generates the following IR:

```llvm
; ModuleID = 'test.eb59d332-cgu.0'
source_filename = "test.eb59d332-cgu.0"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; test::mult
; Function Attrs: nonlazybind uwtable
define void @_ZN4test4mult17h051a3e752fc0d19eE(ptr noalias nocapture noundef sret([2 x i64]) dereferenceable(16) %0, ptr noalias nocapture noundef readonly dereferenceable(16) %xy) unnamed_addr #0 {
start:
  %1 = getelementptr inbounds [2 x i64], ptr %xy, i64 0, i64 0
  %x = load i64, ptr %1, align 8, !noundef !2
  %2 = getelementptr inbounds [2 x i64], ptr %xy, i64 0, i64 1
  %y = load i64, ptr %2, align 8, !noundef !2
  %_6 = trunc i64 %x to i32
  %_5 = zext i32 %_6 to i64
  %_7 = lshr i64 %x, 32
  %m0 = mul i64 %_5, %_7
  %_11 = trunc i64 %y to i32
  %_10 = zext i32 %_11 to i64
  %_12 = lshr i64 %y, 32
  %m1 = mul i64 %_10, %_12
  %3 = getelementptr inbounds [2 x i64], ptr %0, i64 0, i64 0
  store i64 %m0, ptr %3, align 8
  %4 = getelementptr inbounds [2 x i64], ptr %0, i64 0, i64 1
  store i64 %m1, ptr %4, align 8
  ret void
}

attributes #0 = { nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" "target-features"="+sse4.2" }

!llvm.module.flags = !{!0, !1}

!0 = !{i32 7, !"PIC Level", i32 2}
!1 = !{i32 2, !"RtLibUseGOT", i32 1}
!2 = !{}
```

With `opt -S -O3` we see that it optimizes nicely:

```llvm
start:
  %1 = load <2 x i64>, ptr %xy, align 8
  %2 = and <2 x i64> %1, <i64 4294967295, i64 4294967295>
  %3 = lshr <2 x i64> %1, <i64 32, i64 32>
  %4 = mul nuw <2 x i64> %2, %3
  store <2 x i64> %4, ptr %0, align 8
  ret void
```

But if we edit the above IR input and remove `+sse4.2` from `target-features`, we get the following

```llvm
start:
  %x = load i64, ptr %xy, align 8, !noundef !2
  %1 = getelementptr inbounds [2 x i64], ptr %xy, i64 0, i64 1
  %y = load i64, ptr %1, align 8, !noundef !2
  %_5 = and i64 %x, 4294967295
  %_7 = lshr i64 %x, 32
  %m0 = mul nuw i64 %_5, %_7
  %_10 = and i64 %y, 4294967295
  %_12 = lshr i64 %y, 32
  %m1 = mul nuw i64 %_10, %_12
  store i64 %m0, ptr %0, align 8
  %2 = getelementptr inbounds [2 x i64], ptr %0, i64 0, i64 1
  store i64 %m1, ptr %2, align 8
  ret void
  ```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWNuO27wRfhr6ZmBDJCXZvvDFHosF_jZF0qJAbwxaGnvZSJSWh107T18MJdvyYTebIEHWpsmZjx85R0k5pzcGccGyW5bdj1Twz41dNLZqR6um3C2e4E05qJrmuzYbUB78M8K6qarmjSZajQVCs4avwXkomhKZvGHJPUv2n3nS_bfB-W6qDStYG6hD5ZmYbXdM3gDLbkOeMnkLgmX3TMxhzOTD2TSw6W0HAQBQoaf1LRN3sIur8h4I7UymTuIKbQXKQZCC4GmUp8DETbfC5ANtKMWFzBEwovE92u5dtN2n0ACIfp0Q_5rTqbsLm96f3dzwOv-j_TOwPHEO04lgeQIOPUF7ZTfoYY3KB4ugPTSt17X-gQ6MLrDavWcY5epuBreqbqtoQHkTrbPXgP5f3bzGb6virdtS9-t181q-BIBt3Z1nW9dvjS2h9ZYOaZ0-nG-AVb6oqMJ7lf6k0DpbvcBxSYpT1bYOVShfrqkOwTs-JzzKyKNT4acqFv1P7r0Jnfd_-_aQTsThqteV2sT5Jvg2eNAOTOPhFQvfWP0DywncBg_BVOgcPDExraHWzqvvaIiKaUyMIIJQq-YVQRvnbSi8bowDiy9B2_2uTHAy_-AG6I_8QDvQhqQEgSpHEyQZ75JkxB3oKDoZHizG7QYNWuXRnUX309f3nKaqXnuvoeD8e1OGCp_u-9CYenR-gqtsXkopxsUmTBImpp28a4ItcLnWFRpVY68irqr0du99u1ReVWpHZuiVcFwzeYPjVkwTJm-kiB_0k5_-pBHF3k2ejvV-sJ6REhezsZnRIN_r5On4Gxez8_291W11ILyd5cs8HQfz3TRvZlxpE7bjjQkHreP10NkGUXWYfwwmGhluvLeO0qBpTKV-7FbalBDevFpV2ImXuNYG4bXRJbA0Wf73HymhpgTIp89JxpXEaSbWRVLyOT4wMSOfN42qtCKHLFQbvdU0wZS4Bkf-LmYsuxWwBbqTLu2WaHGNFk2BcXcx4znNM5HFyP4Y1aIqG1PtPoLZ7mgQDFm_XKqytMCETI7J3Xllh7mHiaxLuhv0WGGNxhMLbVa0q4OzM3Qc-43uaBqS4-CIuY2YVaPKqHrUizlFVXpjYEZDJvj-fExwMYAQf4gWH2Du3qMlPk1rmUcMb4MpIn48rW9AyxOxLIr9wK2nlV6TxPJ0KDbtGLlnewA7zcpMZH2RrUO1l1lmHclsOR2CcX7JbXeFG08uyXF-hR0XF_R2l_T4BT2e7Pmd3J38HZMm7zua8w2V427TOhkoyaE9jwTSP0OAXyfAB0rpFQIWfUwy571I_FTeW70KVCe6iJWxJbuWtShDtrZZ4dh5VXynpCjvmRDLJfWBy7i0X4npP6bYcdGGg-h2lo8pAIbrfc11ByEmbvtWiORO6TLBqUxN6lidJlSnXZ-9OSUbsXcBzi81k4Ek-d-0F2VC_PPpDv7CV6zi_nfRPcURQXB-piuOul_9X3r1b4d_-_KvgTYfaoshx081g03rYfwNxl8kNQJvCA4R_LPyv9IGHiv6u_k3JiUm7_YuKB8u0tqlP3fHUeZM85Bombwj50zFPJ3nUzHP9h48mJEPFxEa4_1DRCn2SFTUHy5CjJKBCW-XIL25MnkaQhdy6XkAfhxL1yxIjaFek8mw1H7QAj59BW2om6SLs1jTHOke3D1PYG2bmibPYyOPZN4QYtMybOh-3fDvFslTc39Yjv5U8f5Ulfx88e7LH13wsKwN3O73ayD51U_qYHK---793X-1xg23v1bn3i9K1_z4dxud3ypK4qeBBHBw3VG5kOVcztUIFzyfZSJJshkfPS-mfDrHdJrIfK4yVaSyUGqO89l0pjKcSRzphUiETDIx5RnPBZ9MsZzztUKR54Wac8XSBGulq0ksIY3djLRzARe5mOfzUaVWWLn40kQIg28QFymjZ_cjuyCd8SpsHEuTSjvvjihe-woXUmylGDP5kKcQTHwFU8YXIrqtdKHiQ8H-AbL7FYzBAp1TVlc7MIil6x8JR8FWi2fvW3qCYOKRiceN9s9hNSmamonHGN_d17i1zf-w8Ew8RsKOicd4oP8HAAD__62T6x8">