[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