[llvm] [AMDGPU] Fix LowerDIVREM24 for the unsigned case (PR #196418)

Manuel Carrasco via llvm-commits llvm-commits at lists.llvm.org
Tue May 12 12:11:11 PDT 2026


https://github.com/mgcarrasco updated https://github.com/llvm/llvm-project/pull/196418

>From 3c2569b9a46cdce42af62f407075cdc84491dfbf Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Thu, 7 May 2026 15:24:00 -0500
Subject: [PATCH 1/3] [AMDGPU] Fix LowerDIVREM24 lowering for the unsigned case

The code was not properly checking that the operands were
24-bit integers for the unsigned case.
---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp |  20 ++-
 .../CodeGen/AMDGPU/udiv-miscompilation.ll     |  34 ++++
 llvm/test/CodeGen/AMDGPU/udiv.ll              |  41 +++--
 llvm/test/CodeGen/AMDGPU/udivrem24.ll         | 148 +++++++++---------
 4 files changed, 137 insertions(+), 106 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index e05213b2aaf93..6c552b740e02d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -1995,23 +1995,31 @@ SDValue AMDGPUTargetLowering::SplitVectorStore(SDValue Op,
 
 // This is a shortcut for integer division because we have fast i32<->f32
 // conversions, and fast f32 reciprocal instructions. The fractional part of a
-// float is enough to accurately represent up to a 24-bit signed integer.
+// float is enough to accurately represent up to a 24-bit integer.
 SDValue AMDGPUTargetLowering::LowerDIVREM24(SDValue Op, SelectionDAG &DAG,
                                             bool Sign) const {
   SDLoc DL(Op);
   EVT VT = Op.getValueType();
+  assert(VT == MVT::i32 && "LowerDIVREM24 expects an i32");
+
   SDValue LHS = Op.getOperand(0);
   SDValue RHS = Op.getOperand(1);
   MVT IntVT = MVT::i32;
   MVT FltVT = MVT::f32;
 
   unsigned LHSSignBits = DAG.ComputeNumSignBits(LHS);
-  if (LHSSignBits < 9)
-    return SDValue();
-
   unsigned RHSSignBits = DAG.ComputeNumSignBits(RHS);
-  if (RHSSignBits < 9)
-    return SDValue();
+
+  if (Sign) {
+    if (LHSSignBits < 9 || RHSSignBits < 9)
+      return SDValue();
+  } else {
+    APInt MustBeZero = APInt::getHighBitsSet(32, 8);
+    if (!DAG.MaskedValueIsZero(LHS, MustBeZero) ||
+        !DAG.MaskedValueIsZero(RHS, MustBeZero)) {
+      return SDValue();
+    }
+  }
 
   unsigned BitSize = VT.getSizeInBits();
   unsigned SignBits = std::min(LHSSignBits, RHSSignBits);
diff --git a/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll b/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll
new file mode 100644
index 0000000000000..143755157b548
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -start-before=amdgpu-isel -mtriple=amdgcn--amdhsa -mcpu=gfx90a < %s | FileCheck %s
+
+; The precise IR that triggered the bug is optimized before
+; it reaches amdgpu-isel. Thus, the test starts directly from there.
+
+define i32 @baz(i32 noundef %arg) {
+; CHECK-LABEL: baz:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_cvt_f32_u32_e32 v1, v0
+; CHECK-NEXT:    v_sub_u32_e32 v2, 0, v0
+; CHECK-NEXT:    v_rcp_iflag_f32_e32 v1, v1
+; CHECK-NEXT:    v_mul_f32_e32 v1, 0x4f7ffffe, v1
+; CHECK-NEXT:    v_cvt_u32_f32_e32 v1, v1
+; CHECK-NEXT:    v_mul_lo_u32 v2, v2, v1
+; CHECK-NEXT:    v_mul_hi_u32 v2, v1, v2
+; CHECK-NEXT:    v_add_u32_e32 v1, v1, v2
+; CHECK-NEXT:    v_mul_hi_u32 v1, v1, -1
+; CHECK-NEXT:    v_mul_lo_u32 v2, v1, v0
+; CHECK-NEXT:    v_not_b32_e32 v2, v2
+; CHECK-NEXT:    v_add_u32_e32 v3, 1, v1
+; CHECK-NEXT:    v_sub_u32_e32 v4, v2, v0
+; CHECK-NEXT:    v_cmp_ge_u32_e32 vcc, v2, v0
+; CHECK-NEXT:    v_cndmask_b32_e32 v2, v2, v4, vcc
+; CHECK-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc
+; CHECK-NEXT:    v_add_u32_e32 v3, 1, v1
+; CHECK-NEXT:    v_cmp_ge_u32_e32 vcc, v2, v0
+; CHECK-NEXT:    v_cndmask_b32_e32 v0, v1, v3, vcc
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %div = udiv i32 -1, %arg
+  ret i32 %div
+}
diff --git a/llvm/test/CodeGen/AMDGPU/udiv.ll b/llvm/test/CodeGen/AMDGPU/udiv.ll
index dd2acb8de6f41..ec66b3a1e04a0 100644
--- a/llvm/test/CodeGen/AMDGPU/udiv.ll
+++ b/llvm/test/CodeGen/AMDGPU/udiv.ll
@@ -2031,7 +2031,7 @@ define amdgpu_kernel void @v_udiv_i24(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG:       ; %bb.0:
 ; EG-NEXT:    ALU 0, @14, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    TEX 3 @6
-; EG-NEXT:    ALU 23, @15, KC0[CB0:0-32], KC1[]
+; EG-NEXT:    ALU 20, @15, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1
 ; EG-NEXT:    CF_END
 ; EG-NEXT:    PAD
@@ -2045,28 +2045,25 @@ define amdgpu_kernel void @v_udiv_i24(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG-NEXT:    ALU clause starting at 15:
 ; EG-NEXT:     LSHL * T0.W, T1.X, literal.x,
 ; EG-NEXT:    16(2.242078e-44), 0(0.000000e+00)
-; EG-NEXT:     OR_INT * T0.W, T0.X, PV.W,
-; EG-NEXT:     SUB_INT T1.W, 0.0, PV.W,
-; EG-NEXT:     RECIP_UINT * T0.X, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Y, PV.W, PS,
-; EG-NEXT:     LSHL T1.W, T3.X, literal.x,
-; EG-NEXT:     MULHI * T0.Y, T0.X, PS,
+; EG-NEXT:     OR_INT T0.W, T0.X, PV.W,
+; EG-NEXT:     LSHL * T1.W, T3.X, literal.x,
 ; EG-NEXT:    16(2.242078e-44), 0(0.000000e+00)
-; EG-NEXT:     ADD_INT T2.W, T0.X, PS,
-; EG-NEXT:     OR_INT * T1.W, T2.X, PV.W,
-; EG-NEXT:     MULHI * T0.X, PS, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Y, PS, T0.W,
-; EG-NEXT:     SUB_INT * T1.W, T1.W, PS,
-; EG-NEXT:     ADD_INT T0.Z, T0.X, 1,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T3.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T1.W, PV.W, T1.W, PS,
-; EG-NEXT:     CNDE_INT * T2.W, PV.W, T0.X, PV.Z,
-; EG-NEXT:     ADD_INT T3.W, PS, 1,
-; EG-NEXT:     SETGE_UINT * T0.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T0.X, PS, T2.W, PV.W,
-; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.x,
-; EG-NEXT:    2(2.802597e-45), 0(0.000000e+00)
+; EG-NEXT:     UINT_TO_FLT * T0.X, PV.W,
+; EG-NEXT:     OR_INT T0.W, T2.X, T1.W,
+; EG-NEXT:     RECIP_IEEE * T0.Y, PS,
+; EG-NEXT:     UINT_TO_FLT * T0.Z, PV.W,
+; EG-NEXT:     MUL_IEEE * T0.W, PS, T0.Y,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     MULADD_IEEE T1.W, -PV.W, T0.X, T0.Z,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     SETGE * T1.W, |PV.W|, T0.X,
+; EG-NEXT:     CNDE T1.W, PV.W, 0.0, literal.x,
+; EG-NEXT:     FLT_TO_UINT * T0.X, T0.W,
+; EG-NEXT:    1(1.401298e-45), 0(0.000000e+00)
+; EG-NEXT:     ADD_INT * T0.W, PS, PV.W,
+; EG-NEXT:     AND_INT T0.X, PV.W, literal.x,
+; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.y,
+; EG-NEXT:    16777215(2.350989e-38), 2(2.802597e-45)
   %den_ptr = getelementptr i24, ptr addrspace(1) %in, i24 1
   %num = load i24, ptr addrspace(1) %in
   %den = load i24, ptr addrspace(1) %den_ptr
diff --git a/llvm/test/CodeGen/AMDGPU/udivrem24.ll b/llvm/test/CodeGen/AMDGPU/udivrem24.ll
index 935a9bf23c9cb..ff5ab89ffcf78 100644
--- a/llvm/test/CodeGen/AMDGPU/udivrem24.ll
+++ b/llvm/test/CodeGen/AMDGPU/udivrem24.ll
@@ -660,7 +660,7 @@ define amdgpu_kernel void @udiv24_i32(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG:       ; %bb.0:
 ; EG-NEXT:    ALU 0, @8, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    TEX 0 @6
-; EG-NEXT:    ALU 21, @9, KC0[CB0:0-32], KC1[]
+; EG-NEXT:    ALU 18, @9, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1
 ; EG-NEXT:    CF_END
 ; EG-NEXT:    PAD
@@ -671,26 +671,23 @@ define amdgpu_kernel void @udiv24_i32(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG-NEXT:    ALU clause starting at 9:
 ; EG-NEXT:     AND_INT * T0.W, T0.Y, literal.x,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     SUB_INT T1.W, 0.0, PV.W,
-; EG-NEXT:     RECIP_UINT * T0.Y, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Z, PV.W, PS,
-; EG-NEXT:     MULHI * T0.Z, T0.Y, PS,
-; EG-NEXT:     ADD_INT T1.W, T0.Y, PS,
-; EG-NEXT:     AND_INT * T2.W, T0.X, literal.x,
+; EG-NEXT:     UINT_TO_FLT * T0.Y, PV.W,
+; EG-NEXT:     AND_INT T0.W, T0.X, literal.x,
+; EG-NEXT:     RECIP_IEEE * T0.X, PS,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     MULHI * T0.X, PS, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Y, PS, T0.W,
-; EG-NEXT:     SUB_INT * T1.W, T2.W, PS,
-; EG-NEXT:     ADD_INT T0.Z, T0.X, 1,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T3.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T1.W, PV.W, T1.W, PS,
-; EG-NEXT:     CNDE_INT * T2.W, PV.W, T0.X, PV.Z,
-; EG-NEXT:     ADD_INT T3.W, PS, 1,
-; EG-NEXT:     SETGE_UINT * T0.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T0.X, PS, T2.W, PV.W,
-; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.x,
-; EG-NEXT:    2(2.802597e-45), 0(0.000000e+00)
+; EG-NEXT:     UINT_TO_FLT * T0.Z, PV.W,
+; EG-NEXT:     MUL_IEEE * T0.W, PS, T0.X,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     MULADD_IEEE T1.W, -PV.W, T0.Y, T0.Z,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     SETGE * T1.W, |PV.W|, T0.Y,
+; EG-NEXT:     CNDE T1.W, PV.W, 0.0, literal.x,
+; EG-NEXT:     FLT_TO_UINT * T0.X, T0.W,
+; EG-NEXT:    1(1.401298e-45), 0(0.000000e+00)
+; EG-NEXT:     ADD_INT * T0.W, PS, PV.W,
+; EG-NEXT:     AND_INT T0.X, PV.W, literal.x,
+; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.y,
+; EG-NEXT:    16777215(2.350989e-38), 2(2.802597e-45)
   %den_ptr = getelementptr i32, ptr addrspace(1) %in, i32 1
   %num = load i32, ptr addrspace(1) %in, align 4
   %den = load i32, ptr addrspace(1) %den_ptr, align 4
@@ -754,7 +751,7 @@ define amdgpu_kernel void @no_udiv24_u23_u24_i32(ptr addrspace(1) %out, ptr addr
 ; EG:       ; %bb.0:
 ; EG-NEXT:    ALU 0, @8, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    TEX 0 @6
-; EG-NEXT:    ALU 21, @9, KC0[CB0:0-32], KC1[]
+; EG-NEXT:    ALU 18, @9, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1
 ; EG-NEXT:    CF_END
 ; EG-NEXT:    PAD
@@ -765,26 +762,23 @@ define amdgpu_kernel void @no_udiv24_u23_u24_i32(ptr addrspace(1) %out, ptr addr
 ; EG-NEXT:    ALU clause starting at 9:
 ; EG-NEXT:     AND_INT * T0.W, T0.Y, literal.x,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     SUB_INT T1.W, 0.0, PV.W,
-; EG-NEXT:     RECIP_UINT * T0.Y, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Z, PV.W, PS,
-; EG-NEXT:     MULHI * T0.Z, T0.Y, PS,
-; EG-NEXT:     ADD_INT T1.W, T0.Y, PS,
-; EG-NEXT:     AND_INT * T2.W, T0.X, literal.x,
+; EG-NEXT:     UINT_TO_FLT * T0.Y, PV.W,
+; EG-NEXT:     AND_INT T0.W, T0.X, literal.x,
+; EG-NEXT:     RECIP_IEEE * T0.X, PS,
 ; EG-NEXT:    8388607(1.175494e-38), 0(0.000000e+00)
-; EG-NEXT:     MULHI * T0.X, PS, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Y, PS, T0.W,
-; EG-NEXT:     SUB_INT * T1.W, T2.W, PS,
-; EG-NEXT:     ADD_INT T0.Z, T0.X, 1,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T3.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T1.W, PV.W, T1.W, PS,
-; EG-NEXT:     CNDE_INT * T2.W, PV.W, T0.X, PV.Z,
-; EG-NEXT:     ADD_INT T3.W, PS, 1,
-; EG-NEXT:     SETGE_UINT * T0.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T0.X, PS, T2.W, PV.W,
-; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.x,
-; EG-NEXT:    2(2.802597e-45), 0(0.000000e+00)
+; EG-NEXT:     UINT_TO_FLT * T0.Z, PV.W,
+; EG-NEXT:     MUL_IEEE * T0.W, PS, T0.X,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     MULADD_IEEE T1.W, -PV.W, T0.Y, T0.Z,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     SETGE * T1.W, |PV.W|, T0.Y,
+; EG-NEXT:     CNDE T1.W, PV.W, 0.0, literal.x,
+; EG-NEXT:     FLT_TO_UINT * T0.X, T0.W,
+; EG-NEXT:    1(1.401298e-45), 0(0.000000e+00)
+; EG-NEXT:     ADD_INT * T0.W, PS, PV.W,
+; EG-NEXT:     AND_INT T0.X, PV.W, literal.x,
+; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.y,
+; EG-NEXT:    16777215(2.350989e-38), 2(2.802597e-45)
   %den_ptr = getelementptr i32, ptr addrspace(1) %in, i32 1
   %num = load i32, ptr addrspace(1) %in, align 4
   %den = load i32, ptr addrspace(1) %den_ptr, align 4
@@ -848,7 +842,7 @@ define amdgpu_kernel void @no_udiv24_u24_u23_i32(ptr addrspace(1) %out, ptr addr
 ; EG:       ; %bb.0:
 ; EG-NEXT:    ALU 0, @8, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    TEX 0 @6
-; EG-NEXT:    ALU 21, @9, KC0[CB0:0-32], KC1[]
+; EG-NEXT:    ALU 18, @9, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1
 ; EG-NEXT:    CF_END
 ; EG-NEXT:    PAD
@@ -859,26 +853,23 @@ define amdgpu_kernel void @no_udiv24_u24_u23_i32(ptr addrspace(1) %out, ptr addr
 ; EG-NEXT:    ALU clause starting at 9:
 ; EG-NEXT:     AND_INT * T0.W, T0.Y, literal.x,
 ; EG-NEXT:    8388607(1.175494e-38), 0(0.000000e+00)
-; EG-NEXT:     SUB_INT T1.W, 0.0, PV.W,
-; EG-NEXT:     RECIP_UINT * T0.Y, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Z, PV.W, PS,
-; EG-NEXT:     MULHI * T0.Z, T0.Y, PS,
-; EG-NEXT:     ADD_INT T1.W, T0.Y, PS,
-; EG-NEXT:     AND_INT * T2.W, T0.X, literal.x,
+; EG-NEXT:     UINT_TO_FLT * T0.Y, PV.W,
+; EG-NEXT:     AND_INT T0.W, T0.X, literal.x,
+; EG-NEXT:     RECIP_IEEE * T0.X, PS,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     MULHI * T0.X, PS, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Y, PS, T0.W,
-; EG-NEXT:     SUB_INT * T1.W, T2.W, PS,
-; EG-NEXT:     ADD_INT T0.Z, T0.X, 1,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T3.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T1.W, PV.W, T1.W, PS,
-; EG-NEXT:     CNDE_INT * T2.W, PV.W, T0.X, PV.Z,
-; EG-NEXT:     ADD_INT T3.W, PS, 1,
-; EG-NEXT:     SETGE_UINT * T0.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T0.X, PS, T2.W, PV.W,
-; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.x,
-; EG-NEXT:    2(2.802597e-45), 0(0.000000e+00)
+; EG-NEXT:     UINT_TO_FLT * T0.Z, PV.W,
+; EG-NEXT:     MUL_IEEE * T0.W, PS, T0.X,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     MULADD_IEEE T1.W, -PV.W, T0.Y, T0.Z,
+; EG-NEXT:     TRUNC * T0.W, PV.W,
+; EG-NEXT:     SETGE * T1.W, |PV.W|, T0.Y,
+; EG-NEXT:     CNDE T1.W, PV.W, 0.0, literal.x,
+; EG-NEXT:     FLT_TO_UINT * T0.X, T0.W,
+; EG-NEXT:    1(1.401298e-45), 0(0.000000e+00)
+; EG-NEXT:     ADD_INT * T0.W, PS, PV.W,
+; EG-NEXT:     AND_INT T0.X, PV.W, literal.x,
+; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.y,
+; EG-NEXT:    16777215(2.350989e-38), 2(2.802597e-45)
   %den_ptr = getelementptr i32, ptr addrspace(1) %in, i32 1
   %num = load i32, ptr addrspace(1) %in, align 4
   %den = load i32, ptr addrspace(1) %den_ptr, align 4
@@ -1521,7 +1512,7 @@ define amdgpu_kernel void @urem24_i32(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG:       ; %bb.0:
 ; EG-NEXT:    ALU 0, @8, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    TEX 0 @6
-; EG-NEXT:    ALU 19, @9, KC0[CB0:0-32], KC1[]
+; EG-NEXT:    ALU 20, @9, KC0[CB0:0-32], KC1[]
 ; EG-NEXT:    MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1
 ; EG-NEXT:    CF_END
 ; EG-NEXT:    PAD
@@ -1532,24 +1523,25 @@ define amdgpu_kernel void @urem24_i32(ptr addrspace(1) %out, ptr addrspace(1) %i
 ; EG-NEXT:    ALU clause starting at 9:
 ; EG-NEXT:     AND_INT * T0.W, T0.Y, literal.x,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     SUB_INT T1.W, 0.0, PV.W,
-; EG-NEXT:     RECIP_UINT * T0.Y, PV.W,
-; EG-NEXT:     MULLO_INT * T0.Z, PV.W, PS,
-; EG-NEXT:     MULHI * T0.Z, T0.Y, PS,
-; EG-NEXT:     ADD_INT T1.W, T0.Y, PS,
-; EG-NEXT:     AND_INT * T2.W, T0.X, literal.x,
+; EG-NEXT:     UINT_TO_FLT * T0.Z, PV.W,
+; EG-NEXT:     AND_INT T0.W, T0.X, literal.x,
+; EG-NEXT:     RECIP_IEEE * T1.X, PS,
 ; EG-NEXT:    16777215(2.350989e-38), 0(0.000000e+00)
-; EG-NEXT:     MULHI * T0.X, PS, PV.W,
-; EG-NEXT:     MULLO_INT * T0.X, PS, T0.W,
-; EG-NEXT:     SUB_INT * T1.W, T2.W, PS,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T3.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT * T1.W, PV.W, T1.W, PS,
-; EG-NEXT:     SETGE_UINT T2.W, PV.W, T0.W,
-; EG-NEXT:     SUB_INT * T0.W, PV.W, T0.W,
-; EG-NEXT:     CNDE_INT T0.X, PV.W, T1.W, PS,
-; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.x,
-; EG-NEXT:    2(2.802597e-45), 0(0.000000e+00)
+; EG-NEXT:     UINT_TO_FLT * T0.W, PV.W,
+; EG-NEXT:     MUL_IEEE * T1.W, PS, T1.X,
+; EG-NEXT:     TRUNC * T1.W, PV.W,
+; EG-NEXT:     MULADD_IEEE T0.W, -PV.W, T0.Z, T0.W,
+; EG-NEXT:     TRUNC * T1.W, PV.W,
+; EG-NEXT:     SETGE * T0.W, |PV.W|, T0.Z,
+; EG-NEXT:     CNDE T0.W, PV.W, 0.0, literal.x,
+; EG-NEXT:     FLT_TO_UINT * T0.Z, T1.W,
+; EG-NEXT:    1(1.401298e-45), 0(0.000000e+00)
+; EG-NEXT:     ADD_INT * T0.W, PS, PV.W,
+; EG-NEXT:     MULLO_INT * T0.Y, PV.W, T0.Y,
+; EG-NEXT:     SUB_INT * T0.W, T0.X, PS,
+; EG-NEXT:     AND_INT T0.X, PV.W, literal.x,
+; EG-NEXT:     LSHR * T1.X, KC0[2].Y, literal.y,
+; EG-NEXT:    16777215(2.350989e-38), 2(2.802597e-45)
   %den_ptr = getelementptr i32, ptr addrspace(1) %in, i32 1
   %num = load i32, ptr addrspace(1) %in, align 4
   %den = load i32, ptr addrspace(1) %den_ptr, align 4

>From 617fdfae5139e0d0d6daf05308ebbd3640e275bb Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 12 May 2026 11:17:19 -0500
Subject: [PATCH 2/3] [reviews] Improve test.

---
 .../CodeGen/AMDGPU/udiv-miscompilation.ll     | 72 ++++++++++++++++++-
 1 file changed, 70 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll b/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll
index 143755157b548..22bad65561c2c 100644
--- a/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll
+++ b/llvm/test/CodeGen/AMDGPU/udiv-miscompilation.ll
@@ -3,9 +3,12 @@
 
 ; The precise IR that triggered the bug is optimized before
 ; it reaches amdgpu-isel. Thus, the test starts directly from there.
+; The test ensures that LowerDIVREM24 is not applied when the operands
+; do not fit in 24-bit integers. The opt missed the checks for the unsigned case.
 
-define i32 @baz(i32 noundef %arg) {
-; CHECK-LABEL: baz:
+; This unsigned i32 case was mishandled (LowerDIVREM24 must bail out).
+define i32 @udiv_i32_no_divrem24(i32 noundef %arg) {
+; CHECK-LABEL: udiv_i32_no_divrem24:
 ; CHECK:       ; %bb.0: ; %entry
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; CHECK-NEXT:    v_cvt_f32_u32_e32 v1, v0
@@ -32,3 +35,68 @@ entry:
   %div = udiv i32 -1, %arg
   ret i32 %div
 }
+
+define i8 @udiv_i8_divrem24(i8 noundef %arg) {
+; CHECK-LABEL: udiv_i8_divrem24:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_cvt_f32_ubyte0_e32 v0, v0
+; CHECK-NEXT:    v_rcp_iflag_f32_e32 v1, v0
+; CHECK-NEXT:    v_trunc_f32_e32 v1, v1
+; CHECK-NEXT:    v_cvt_u32_f32_e32 v2, v1
+; CHECK-NEXT:    v_mad_f32 v1, -v1, v0, 1.0
+; CHECK-NEXT:    v_cmp_ge_f32_e64 s[4:5], |v1|, v0
+; CHECK-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s[4:5]
+; CHECK-NEXT:    v_add_u32_e32 v0, v2, v0
+; CHECK-NEXT:    v_and_b32_e32 v0, 0xff, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %div = udiv i8 1, %arg
+  ret i8 %div
+}
+
+define i32 @sdiv_i32_no_divrem24(i32 noundef %arg) {
+; CHECK-LABEL: sdiv_i32_no_divrem24:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_sub_u32_e32 v1, 0, v0
+; CHECK-NEXT:    v_max_i32_e32 v1, v1, v0
+; CHECK-NEXT:    v_sub_u32_e32 v2, 1, v1
+; CHECK-NEXT:    v_cmp_gt_u32_e32 vcc, 2, v1
+; CHECK-NEXT:    v_cndmask_b32_e32 v2, 1, v2, vcc
+; CHECK-NEXT:    v_cndmask_b32_e64 v3, 0, 1, vcc
+; CHECK-NEXT:    v_add_u32_e32 v4, 1, v3
+; CHECK-NEXT:    v_cmp_ge_u32_e32 vcc, v2, v1
+; CHECK-NEXT:    v_cndmask_b32_e32 v1, v3, v4, vcc
+; CHECK-NEXT:    v_ashrrev_i32_e32 v0, 31, v0
+; CHECK-NEXT:    v_xnor_b32_e32 v1, v0, v1
+; CHECK-NEXT:    v_not_b32_e32 v0, v0
+; CHECK-NEXT:    v_sub_u32_e32 v0, v1, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %div = sdiv i32 -1, %arg
+  ret i32 %div
+}
+
+define i8 @sdiv_i8_divrem24(i8 noundef %arg) {
+; CHECK-LABEL: sdiv_i8_divrem24:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_bfe_i32 v0, v0, 0, 8
+; CHECK-NEXT:    v_cvt_f32_i32_sdwa v1, sext(v0) dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_0
+; CHECK-NEXT:    v_mov_b32_e32 v3, 30
+; CHECK-NEXT:    v_ashrrev_i32_sdwa v0, v3, sext(v0) dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:WORD_0
+; CHECK-NEXT:    v_or_b32_e32 v0, 1, v0
+; CHECK-NEXT:    v_rcp_iflag_f32_e32 v2, v1
+; CHECK-NEXT:    v_trunc_f32_e32 v2, v2
+; CHECK-NEXT:    v_mad_f32 v3, -v2, v1, 1.0
+; CHECK-NEXT:    v_cvt_i32_f32_e32 v2, v2
+; CHECK-NEXT:    v_cmp_ge_f32_e64 vcc, |v3|, |v1|
+; CHECK-NEXT:    v_cndmask_b32_e32 v0, 0, v0, vcc
+; CHECK-NEXT:    v_add_u32_e32 v0, v2, v0
+; CHECK-NEXT:    v_bfe_i32 v0, v0, 0, 8
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %div = sdiv i8 1, %arg
+  ret i8 %div
+}

>From 4eb0cd6dc24764d2772a2e4ecbc1238c75c1591a Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 12 May 2026 14:10:34 -0500
Subject: [PATCH 3/3] [reviews] reduce overhead

---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 6c552b740e02d..64efd51c9433c 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -2007,18 +2007,20 @@ SDValue AMDGPUTargetLowering::LowerDIVREM24(SDValue Op, SelectionDAG &DAG,
   MVT IntVT = MVT::i32;
   MVT FltVT = MVT::f32;
 
+  if (!Sign) {
+    APInt MustBeZero = APInt::getHighBitsSet(32, 8);
+    if (!DAG.MaskedValueIsZero(LHS, MustBeZero) ||
+        !DAG.MaskedValueIsZero(RHS, MustBeZero)) {
+      return SDValue();
+    }
+  }
+
   unsigned LHSSignBits = DAG.ComputeNumSignBits(LHS);
   unsigned RHSSignBits = DAG.ComputeNumSignBits(RHS);
 
   if (Sign) {
     if (LHSSignBits < 9 || RHSSignBits < 9)
       return SDValue();
-  } else {
-    APInt MustBeZero = APInt::getHighBitsSet(32, 8);
-    if (!DAG.MaskedValueIsZero(LHS, MustBeZero) ||
-        !DAG.MaskedValueIsZero(RHS, MustBeZero)) {
-      return SDValue();
-    }
   }
 
   unsigned BitSize = VT.getSizeInBits();



More information about the llvm-commits mailing list