[llvm] AMDGPU/GlobalISel: RegBankLegalize rules for G_ABS (PR #192760)

via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 17 18:01:02 PDT 2026


https://github.com/vangthao95 created https://github.com/llvm/llvm-project/pull/192760

None

>From e41e512cb35d7fd692f3da119960f53f28f9bede Mon Sep 17 00:00:00 2001
From: Vang Thao <Vang.Thao at amd.com>
Date: Fri, 17 Apr 2026 20:38:36 -0400
Subject: [PATCH] AMDGPU/GlobalISel: RegBankLegalize rules for G_ABS

---
 .../AMDGPU/AMDGPURegBankLegalizeHelper.cpp    | 56 +++++++++++++++++++
 .../AMDGPU/AMDGPURegBankLegalizeHelper.h      |  2 +
 .../AMDGPU/AMDGPURegBankLegalizeRules.cpp     |  8 ++-
 .../AMDGPU/AMDGPURegBankLegalizeRules.h       |  4 +-
 .../CodeGen/AMDGPU/GlobalISel/llvm.abs.ll     | 23 +++++---
 .../AMDGPU/GlobalISel/regbankselect-abs.mir   |  3 +-
 6 files changed, 83 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
index 63a940ab5d29b..3626d60ba6cde 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.cpp
@@ -1083,6 +1083,58 @@ bool RegBankLegalizeHelper::lowerInsVecEltTo32(MachineInstr &MI) {
   return true;
 }
 
+bool RegBankLegalizeHelper::lowerAbsToNegMax(MachineInstr &MI) {
+  // Lower divergent G_ABS to smax(x, 0 - x) in the VGPR bank:
+  //   zero = 0
+  //   neg  = G_SUB zero, x
+  //   dst  = G_SMAX x, neg
+  //
+  // There is no integer v_abs instruction on AMDGPU, so divergent G_ABS is
+  // expanded to this sub/smax pair.
+  Register DstReg = MI.getOperand(0).getReg();
+  Register SrcReg = MI.getOperand(1).getReg();
+  LLT Ty = MRI.getType(DstReg);
+
+  Register Zero;
+  if (Ty == V2S16) {
+    // buildConstant cannot produce a V2S16 directly; pack two S16 zeros.
+    Register Zero16 = B.buildConstant({VgprRB, S16}, 0).getReg(0);
+    Zero = B.buildBuildVector({VgprRB, Ty}, {Zero16, Zero16}).getReg(0);
+  } else {
+    assert((Ty == S32 || Ty == S16) && "unexpected type for AbsToNegMax");
+    Zero = B.buildConstant({VgprRB, Ty}, 0).getReg(0);
+  }
+
+  auto Neg = B.buildSub({VgprRB, Ty}, Zero, SrcReg);
+  B.buildSMax(DstReg, SrcReg, Neg);
+  MI.eraseFromParent();
+  return true;
+}
+
+bool RegBankLegalizeHelper::lowerAbsToS32(MachineInstr &MI) {
+  // Lower uniform V2S16 abs by unpacking to two S32 lanes and re-emitting
+  // G_ABS on each lane:
+  //   packed  = bitcast <2 x s16> src to s32
+  //   lo      = sext_inreg packed, 16
+  //   hi      = ashr packed, 16
+  //   dst     = build_vector_trunc G_ABS(lo), G_ABS(hi)
+  //
+  // SALU only has s_abs_i32, with no direct uniform V2S16 abs. The
+  // re-emitted G_ABS(SgprRB, S32) selects to s_abs_i32 on each value.
+  auto Bitcast = B.buildBitcast({SgprRB, S32}, MI.getOperand(1).getReg());
+  auto SextInReg = B.buildSExtInReg({SgprRB, S32}, Bitcast, 16);
+  auto ShiftHi =
+      B.buildAShr({SgprRB, S32}, Bitcast, B.buildConstant({SgprRB, S32}, 16));
+
+  auto AbsLo = B.buildInstr(AMDGPU::G_ABS, {{SgprRB, S32}}, {SextInReg});
+  auto AbsHi = B.buildInstr(AMDGPU::G_ABS, {{SgprRB, S32}}, {ShiftHi});
+  B.buildBuildVectorTrunc(MI.getOperand(0).getReg(),
+                          {AbsLo.getReg(0), AbsHi.getReg(0)});
+
+  MI.eraseFromParent();
+  return true;
+}
+
 bool RegBankLegalizeHelper::lower(MachineInstr &MI,
                                   const RegBankLLTMapping &Mapping,
                                   WaterfallInfo &WFI) {
@@ -1365,6 +1417,10 @@ bool RegBankLegalizeHelper::lower(MachineInstr &MI,
     return lowerInsVecEltToSel(MI);
   case InsVecEltTo32:
     return lowerInsVecEltTo32(MI);
+  case AbsToNegMax:
+    return lowerAbsToNegMax(MI);
+  case AbsToS32:
+    return lowerAbsToS32(MI);
   }
 
   if (!WFI.SgprWaterfallOperandRegs.empty()) {
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.h b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.h
index 57df192832dc6..4bfb322ca7985 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeHelper.h
@@ -144,6 +144,8 @@ class RegBankLegalizeHelper {
   bool lowerExtrVecEltTo32(MachineInstr &MI);
   bool lowerInsVecEltToSel(MachineInstr &MI);
   bool lowerInsVecEltTo32(MachineInstr &MI);
+  bool lowerAbsToNegMax(MachineInstr &MI);
+  bool lowerAbsToS32(MachineInstr &MI);
   bool applyRegisterBanksINTRIN_IMAGE(MachineInstr &MI);
 };
 
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
index 03b9ea9397650..112ba7f5e12bc 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
@@ -1234,7 +1234,13 @@ RegBankLegalizeRules::RegBankLegalizeRules(const GCNSubtarget &_ST,
       .Any({{UniP3}, {{SgprP3}, {SgprP3, Sgpr32}}})
       .Any({{DivP3}, {{VgprP3}, {VgprP3, Vgpr32}}});
 
-  addRulesForGOpcs({G_ABS}, Standard).Uni(S16, {{Sgpr32Trunc}, {Sgpr32SExt}});
+  addRulesForGOpcs({G_ABS}, Standard)
+      .Uni(S16, {{Sgpr32Trunc}, {Sgpr32SExt}})
+      .Div(S16, {{Vgpr16}, {Vgpr16}, AbsToNegMax})
+      .Uni(S32, {{Sgpr32}, {Sgpr32}})
+      .Div(S32, {{Vgpr32}, {Vgpr32}, AbsToNegMax})
+      .Uni(V2S16, {{SgprV2S16}, {SgprV2S16}, AbsToS32})
+      .Div(V2S16, {{VgprV2S16}, {VgprV2S16}, AbsToNegMax});
 
   addRulesForGOpcs({G_BITREVERSE}, Standard)
       .Uni(S32, {{Sgpr32}, {Sgpr32}})
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
index 3d282220d8611..f4bbac114d00c 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.h
@@ -296,7 +296,9 @@ enum LoweringMethodID {
   ExtrVecEltToSel,
   ExtrVecEltTo32,
   InsVecEltToSel,
-  InsVecEltTo32
+  InsVecEltTo32,
+  AbsToNegMax,
+  AbsToS32
 };
 
 enum FastRulesTypes {
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.abs.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.abs.ll
index 239408d31482f..ada49d85b463d 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.abs.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.abs.ll
@@ -1,9 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=tahiti -o - < %s | FileCheck %s --check-prefixes=GFX,GFX6
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=fiji -o - < %s | FileCheck %s --check-prefixes=GFX,GFX8
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=gfx1010 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX10
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=gfx1250 -mattr=-real-true16 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX1250,GFX1250-FAKE16
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=gfx1250 -mattr=+real-true16 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX1250,GFX1250-REAL16
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=tahiti -o - < %s | FileCheck %s --check-prefixes=GFX,GFX6
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=fiji -o - < %s | FileCheck %s --check-prefixes=GFX,GFX8
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1010 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX10
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1250 -mattr=-real-true16 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX1250,GFX1250-FAKE16
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1250 -mattr=+real-true16 -o - < %s | FileCheck %s --check-prefixes=GFX,GFX1250,GFX1250-REAL16
 
 declare i16 @llvm.abs.i16(i16, i1)
 declare i32 @llvm.abs.i32(i32, i1)
@@ -730,21 +730,26 @@ define <3 x i16> @abs_vgpr_v3i16(<3 x i16> %arg) {
 ; GFX10-LABEL: abs_vgpr_v3i16:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_sub_nc_u16 v2, 0, v1
+; GFX10-NEXT:    v_max_i16 v1, v1, v2
 ; GFX10-NEXT:    v_pk_sub_i16 v2, 0, v0
-; GFX10-NEXT:    v_sub_nc_u16 v3, 0, v1
+; GFX10-NEXT:    v_and_b32_e32 v1, 0xffff, v1
 ; GFX10-NEXT:    v_pk_max_i16 v0, v0, v2
-; GFX10-NEXT:    v_max_i16 v1, v1, v3
+; GFX10-NEXT:    v_lshl_or_b32 v1, s4, 16, v1
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1250-FAKE16-LABEL: abs_vgpr_v3i16:
 ; GFX1250-FAKE16:       ; %bb.0:
 ; GFX1250-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
 ; GFX1250-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GFX1250-FAKE16-NEXT:    v_sub_nc_u16 v2, 0, v1
+; GFX1250-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
+; GFX1250-FAKE16-NEXT:    v_max_i16 v1, v1, v2
 ; GFX1250-FAKE16-NEXT:    v_pk_sub_i16 v2, 0, v0
-; GFX1250-FAKE16-NEXT:    v_sub_nc_u16 v3, 0, v1
+; GFX1250-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff, v1
 ; GFX1250-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX1250-FAKE16-NEXT:    v_pk_max_i16 v0, v0, v2
-; GFX1250-FAKE16-NEXT:    v_max_i16 v1, v1, v3
+; GFX1250-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v1
 ; GFX1250-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
 ;
 ; GFX1250-REAL16-LABEL: abs_vgpr_v3i16:
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-abs.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-abs.mir
index 7f7f8b0121567..dc73f1061dac8 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-abs.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-abs.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -run-pass=regbankselect %s -verify-machineinstrs -o - | FileCheck %s
+# RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -run-pass='amdgpu-regbankselect,amdgpu-regbanklegalize' %s -o - | FileCheck %s
 
 ---
 name: abs_sgpr_s16
@@ -16,7 +16,6 @@ body: |
     ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:sgpr(s16) = G_TRUNC [[COPY]](s32)
     ; CHECK-NEXT: [[SEXT:%[0-9]+]]:sgpr(s32) = G_SEXT [[TRUNC]](s16)
     ; CHECK-NEXT: [[ABS:%[0-9]+]]:sgpr(s32) = G_ABS [[SEXT]]
-    ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:sgpr(s16) = G_TRUNC [[ABS]](s32)
     %1:_(s32) = COPY $sgpr0
     %2:_(s16) = G_TRUNC %1
     %5:_(s16) = G_ABS %2



More information about the llvm-commits mailing list