[llvm] bf9b8de - [AMDGPU][GlobalISel] Add RegBankLegalize support for G_AMDGPU_S_MUL_* (#176842)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 21 08:58:41 PST 2026


Author: vangthao95
Date: 2026-01-21T08:58:35-08:00
New Revision: bf9b8dea31a037ccfd848d94d03824b7923d2226

URL: https://github.com/llvm/llvm-project/commit/bf9b8dea31a037ccfd848d94d03824b7923d2226
DIFF: https://github.com/llvm/llvm-project/commit/bf9b8dea31a037ccfd848d94d03824b7923d2226.diff

LOG: [AMDGPU][GlobalISel] Add RegBankLegalize support for G_AMDGPU_S_MUL_* (#176842)

Added: 
    llvm/test/CodeGen/AMDGPU/GlobalISel/smul.ll

Modified: 
    llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
    llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
    llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
index 9f6a9c317667a..e7705649dd1ac 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
@@ -907,6 +907,25 @@ bool RegBankLegalizeHelper::lower(MachineInstr &MI,
     return lowerS_BFE(MI);
   case UniMAD64:
     return lowerUniMAD64(MI);
+  case UniMul64: {
+    B.buildMul(MI.getOperand(0), MI.getOperand(1), MI.getOperand(2));
+    MI.eraseFromParent();
+    return true;
+  }
+  case DivSMulToMAD: {
+    auto Op1 = B.buildTrunc(VgprRB_S32, MI.getOperand(1));
+    auto Op2 = B.buildTrunc(VgprRB_S32, MI.getOperand(2));
+    auto Zero = B.buildConstant({VgprRB, S64}, 0);
+
+    unsigned NewOpc = MI.getOpcode() == AMDGPU::G_AMDGPU_S_MUL_U64_U32
+                          ? AMDGPU::G_AMDGPU_MAD_U64_U32
+                          : AMDGPU::G_AMDGPU_MAD_I64_I32;
+
+    B.buildInstr(NewOpc, {MI.getOperand(0).getReg(), {SgprRB, S32}},
+                 {Op1, Op2, Zero});
+    MI.eraseFromParent();
+    return true;
+  }
   case SplitTo32:
     return lowerSplitTo32(MI);
   case SplitTo32Select:

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
index 7dbfde0fdf517..155725ebb40f3 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
@@ -509,6 +509,11 @@ RegBankLegalizeRules::RegBankLegalizeRules(const GCNSubtarget &_ST,
       .Div(S64, {{Vgpr64, Vcc}, {Vgpr32, Vgpr32, Vgpr64}})
       .Uni(S64, {{Sgpr64, Sgpr32Trunc}, {Sgpr32, Sgpr32, Sgpr64}, UniMAD64});
 
+  bool HasScalarSMulU64 = ST->hasScalarSMulU64();
+  addRulesForGOpcs({G_AMDGPU_S_MUL_U64_U32, G_AMDGPU_S_MUL_I64_I32}, Standard)
+      .Uni(S64, {{Sgpr64}, {Sgpr64, Sgpr64}, UniMul64}, HasScalarSMulU64)
+      .Div(S64, {{Vgpr64}, {Vgpr64, Vgpr64}, DivSMulToMAD});
+
   addRulesForGOpcs({G_XOR, G_OR, G_AND}, StandardB)
       .Any({{UniS1}, {{Sgpr32Trunc}, {Sgpr32AExt, Sgpr32AExt}}})
       .Any({{DivS1}, {{Vcc}, {Vcc, Vcc}}})

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
index 371e91ceb2649..0d147f30a9d6f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
@@ -226,6 +226,8 @@ enum LoweringMethodID {
   V_BFE,
   VgprToVccCopy,
   UniMAD64,
+  UniMul64,
+  DivSMulToMAD,
   SplitTo32,
   ScalarizeToS16,
   SplitTo32Select,

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/smul.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/smul.ll
new file mode 100644
index 0000000000000..fc0d1353a1a8c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/smul.ll
@@ -0,0 +1,194 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=verde < %s | FileCheck -check-prefix=SI %s
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1100 < %s | FileCheck -check-prefix=GFX11 %s
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck -check-prefix=GFX12 %s
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1250 < %s | FileCheck -check-prefix=GFX1250 %s
+
+define amdgpu_ps i64 @s_mul_u64_u32(i32 inreg %a, i32 inreg %b) {
+; SI-LABEL: s_mul_u64_u32:
+; SI:       ; %bb.0:
+; SI-NEXT:    v_mov_b32_e32 v0, s1
+; SI-NEXT:    v_mul_hi_u32 v0, s0, v0
+; SI-NEXT:    s_mul_i32 s0, s0, s1
+; SI-NEXT:    v_readfirstlane_b32 s1, v0
+; SI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_mul_u64_u32:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_mul_i32 s2, s0, s1
+; GFX11-NEXT:    s_mul_hi_u32 s1, s0, s1
+; GFX11-NEXT:    s_mov_b32 s0, s2
+; GFX11-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: s_mul_u64_u32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_mov_b32 s2, s1
+; GFX12-NEXT:    s_mov_b32 s1, 0
+; GFX12-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT:    s_mov_b32 s3, s1
+; GFX12-NEXT:    s_mul_u64 s[0:1], s[0:1], s[2:3]
+; GFX12-NEXT:    ; return to shader part epilog
+;
+; GFX1250-LABEL: s_mul_u64_u32:
+; GFX1250:       ; %bb.0:
+; GFX1250-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1
+; GFX1250-NEXT:    s_mov_b32 s2, s1
+; GFX1250-NEXT:    s_mov_b32 s1, 0
+; GFX1250-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX1250-NEXT:    s_mov_b32 s3, s1
+; GFX1250-NEXT:    s_mul_u64 s[0:1], s[0:1], s[2:3]
+; GFX1250-NEXT:    ; return to shader part epilog
+  %ext_a = zext i32 %a to i64
+  %ext_b = zext i32 %b to i64
+  %result = mul i64 %ext_a, %ext_b
+  ret i64 %result
+}
+
+define amdgpu_ps i64 @s_mul_i64_i32(i32 inreg %a, i32 inreg %b) {
+; SI-LABEL: s_mul_i64_i32:
+; SI:       ; %bb.0:
+; SI-NEXT:    v_mov_b32_e32 v0, s1
+; SI-NEXT:    v_mul_hi_u32 v0, s0, v0
+; SI-NEXT:    s_ashr_i32 s3, s0, 31
+; SI-NEXT:    s_ashr_i32 s4, s1, 31
+; SI-NEXT:    s_mul_i32 s2, s0, s1
+; SI-NEXT:    s_mul_i32 s1, s3, s1
+; SI-NEXT:    s_mul_i32 s0, s0, s4
+; SI-NEXT:    v_readfirstlane_b32 s3, v0
+; SI-NEXT:    s_add_i32 s0, s1, s0
+; SI-NEXT:    s_add_i32 s1, s0, s3
+; SI-NEXT:    s_mov_b32 s0, s2
+; SI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_mul_i64_i32:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_ashr_i32 s2, s1, 31
+; GFX11-NEXT:    s_mul_hi_u32 s3, s0, s1
+; GFX11-NEXT:    s_mul_i32 s2, s0, s2
+; GFX11-NEXT:    s_ashr_i32 s4, s0, 31
+; GFX11-NEXT:    s_add_i32 s2, s3, s2
+; GFX11-NEXT:    s_mul_i32 s4, s4, s1
+; GFX11-NEXT:    s_mul_i32 s0, s0, s1
+; GFX11-NEXT:    s_add_i32 s1, s2, s4
+; GFX11-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: s_mul_i64_i32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_mov_b32 s2, s1
+; GFX12-NEXT:    s_ashr_i32 s1, s0, 31
+; GFX12-NEXT:    s_ashr_i32 s3, s2, 31
+; GFX12-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX12-NEXT:    s_mul_u64 s[0:1], s[0:1], s[2:3]
+; GFX12-NEXT:    ; return to shader part epilog
+;
+; GFX1250-LABEL: s_mul_i64_i32:
+; GFX1250:       ; %bb.0:
+; GFX1250-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1
+; GFX1250-NEXT:    s_mov_b32 s2, s1
+; GFX1250-NEXT:    s_ashr_i32 s1, s0, 31
+; GFX1250-NEXT:    s_ashr_i32 s3, s2, 31
+; GFX1250-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX1250-NEXT:    s_mul_u64 s[0:1], s[0:1], s[2:3]
+; GFX1250-NEXT:    ; return to shader part epilog
+  %ext_a = sext i32 %a to i64
+  %ext_b = sext i32 %b to i64
+  %result = mul i64 %ext_a, %ext_b
+  ret i64 %result
+}
+
+define i64 @v_mul_u64_u32(i32 %a, i32 %b) {
+; SI-LABEL: v_mul_u64_u32:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_mul_lo_u32 v2, v0, v1
+; SI-NEXT:    v_mul_hi_u32 v1, v0, v1
+; SI-NEXT:    v_mov_b32_e32 v0, v2
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_mul_u64_u32:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_mad_u64_u32 v[0:1], null, v2, v3, 0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_mul_u64_u32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_mad_co_u64_u32 v[0:1], null, v2, v3, 0
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1250-LABEL: v_mul_u64_u32:
+; GFX1250:       ; %bb.0:
+; GFX1250-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX1250-NEXT:    s_wait_kmcnt 0x0
+; GFX1250-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX1250-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX1250-NEXT:    v_mad_nc_u64_u32 v[0:1], v2, v3, 0
+; GFX1250-NEXT:    s_set_pc_i64 s[30:31]
+  %ext_a = zext i32 %a to i64
+  %ext_b = zext i32 %b to i64
+  %result = mul i64 %ext_a, %ext_b
+  ret i64 %result
+}
+
+define i64 @v_mul_i64_i32(i32 %a, i32 %b) {
+; SI-LABEL: v_mul_i64_i32:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_ashrrev_i32_e32 v2, 31, v0
+; SI-NEXT:    v_ashrrev_i32_e32 v3, 31, v1
+; SI-NEXT:    v_mul_lo_u32 v4, v2, v1
+; SI-NEXT:    v_mul_lo_u32 v3, v0, v3
+; SI-NEXT:    v_mul_lo_u32 v2, v0, v1
+; SI-NEXT:    v_mul_hi_u32 v0, v0, v1
+; SI-NEXT:    v_add_i32_e32 v1, vcc, v4, v3
+; SI-NEXT:    v_add_i32_e32 v1, vcc, v1, v0
+; SI-NEXT:    v_mov_b32_e32 v0, v2
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_mul_i64_i32:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_mad_u64_u32 v[0:1], null, v2, v3, 0
+; GFX11-NEXT:    v_ashrrev_i32_e32 v6, 31, v3
+; GFX11-NEXT:    v_mad_u64_u32 v[4:5], null, v2, v6, v[1:2]
+; GFX11-NEXT:    v_ashrrev_i32_e32 v5, 31, v2
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_mad_u64_u32 v[1:2], null, v5, v3, v[4:5]
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_mul_i64_i32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_mad_co_i64_i32 v[0:1], null, v2, v3, 0
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1250-LABEL: v_mul_i64_i32:
+; GFX1250:       ; %bb.0:
+; GFX1250-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX1250-NEXT:    s_wait_kmcnt 0x0
+; GFX1250-NEXT:    v_dual_mov_b32 v2, v0 :: v_dual_mov_b32 v3, v1
+; GFX1250-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX1250-NEXT:    v_mad_nc_i64_i32 v[0:1], v2, v3, 0
+; GFX1250-NEXT:    s_set_pc_i64 s[30:31]
+  %ext_a = sext i32 %a to i64
+  %ext_b = sext i32 %b to i64
+  %result = mul i64 %ext_a, %ext_b
+  ret i64 %result
+}


        


More information about the llvm-commits mailing list