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

    <tr>
        <th>Summary</th>
        <td>
            [llvm] [maybe AMDGCN?] Adding range information to workitem ID causes missed optimization
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            backend:AMDGPU,
            llvm:optimizations,
            llvm
      </td>
    </tr>

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

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

<pre>
    Consider the following LLVM IR
```llvm
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7"
target triple = "amdgcn-amd-amdhsa"

@lds = external unnamed_addr addrspace(3) global [2048 x float]

define amdgpu_kernel void @fail(ptr addrspace(1) %store) local_unnamed_addr #0 !reqd_work_group_size !0 {
entry:
  %tmp = alloca float, i64 4, align 4, addrspace(5)
  %tid = tail call i32 @llvm.amdgcn.workitem.id.x(), !range !1
  %wave = udiv i32 %tid, 64
  %waveHalf = urem i32 %wave, 2
  %waveHalfScale = mul i32 %waveHalf, 64
  %base = add i32 %waveHalfScale, 1024
  %lane = urem i32 %tid, 64

  br label %loadLoopHead
loadLoopHead:
  %loadIdx = phi i32 [ %loadIdxInc, %loadLoop ], [ 0, %entry ]
  %loadBound = icmp slt i32 %loadIdx, 4
  br i1 %loadBound, label %loadLoop, label %addLoopHead
loadLoop:
  %ldsOffset = mul i32 %loadIdx, 128
 %ldsTmp1 = add i32 %ldsOffset, %lane
  %ldsAddr = add i32 %ldsTmp1, %base

  %loadPtr = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr
  %loadVal = load float, ptr addrspace(3) %loadPtr, align 4
 %tmpStorePtr = getelementptr float, ptr addrspace(5) %tmp, i32 %loadIdx
 store float %loadVal, ptr addrspace(5) %tmpStorePtr, align 4
  %loadIdxInc = add i32 %loadIdx, 1
  br label %loadLoopHead

addLoopHead:
 %val = phi float [ %valNext, %addLoop ], [ 0.0, %loadLoopHead ]
  %addIdx = phi i32 [ %addIdxInc, %addLoop ], [ 0, %loadLoopHead ]
  %addBound = icmp slt i32 %addIdx, 4
  br i1 %addBound, label %addLoop, label %exit
addLoop:
  %tmpLoadPtr = getelementptr float, ptr addrspace(5) %tmp, i32 %addIdx
  %tmpLoadVal = load float, ptr addrspace(5) %tmpLoadPtr
  %valNext = fadd float %val, %tmpLoadVal
  %addIdxInc = add i32 %addIdx, 1
  br label %addLoopHead

exit:
  store float %val, ptr addrspace(1) %store

  ret void
}

define amdgpu_kernel void @pass(ptr addrspace(1) %store) local_unnamed_addr #0 !reqd_work_group_size !0 {
entry:
  %tmp = alloca float, i64 4, align 4, addrspace(5)
  %tid = tail call i32 @llvm.amdgcn.workitem.id.x();;; ONLY CHANGE , !range !1
  %wave = udiv i32 %tid, 64
  %waveHalf = urem i32 %wave, 2
  %waveHalfScale = mul i32 %waveHalf, 64
  %base = add i32 %waveHalfScale, 1024
  %lane = urem i32 %tid, 64

  br label %loadLoopHead
loadLoopHead:
  %loadIdx = phi i32 [ %loadIdxInc, %loadLoop ], [ 0, %entry ]
  %loadBound = icmp slt i32 %loadIdx, 4
  br i1 %loadBound, label %loadLoop, label %addLoopHead
loadLoop:
 %ldsOffset = mul i32 %loadIdx, 128
  %ldsTmp1 = add i32 %ldsOffset, %lane
  %ldsAddr = add i32 %ldsTmp1, %base

  %loadPtr = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr
  %loadVal = load float, ptr addrspace(3) %loadPtr, align 4
  %tmpStorePtr = getelementptr float, ptr addrspace(5) %tmp, i32 %loadIdx
  store float %loadVal, ptr addrspace(5) %tmpStorePtr, align 4
  %loadIdxInc = add i32 %loadIdx, 1
 br label %loadLoopHead

addLoopHead:
  %val = phi float [ %valNext, %addLoop ], [ 0.0, %loadLoopHead ]
  %addIdx = phi i32 [ %addIdxInc, %addLoop ], [ 0, %loadLoopHead ]
  %addBound = icmp slt i32 %addIdx, 4
 br i1 %addBound, label %addLoop, label %exit
addLoop:
  %tmpLoadPtr = getelementptr float, ptr addrspace(5) %tmp, i32 %addIdx
  %tmpLoadVal = load float, ptr addrspace(5) %tmpLoadPtr
  %valNext = fadd float %val, %tmpLoadVal
  %addIdxInc = add i32 %addIdx, 1
  br label %addLoopHead

exit:
  store float %val, ptr addrspace(1) %store

  ret void
}

; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn
declare i32 @llvm.amdgcn.workitem.id.x() #1

attributes #0 = { "amdgpu-flat-work-group-size"="256,256" "amdgpu-implicitarg-num-bytes"="56" }

attributes #1 = { mustprogress nofree nosync nounwind readnone speculatable willreturn }

!0 = !{i32 256, i32 1, i32 1}
!1 = !{i32 0, i32 256}
```

Note that the only difference between `@fail` and `@pass` is that, in `@pass`, the workitem intrinsic is not annotated with `!range` information.

When compiled through  `./bin/opt -passes='default<O3>,strip' ~/input.ll -S | ./bin/llc -O3 -o - -mcpu=gfx908` on a recent commit to the main branch, the assembly output is as follows
```asm
fail:                                   ; @fail
; %bb.0:
        v_and_b32_e32 v1, 0x7f, v0
        v_lshlrev_b32_e32 v1, 2, v1
        v_lshlrev_b32_e32 v0, 2, v0
        ds_read2st64_b32 v[1:2], v1 offset0:16 offset1:20
        v_or_b32_e32 v3, 0x1200, v0
 ds_read_b32 v3, v3
        v_or_b32_e32 v0, 0x1600, v0
 ds_read_b32 v0, v0
        s_load_dwordx2 s[0:1], s[4:5], 0x0
 s_waitcnt lgkmcnt(0)
        v_add_f32_e32 v1, 0, v1
 v_add_f32_e32 v1, v1, v3
        v_add_f32_e32 v1, v1, v2
 v_mov_b32_e32 v4, 0
        v_add_f32_e32 v0, v1, v0
 global_store_dword v4, v0, s[0:1]
        s_endpgm
pass: ; @pass
; %bb.0:
        v_and_b32_e32 v0, 0x7f, v0
        v_lshlrev_b32_e32 v2, 2, v0
        ds_read2st64_b32 v[0:1], v2 offset0:16 offset1:18
        ds_read2st64_b32 v[2:3], v2 offset0:20 offset1:22
        s_load_dwordx2 s[0:1], s[4:5], 0x0
 v_mov_b32_e32 v4, 0
        s_waitcnt lgkmcnt(0)
        v_add_f32_e32 v0, 0, v0
        v_add_f32_e32 v0, v0, v1
        v_add_f32_e32 v0, v0, v2
        v_add_f32_e32 v0, v0, v3
        global_store_dword v4, v0, s[0:1]
        s_endpgm
```

Note that `pass` uses two `ds_read2st64_b32` instructions, while `fail` only uses one

A suspicious difference between the two functions occurs in the `InstCombine` that comes after loop unrolling, where `@fail` has
```llvm
  %ldsTmp1 = and i32 %tid, 127
  %base = or i32 %ldsTmp1, 1024
  %loadPtr = getelementptr float, ptr addrspace(3) @lds, i32 %base
  %loadVal = load float, ptr addrspace(3) %loadPtr, align 4
  %ldsAddr.1 = or i32 %tid, 1152
  %loadPtr.1 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.1
  %loadVal.1 = load float, ptr addrspace(3) %loadPtr.1, align 4
  %ldsAddr.2 = or i32 %ldsTmp1, 1280
  %loadPtr.2 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.2
  %loadVal.2 = load float, ptr addrspace(3) %loadPtr.2, align 4
  %ldsAddr.3 = or i32 %tid, 1408
 %loadPtr.3 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.3
 %loadVal.3 = load float, ptr addrspace(3) %loadPtr.3, align 4
```

but `@pass` has
```llvm
  %ldsTmp1 = and i32 %tid, 127
  %base = or i32 %ldsTmp1, 1024
  %loadPtr = getelementptr float, ptr addrspace(3) @lds, i32 %base
  %loadVal = load float, ptr addrspace(3) %loadPtr, align 4
  %ldsAddr.1 = or i32 %ldsTmp1, 1152
  %loadPtr.1 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.1
  %loadVal.1 = load float, ptr addrspace(3) %loadPtr.1, align 4
  %ldsAddr.2 = or i32 %ldsTmp1, 1280
  %loadPtr.2 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.2
  %loadVal.2 = load float, ptr addrspace(3) %loadPtr.2, align 4
  %ldsAddr.3 = or i32 %ldsTmp1, 1408
  %loadPtr.3 = getelementptr float, ptr addrspace(3) @lds, i32 %ldsAddr.3
  %loadVal.3 = load float, ptr addrspace(3) %loadPtr.3, align 4
```

Note that `@pass` always uses `%ldsTmp1` in its address calculations, while `@fail` *alternates* between `%ldsTmp1` and `%tid`

Over in `separate-const-offset-from-gep`, `@fail` has
```llvm
  %2 = tail call i32 @llvm.amdgcn.workitem.id.x(), !range !1
  %3 = and i32 %2, 127
  %4 = getelementptr float, ptr addrspace(3) @lds, i32 %3
  %5 = getelementptr float, ptr addrspace(3) %4, i32 1024
  %6 = load float, ptr addrspace(3) %5, align 4
  %7 = or i32 %2, 1152
  %8 = getelementptr float, ptr addrspace(3) @lds, i32 %7
  %9 = load float, ptr addrspace(3) %8, align 4
  %10 = getelementptr float, ptr addrspace(3) @lds, i32 %3
  %11 = getelementptr float, ptr addrspace(3) %10, i32 1280
  %12 = load float, ptr addrspace(3) %11, align 4
  %13 = or i32 %2, 1408
  %14 = getelementptr` float, ptr addrspace(3) @lds, i32 %13
  %15 = load float, ptr addrspace(3) %14, align 4
```
which is rather suspicious because some of those `or`'s really should be `gep`s with an offset.

On the other hand, `@pass` has
```llvm
  %2 = tail call i32 @llvm.amdgcn.workitem.id.x()
  %3 = and i32 %2, 127
  %4 = getelementptr float, ptr addrspace(3) @lds, i32 %3
  %5 = getelementptr float, ptr addrspace(3) %4, i32 1024
  %6 = load float, ptr addrspace(3) %5, align 4
  %7 = getelementptr float, ptr addrspace(3) @lds, i32 %3
 %8 = getelementptr float, ptr addrspace(3) %7, i32 1152
  %9 = load float, ptr addrspace(3) %8, align 4
  %10 = getelementptr float, ptr addrspace(3) @lds, i32 %3
  %11 = getelementptr float, ptr addrspace(3) %10, i32 1280
  %12 = load float, ptr addrspace(3) %11, align 4
  %13 = getelementptr float, ptr addrspace(3) @lds, i32 %3
  %14 = getelementptr float, ptr addrspace(3) %13, i32 1408
  %15 = load float, ptr addrspace(3) %14, align 4
```
which indicates the pass is working correctly in that example.

I *suspect* that the failure of `separate-const-offset-from-gep` is causing the eventual misoptimization. Perhaps there's something weird with known bits?
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsW19z27gR_zTwC4YaEiD158EPsnW-y0wuuWna6_RJA5KQhAYEWACkrDz0s3cWJCWSkmPL57TTOXscWiR2F_v3hwWoMGvFVnF-i5I7lKxuWOV22tx-Nd8O9lsY3qQ6P9zea2VFzg12O443Wkq9F2qLP378_Vf84S8oXKFwiaZh8ytlXTSPHDNb7nDOHJPsoCuHEV1hRAgPSkSX09hfgjLq3xBEl7S5BCXt38R9sqQ_Mu3diI6kjuBxNA1qEjdDdUdTx_OWZuFpyDyoowUMkgTok2n3MYngaRKRoI5CLwf-BDUJvQj4EygvdhoHXygJlkmgBKLLGSJk4AVnRCl55wFW5NtMBazI4d_OsiN5e41DmVtPzR8dN4pJXCnFCp6vWZ4bDBdbsowjMqeILPBW6pRJjJI7UAo_4o3UzKFk1Reb841QHMPsZbX-yo3iEtda5BjF4YYJici8dEPpEUhHJLFOGw6fpc6YXA-0QYSGGJHI8H_l6702X9dbo6tybcU3Ds9DjGZ3jQpcOXNAtFUIg2RXlN5SJkF0qzi5x2Ia4xg-MCm2qv3Y0yxBZNEXA2bQFXZMSJwxKbGgBAyDjJw0Hp-AcsLxYiLyySMicxBB7r3uTG29slFP5p7VTcyqXNSNPD8R8EzjEeEvTG4aYsOLjhgGgJpcIP6SsTYlikr2GWDwbIqU2YaY5fmY2EsCDp-lJx7JFD9TaaR_R54aLFnKpefTLP-odfkLZ3kzPngyCB-MfMgf_TTlTjSzJHe9oQ8qa5x8lIshMeFRcofDdsxnBj5m7FH2na5UE1mRFSW20nWGtOKBP-5ZIaIBKwyfGTZ4yPInjB0ZmtvPm43lbhyynh4RmbccDcNfizIaB-0op3MKU3w4zdIX1RkXCGt5IBmG4Wv1-M01nFvuuOQFVw4K-lhT4-r22NGgjS-541ygwkj074AvdIXh83MSj8r06_foGFeUXwBOrlQ2aUW7ouwr23q_ke5hqhHR0_sZaZ0y58oOs_gsJr3Av6yMmms_4Y4phkhStx6GMmpNaAqpZvITf-wSpmUfFNEkHJUYCB9VE8ufKtRm5FSnl2Z4kfyni7WZ4nKtdoyXqnLwjD8KN3Dh2Ury8foauJxWrb5nwl9WBT2ZrUY9SW00vZgNpNMxXesmVQeznQXwQiKenHsxD88Arl2LwZsnB45Kp75cNsN-YABBhjvfTbRPZy_vPUpm7Z-y96B3zS_-_OnjP_D9L8tPP_-E3zuS947k2Y7k6obkvSN5qiP5wS3J_7wneXVL8ufrSd5bkj9RSwLr7kOlMie0wkvnjEV0iYvKutLoreHWYqU3hnOstD2oDCtdqb1QOTac5Uorjm3Js0oyx1LJ8V5IabirjOpankwyw1_YC0AnEw1K0jkj0spx2zY5dAW9THd-VFbBRjIXgKjA9zwB9DyIEERXiBCSTBG591fS4xFFKUUmHDPbQFVFkB4ct0emlnrop6Ei0VGRt_DUeK6mY_OnZBGa3YHrGkO8F6PThyMbiaIRQ9hRAeeRrjug7M_2STuO3Y45f7SplTzgXGw23HCVcZxyt-dcYWBqz8emIWYAJv6J71qnIRbWy_CzquEYPAPRXbyxUM4IZUUGXEo7zJTSjjme471wO8_dtn5etNpoUzDI0Elf8b_vuMKZLkoheY7dzuhqu8PAPUHkIRUKkQddOhyAHtz64M5yvmGVdIjef6aI_oTIvXVGlIjM8L8ReRCqrNxEShx8wWh2j0-SpMxw8JniQOMAB0VWVoiutpvHRTgHJbXCDBueceVAp0I47LQ3u2BC4dQwle06T4A-RSoPWFeurBy4gdn2VNmOQsVse5TsfU-X-PkfqOkuWMcih_YknYQ9YGl-6jVT-TqlZM0pwbXPrvBx5jvdOhzTSruThtcjeuKJo2eJwxPxSHJu11AlxLppDPS4RsldhOiStEtdHWHt27PQn2i3N57iTEltTlPSxp6IhOFg3nbCZi5PVNPvyQlbOdPvyQkvmWbXsCat8702-SPBFiV33obWMLiPEV0m7X342PHb9Z4JlymH5fZrkSmHyDzs7bmO8cvz9WYYv0E8LlG01zOTn6QkR2GF7kU0bqb7npSwJ6WjbE7q136xajzTimqoBz4aOZOrvNy2JeEBhi67hPe31yZ8eGXCk-tyuB_qmjyVw9H8BaL8m5tLokjYLwfyRun3gki_KkPDU4a-JHHCy9jyJCV5MeUo-d8oJ59ZY9H0uGRWllvs9hqejQPerHvWmcp3Zn4buN8JyYG4W4X9Wu2laDXo-ZbYVrYUmdCVvbSYwxoEE2_axs9inWWVsbB0wxiahh-Udfe6SIXya7DXPdMFt5htHDdYwjakUkZLKdS2UY8bPuoTdmy8nJ1ejZ5vxlU-OgyJyOzSUYs2F7bf4zOWt9p1n_b0P2LL3e7pJ9HIsM4BUULOjWqp3-IwYRKd29aKv8q6SfR9-8h3AgeYcW4jeTsbxy4EG8krbCTft5E-EcM47L8Pa2XRtzOPDqWDdfQV1tEz6y5CWVq5Uev_XuSvLPK-Ye-F_v9b6H0bT8X-g6v9v1Tug86lV_RM7tnBNt2H368fveA7Fyyc9dNza3HGpD_2OGtkep0CIksm_bd8_FHMcnDwMBDenT00ADLU9nPNTXv-YHnJDHM8yLSyLmga5GBjdBFsedkeS1zZrZA3_3INHYMiOYfE-I8nTz9pkuvFkSQ-HjoNEXh6ReYll6tqNqomcgEP53_cBX2PLq7Qen5Z6_aE7s2iEr0C6kGLY1yG4BpdA3vRE5gejYGOXIC46EJ6QjFd6Yto4IzkGu3j55BsvxPZDguLDXM7bvqbo5RnrLIcW11wrDfY7bT10KSNh4iZxYYzKQ_Y7nQlc5z60QZBbHNcyVS7_R6cTn5utlLaz7hjzVuUKxunV-LNO7ycwcubmPc6IALo6awboto7DF0DQ29n4ysy3gNUZ-MIAH8IWKlcZNAKeRABwAD88sWutjjTxvDMyUNzYMMc5o-sKCUfINAHaKoA63jmoKM6vuOBfqcyHu9e0ijBzICSMDOw85orVzGJC2F16UQhvjUvZ_Bv3OxY6XU23IMn4KrbAeeeC9O-3_mq9F7hVDiL6MNNfkvzBV2wG34bTWdhTBezMLrZ3aZplDOeh_F0FiYkm6fxIouimLKIUsrmsxtxS0JCIhLOokUYxdEkjKZRuOGUb8IZ5dMYxSEvmJATD5jabG-EtRW_TRZ0trjxr2Gt_9I_ISnLvnKVI7pc_rr6-be_IQJIiQjxiEyXfTvtcJAQlKxuzC3cBGm1tZB8wjp7mtYJJ_1_L_AMyQqj5K5gh5RjmO3-E6IP8HSZ5-CpplHsvfXCTp9enn1Y-WBwC-63PMd91W4qI293zpUW0SUiD4g8bIXbVekk04V_iVV3f4LS6H_6zHjwXrGIPHjH_CcAAP__8-URAQ">