[llvm] [AMDGPU] Fix undivergent parameter pass using vgpr (PR #178198)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 27 21:59:13 PST 2026
https://github.com/Shoreshen updated https://github.com/llvm/llvm-project/pull/178198
>From da64dfb7889f69325392faca1d23a4a016756993 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 27 Jan 2026 21:10:59 +0800
Subject: [PATCH 1/3] fix undivergent parameter pass using vgpr
---
llvm/include/llvm/CodeGen/TargetCallingConv.h | 14 +-
llvm/include/llvm/CodeGen/TargetLowering.h | 10 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 2 +
.../CodeGen/SelectionDAG/TargetLowering.cpp | 3 +
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 7 +-
...l-args-inreg-no-sgpr-for-csrspill-xfail.ll | 27 ---
.../call-args-inreg-no-sgpr-for-csrspill.ll | 156 ++++++++++++++++++
7 files changed, 181 insertions(+), 38 deletions(-)
delete mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
create mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
diff --git a/llvm/include/llvm/CodeGen/TargetCallingConv.h b/llvm/include/llvm/CodeGen/TargetCallingConv.h
index f197c7f1645ec..afc8b6d1af84c 100644
--- a/llvm/include/llvm/CodeGen/TargetCallingConv.h
+++ b/llvm/include/llvm/CodeGen/TargetCallingConv.h
@@ -30,6 +30,7 @@ namespace ISD {
unsigned IsSExt : 1; ///< Sign extended
unsigned IsNoExt : 1; ///< No extension
unsigned IsInReg : 1; ///< Passed in register
+ unsigned IsArgInReg : 1; ///< Is caller function's 'inreg' argument
unsigned IsSRet : 1; ///< Hidden struct-ret ptr
unsigned IsByVal : 1; ///< Struct passed by value
unsigned IsByRef : 1; ///< Passed in memory
@@ -63,11 +64,11 @@ namespace ISD {
public:
ArgFlagsTy()
- : IsZExt(0), IsSExt(0), IsNoExt(0), IsInReg(0), IsSRet(0), IsByVal(0),
- IsByRef(0), IsNest(0), IsReturned(0), IsSplit(0), IsInAlloca(0),
- IsPreallocated(0), IsSplitEnd(0), IsSwiftSelf(0), IsSwiftAsync(0),
- IsSwiftError(0), IsCFGuardTarget(0), IsHva(0), IsHvaStart(0),
- IsSecArgPass(0), MemAlign(0), OrigAlign(0),
+ : IsZExt(0), IsSExt(0), IsNoExt(0), IsInReg(0), IsArgInReg(0),
+ IsSRet(0), IsByVal(0), IsByRef(0), IsNest(0), IsReturned(0),
+ IsSplit(0), IsInAlloca(0), IsPreallocated(0), IsSplitEnd(0),
+ IsSwiftSelf(0), IsSwiftAsync(0), IsSwiftError(0), IsCFGuardTarget(0),
+ IsHva(0), IsHvaStart(0), IsSecArgPass(0), MemAlign(0), OrigAlign(0),
IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0),
IsCopyElisionCandidate(0), IsPointer(0), IsVarArg(0) {
static_assert(sizeof(*this) == 4 * sizeof(unsigned), "flags are too big");
@@ -85,6 +86,9 @@ namespace ISD {
bool isInReg() const { return IsInReg; }
void setInReg() { IsInReg = 1; }
+ bool isArgInReg() const { return IsArgInReg; }
+ void setArgInReg() { IsArgInReg = 1; }
+
bool isSRet() const { return IsSRet; }
void setSRet() { IsSRet = 1; }
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index df0fced112f73..d2b2e502268fb 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -309,6 +309,7 @@ class LLVM_ABI TargetLoweringBase {
bool IsZExt : 1;
bool IsNoExt : 1;
bool IsInReg : 1;
+ bool IsArgInReg : 1;
bool IsSRet : 1;
bool IsNest : 1;
bool IsByVal : 1;
@@ -325,10 +326,11 @@ class LLVM_ABI TargetLoweringBase {
ArgListEntry(Value *Val, SDValue Node, Type *Ty)
: Val(Val), Node(Node), OrigTy(Ty), Ty(Ty), IsSExt(false),
- IsZExt(false), IsNoExt(false), IsInReg(false), IsSRet(false),
- IsNest(false), IsByVal(false), IsByRef(false), IsInAlloca(false),
- IsPreallocated(false), IsReturned(false), IsSwiftSelf(false),
- IsSwiftAsync(false), IsSwiftError(false), IsCFGuardTarget(false) {}
+ IsZExt(false), IsNoExt(false), IsInReg(false), IsArgInReg(false),
+ IsSRet(false), IsNest(false), IsByVal(false), IsByRef(false),
+ IsInAlloca(false), IsPreallocated(false), IsReturned(false),
+ IsSwiftSelf(false), IsSwiftAsync(false), IsSwiftError(false),
+ IsCFGuardTarget(false) {}
explicit ArgListEntry(Value *Val, SDValue Node = SDValue())
: ArgListEntry(Val, Node, Val->getType()) {}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 63c9d193421ea..32f1ad6763db4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11323,6 +11323,8 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
// Set InReg Flag
Flags.setInReg();
}
+ if (Args[i].IsArgInReg)
+ Flags.setArgInReg();
if (Args[i].IsSRet)
Flags.setSRet();
if (Args[i].IsSwiftSelf)
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index edba0a7169c0a..ad6b2cf421ba7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -134,6 +134,9 @@ void TargetLoweringBase::ArgListEntry::setAttributes(const CallBase *Call,
IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError);
Alignment = Call->getParamStackAlign(ArgIdx);
IndirectType = nullptr;
+ Value *Op = Call->getArgOperand(ArgIdx);
+ if (const Argument *Arg = dyn_cast<Argument>(Op))
+ IsArgInReg = Arg->hasInRegAttr();
assert(IsByVal + IsPreallocated + IsInAlloca + IsSRet <= 1 &&
"multiple ABI attributes?");
if (IsByVal) {
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 18f77ce2d76ec..db5364fbb4ad6 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -4391,8 +4391,10 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
unsigned ArgIdx = 0;
for (auto [Reg, Val] : RegsToPass) {
- if (ArgIdx++ >= NumSpecialInputs &&
- (IsChainCallConv || !Val->isDivergent()) && TRI->isSGPRPhysReg(Reg)) {
+ if (ArgIdx >= NumSpecialInputs &&
+ (IsChainCallConv || !Val->isDivergent() ||
+ Outs[ArgIdx - NumSpecialInputs].Flags.isArgInReg()) &&
+ TRI->isSGPRPhysReg(Reg)) {
// For chain calls, the inreg arguments are required to be
// uniform. Speculatively Insert a readfirstlane in case we cannot prove
// they are uniform.
@@ -4412,6 +4414,7 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
Chain = DAG.getCopyToReg(Chain, DL, Reg, Val, InGlue);
InGlue = Chain.getValue(1);
+ ArgIdx++;
}
// We don't usually want to end the call-sequence here because we would tidy
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
deleted file mode 100644
index 34f4476f7fd6a..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
+++ /dev/null
@@ -1,27 +0,0 @@
-; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -enable-var-scope %s
-
-; CHECK: illegal VGPR to SGPR copy
-
-declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
-declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
-declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
-
-define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
- call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
- call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
- call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
- ret void
-}
-
-attributes #0 = { nounwind }
-
-!llvm.module.flags = !{!0}
-!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
new file mode 100644
index 0000000000000..fae5fa5ceeef7
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
@@ -0,0 +1,156 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 < %s | FileCheck -enable-var-scope %s
+
+declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
+declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
+declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
+
+define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
+; CHECK-LABEL: test_call_external_void_func_a15i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s27
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
+; CHECK-LABEL: test_call_external_void_func_a16i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s41, s27
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: v_readfirstlane_b32 s27, v1
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a16i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a16i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s41
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
+; CHECK-LABEL: test_call_external_void_func_a15i32_inreg_i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s41, s27
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: v_readfirstlane_b32 s27, v1
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg_i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg_i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s41
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
+ ret void
+}
+
+attributes #0 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
>From 767b2fe38688bc62a564c3dff0836fdb5120bf6f Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 28 Jan 2026 13:31:28 +0800
Subject: [PATCH 2/3] Revert "fix undivergent parameter pass using vgpr"
This reverts commit da64dfb7889f69325392faca1d23a4a016756993.
---
llvm/include/llvm/CodeGen/TargetCallingConv.h | 14 +-
llvm/include/llvm/CodeGen/TargetLowering.h | 10 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 2 -
.../CodeGen/SelectionDAG/TargetLowering.cpp | 3 -
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 7 +-
...l-args-inreg-no-sgpr-for-csrspill-xfail.ll | 27 +++
.../call-args-inreg-no-sgpr-for-csrspill.ll | 156 ------------------
7 files changed, 38 insertions(+), 181 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
delete mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
diff --git a/llvm/include/llvm/CodeGen/TargetCallingConv.h b/llvm/include/llvm/CodeGen/TargetCallingConv.h
index afc8b6d1af84c..f197c7f1645ec 100644
--- a/llvm/include/llvm/CodeGen/TargetCallingConv.h
+++ b/llvm/include/llvm/CodeGen/TargetCallingConv.h
@@ -30,7 +30,6 @@ namespace ISD {
unsigned IsSExt : 1; ///< Sign extended
unsigned IsNoExt : 1; ///< No extension
unsigned IsInReg : 1; ///< Passed in register
- unsigned IsArgInReg : 1; ///< Is caller function's 'inreg' argument
unsigned IsSRet : 1; ///< Hidden struct-ret ptr
unsigned IsByVal : 1; ///< Struct passed by value
unsigned IsByRef : 1; ///< Passed in memory
@@ -64,11 +63,11 @@ namespace ISD {
public:
ArgFlagsTy()
- : IsZExt(0), IsSExt(0), IsNoExt(0), IsInReg(0), IsArgInReg(0),
- IsSRet(0), IsByVal(0), IsByRef(0), IsNest(0), IsReturned(0),
- IsSplit(0), IsInAlloca(0), IsPreallocated(0), IsSplitEnd(0),
- IsSwiftSelf(0), IsSwiftAsync(0), IsSwiftError(0), IsCFGuardTarget(0),
- IsHva(0), IsHvaStart(0), IsSecArgPass(0), MemAlign(0), OrigAlign(0),
+ : IsZExt(0), IsSExt(0), IsNoExt(0), IsInReg(0), IsSRet(0), IsByVal(0),
+ IsByRef(0), IsNest(0), IsReturned(0), IsSplit(0), IsInAlloca(0),
+ IsPreallocated(0), IsSplitEnd(0), IsSwiftSelf(0), IsSwiftAsync(0),
+ IsSwiftError(0), IsCFGuardTarget(0), IsHva(0), IsHvaStart(0),
+ IsSecArgPass(0), MemAlign(0), OrigAlign(0),
IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0),
IsCopyElisionCandidate(0), IsPointer(0), IsVarArg(0) {
static_assert(sizeof(*this) == 4 * sizeof(unsigned), "flags are too big");
@@ -86,9 +85,6 @@ namespace ISD {
bool isInReg() const { return IsInReg; }
void setInReg() { IsInReg = 1; }
- bool isArgInReg() const { return IsArgInReg; }
- void setArgInReg() { IsArgInReg = 1; }
-
bool isSRet() const { return IsSRet; }
void setSRet() { IsSRet = 1; }
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index d2b2e502268fb..df0fced112f73 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -309,7 +309,6 @@ class LLVM_ABI TargetLoweringBase {
bool IsZExt : 1;
bool IsNoExt : 1;
bool IsInReg : 1;
- bool IsArgInReg : 1;
bool IsSRet : 1;
bool IsNest : 1;
bool IsByVal : 1;
@@ -326,11 +325,10 @@ class LLVM_ABI TargetLoweringBase {
ArgListEntry(Value *Val, SDValue Node, Type *Ty)
: Val(Val), Node(Node), OrigTy(Ty), Ty(Ty), IsSExt(false),
- IsZExt(false), IsNoExt(false), IsInReg(false), IsArgInReg(false),
- IsSRet(false), IsNest(false), IsByVal(false), IsByRef(false),
- IsInAlloca(false), IsPreallocated(false), IsReturned(false),
- IsSwiftSelf(false), IsSwiftAsync(false), IsSwiftError(false),
- IsCFGuardTarget(false) {}
+ IsZExt(false), IsNoExt(false), IsInReg(false), IsSRet(false),
+ IsNest(false), IsByVal(false), IsByRef(false), IsInAlloca(false),
+ IsPreallocated(false), IsReturned(false), IsSwiftSelf(false),
+ IsSwiftAsync(false), IsSwiftError(false), IsCFGuardTarget(false) {}
explicit ArgListEntry(Value *Val, SDValue Node = SDValue())
: ArgListEntry(Val, Node, Val->getType()) {}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 32f1ad6763db4..63c9d193421ea 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11323,8 +11323,6 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
// Set InReg Flag
Flags.setInReg();
}
- if (Args[i].IsArgInReg)
- Flags.setArgInReg();
if (Args[i].IsSRet)
Flags.setSRet();
if (Args[i].IsSwiftSelf)
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index ad6b2cf421ba7..edba0a7169c0a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -134,9 +134,6 @@ void TargetLoweringBase::ArgListEntry::setAttributes(const CallBase *Call,
IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError);
Alignment = Call->getParamStackAlign(ArgIdx);
IndirectType = nullptr;
- Value *Op = Call->getArgOperand(ArgIdx);
- if (const Argument *Arg = dyn_cast<Argument>(Op))
- IsArgInReg = Arg->hasInRegAttr();
assert(IsByVal + IsPreallocated + IsInAlloca + IsSRet <= 1 &&
"multiple ABI attributes?");
if (IsByVal) {
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index db5364fbb4ad6..18f77ce2d76ec 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -4391,10 +4391,8 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
unsigned ArgIdx = 0;
for (auto [Reg, Val] : RegsToPass) {
- if (ArgIdx >= NumSpecialInputs &&
- (IsChainCallConv || !Val->isDivergent() ||
- Outs[ArgIdx - NumSpecialInputs].Flags.isArgInReg()) &&
- TRI->isSGPRPhysReg(Reg)) {
+ if (ArgIdx++ >= NumSpecialInputs &&
+ (IsChainCallConv || !Val->isDivergent()) && TRI->isSGPRPhysReg(Reg)) {
// For chain calls, the inreg arguments are required to be
// uniform. Speculatively Insert a readfirstlane in case we cannot prove
// they are uniform.
@@ -4414,7 +4412,6 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
Chain = DAG.getCopyToReg(Chain, DL, Reg, Val, InGlue);
InGlue = Chain.getValue(1);
- ArgIdx++;
}
// We don't usually want to end the call-sequence here because we would tidy
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
new file mode 100644
index 0000000000000..34f4476f7fd6a
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
@@ -0,0 +1,27 @@
+; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -enable-var-scope %s
+
+; CHECK: illegal VGPR to SGPR copy
+
+declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
+declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
+declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
+
+define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
+ call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
+ call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
+ call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
+ ret void
+}
+
+attributes #0 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
deleted file mode 100644
index fae5fa5ceeef7..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
+++ /dev/null
@@ -1,156 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 < %s | FileCheck -enable-var-scope %s
-
-declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
-declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
-declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
-
-define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
-; CHECK-LABEL: test_call_external_void_func_a15i32_inreg:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT: s_mov_b32 s40, s33
-; CHECK-NEXT: s_mov_b32 s33, s32
-; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
-; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
-; CHECK-NEXT: s_mov_b64 exec, s[42:43]
-; CHECK-NEXT: v_writelane_b32 v40, s40, 2
-; CHECK-NEXT: s_addk_i32 s32, 0x400
-; CHECK-NEXT: s_mov_b32 s40, s26
-; CHECK-NEXT: v_writelane_b32 v40, s30, 0
-; CHECK-NEXT: v_readfirstlane_b32 s26, v0
-; CHECK-NEXT: s_getpc_b64 s[42:43]
-; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg at rel32@lo+4
-; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg at rel32@hi+12
-; CHECK-NEXT: s_mov_b32 s3, s19
-; CHECK-NEXT: s_mov_b32 s2, s18
-; CHECK-NEXT: s_mov_b32 s1, s17
-; CHECK-NEXT: s_mov_b32 s0, s16
-; CHECK-NEXT: s_mov_b32 s16, s20
-; CHECK-NEXT: s_mov_b32 s17, s21
-; CHECK-NEXT: s_mov_b32 s18, s22
-; CHECK-NEXT: s_mov_b32 s19, s23
-; CHECK-NEXT: s_mov_b32 s20, s24
-; CHECK-NEXT: s_mov_b32 s21, s25
-; CHECK-NEXT: s_mov_b32 s22, s40
-; CHECK-NEXT: s_mov_b32 s23, s27
-; CHECK-NEXT: s_mov_b32 s24, s28
-; CHECK-NEXT: s_mov_b32 s25, s29
-; CHECK-NEXT: v_writelane_b32 v40, s31, 1
-; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
-; CHECK-NEXT: v_readlane_b32 s31, v40, 1
-; CHECK-NEXT: v_readlane_b32 s30, v40, 0
-; CHECK-NEXT: s_mov_b32 s32, s33
-; CHECK-NEXT: v_readlane_b32 s4, v40, 2
-; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
-; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
-; CHECK-NEXT: s_mov_b64 exec, s[6:7]
-; CHECK-NEXT: s_mov_b32 s33, s4
-; CHECK-NEXT: s_waitcnt vmcnt(0)
-; CHECK-NEXT: s_setpc_b64 s[30:31]
- call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
-; CHECK-LABEL: test_call_external_void_func_a16i32_inreg:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT: s_mov_b32 s40, s33
-; CHECK-NEXT: s_mov_b32 s33, s32
-; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
-; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
-; CHECK-NEXT: s_mov_b64 exec, s[42:43]
-; CHECK-NEXT: v_writelane_b32 v40, s40, 2
-; CHECK-NEXT: s_addk_i32 s32, 0x400
-; CHECK-NEXT: s_mov_b32 s41, s27
-; CHECK-NEXT: s_mov_b32 s40, s26
-; CHECK-NEXT: v_writelane_b32 v40, s30, 0
-; CHECK-NEXT: v_readfirstlane_b32 s26, v0
-; CHECK-NEXT: v_readfirstlane_b32 s27, v1
-; CHECK-NEXT: s_getpc_b64 s[42:43]
-; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a16i32_inreg at rel32@lo+4
-; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a16i32_inreg at rel32@hi+12
-; CHECK-NEXT: s_mov_b32 s3, s19
-; CHECK-NEXT: s_mov_b32 s2, s18
-; CHECK-NEXT: s_mov_b32 s1, s17
-; CHECK-NEXT: s_mov_b32 s0, s16
-; CHECK-NEXT: s_mov_b32 s16, s20
-; CHECK-NEXT: s_mov_b32 s17, s21
-; CHECK-NEXT: s_mov_b32 s18, s22
-; CHECK-NEXT: s_mov_b32 s19, s23
-; CHECK-NEXT: s_mov_b32 s20, s24
-; CHECK-NEXT: s_mov_b32 s21, s25
-; CHECK-NEXT: s_mov_b32 s22, s40
-; CHECK-NEXT: s_mov_b32 s23, s41
-; CHECK-NEXT: s_mov_b32 s24, s28
-; CHECK-NEXT: s_mov_b32 s25, s29
-; CHECK-NEXT: v_writelane_b32 v40, s31, 1
-; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
-; CHECK-NEXT: v_readlane_b32 s31, v40, 1
-; CHECK-NEXT: v_readlane_b32 s30, v40, 0
-; CHECK-NEXT: s_mov_b32 s32, s33
-; CHECK-NEXT: v_readlane_b32 s4, v40, 2
-; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
-; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
-; CHECK-NEXT: s_mov_b64 exec, s[6:7]
-; CHECK-NEXT: s_mov_b32 s33, s4
-; CHECK-NEXT: s_waitcnt vmcnt(0)
-; CHECK-NEXT: s_setpc_b64 s[30:31]
- call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
-; CHECK-LABEL: test_call_external_void_func_a15i32_inreg_i32_inreg:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT: s_mov_b32 s40, s33
-; CHECK-NEXT: s_mov_b32 s33, s32
-; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
-; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
-; CHECK-NEXT: s_mov_b64 exec, s[42:43]
-; CHECK-NEXT: v_writelane_b32 v40, s40, 2
-; CHECK-NEXT: s_addk_i32 s32, 0x400
-; CHECK-NEXT: s_mov_b32 s41, s27
-; CHECK-NEXT: s_mov_b32 s40, s26
-; CHECK-NEXT: v_writelane_b32 v40, s30, 0
-; CHECK-NEXT: v_readfirstlane_b32 s26, v0
-; CHECK-NEXT: v_readfirstlane_b32 s27, v1
-; CHECK-NEXT: s_getpc_b64 s[42:43]
-; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg_i32_inreg at rel32@lo+4
-; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg_i32_inreg at rel32@hi+12
-; CHECK-NEXT: s_mov_b32 s3, s19
-; CHECK-NEXT: s_mov_b32 s2, s18
-; CHECK-NEXT: s_mov_b32 s1, s17
-; CHECK-NEXT: s_mov_b32 s0, s16
-; CHECK-NEXT: s_mov_b32 s16, s20
-; CHECK-NEXT: s_mov_b32 s17, s21
-; CHECK-NEXT: s_mov_b32 s18, s22
-; CHECK-NEXT: s_mov_b32 s19, s23
-; CHECK-NEXT: s_mov_b32 s20, s24
-; CHECK-NEXT: s_mov_b32 s21, s25
-; CHECK-NEXT: s_mov_b32 s22, s40
-; CHECK-NEXT: s_mov_b32 s23, s41
-; CHECK-NEXT: s_mov_b32 s24, s28
-; CHECK-NEXT: s_mov_b32 s25, s29
-; CHECK-NEXT: v_writelane_b32 v40, s31, 1
-; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
-; CHECK-NEXT: v_readlane_b32 s31, v40, 1
-; CHECK-NEXT: v_readlane_b32 s30, v40, 0
-; CHECK-NEXT: s_mov_b32 s32, s33
-; CHECK-NEXT: v_readlane_b32 s4, v40, 2
-; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
-; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
-; CHECK-NEXT: s_mov_b64 exec, s[6:7]
-; CHECK-NEXT: s_mov_b32 s33, s4
-; CHECK-NEXT: s_waitcnt vmcnt(0)
-; CHECK-NEXT: s_setpc_b64 s[30:31]
- call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
- ret void
-}
-
-attributes #0 = { nounwind }
-
-!llvm.module.flags = !{!0}
-!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
>From 4f36846e1406df0a5db6e88dd0c901ee40fdfc38 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 28 Jan 2026 13:58:53 +0800
Subject: [PATCH 3/3] Analyze inside LowerCall
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 50 ++++--
...l-args-inreg-no-sgpr-for-csrspill-xfail.ll | 27 ---
.../call-args-inreg-no-sgpr-for-csrspill.ll | 156 ++++++++++++++++++
3 files changed, 188 insertions(+), 45 deletions(-)
delete mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
create mode 100644 llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 18f77ce2d76ec..d755e0794ce28 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -4391,27 +4391,41 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
unsigned ArgIdx = 0;
for (auto [Reg, Val] : RegsToPass) {
- if (ArgIdx++ >= NumSpecialInputs &&
- (IsChainCallConv || !Val->isDivergent()) && TRI->isSGPRPhysReg(Reg)) {
- // For chain calls, the inreg arguments are required to be
- // uniform. Speculatively Insert a readfirstlane in case we cannot prove
- // they are uniform.
- //
- // For other calls, if an inreg arguments is known to be uniform,
- // speculatively insert a readfirstlane in case it is in a VGPR.
- //
- // FIXME: We need to execute this in a waterfall loop if it is a divergent
- // value, so let that continue to produce invalid code.
-
- SmallVector<SDValue, 3> ReadfirstlaneArgs({ReadFirstLaneID, Val});
- if (TokenGlue)
- ReadfirstlaneArgs.push_back(TokenGlue);
- Val = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Val.getValueType(),
- ReadfirstlaneArgs);
+ if (ArgIdx >= NumSpecialInputs) {
+ // If this arg is from an inreg parameter of the caller
+ // This is trying to generate readfirstlane if arg is inreg, but SGPR was
+ // used up and VGPR is used instead. In such case, the data is uniform and
+ // should use readfirstlane.
+ bool IsFromInRegParam = false;
+ unsigned OrigArgIdx = Outs[ArgIdx - NumSpecialInputs].OrigArgIndex;
+ if (CLI.CB && OrigArgIdx < CLI.CB->arg_size()) {
+ Value *ArgOperand =
+ CLI.CB->getArgOperand(Outs[ArgIdx - NumSpecialInputs].OrigArgIndex);
+ if (const Argument *Arg = dyn_cast<Argument>(ArgOperand))
+ IsFromInRegParam = Arg->hasInRegAttr();
+ }
+ if ((IsChainCallConv || !Val->isDivergent() || IsFromInRegParam) &&
+ TRI->isSGPRPhysReg(Reg)) {
+ // For chain calls, the inreg arguments are required to be
+ // uniform. Speculatively Insert a readfirstlane in case we cannot prove
+ // they are uniform.
+ //
+ // For other calls, if an inreg arguments is known to be uniform,
+ // speculatively insert a readfirstlane in case it is in a VGPR.
+ //
+ // FIXME: We need to execute this in a waterfall loop if it is a
+ // divergent value, so let that continue to produce invalid code.
+
+ SmallVector<SDValue, 3> ReadfirstlaneArgs({ReadFirstLaneID, Val});
+ if (TokenGlue)
+ ReadfirstlaneArgs.push_back(TokenGlue);
+ Val = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Val.getValueType(),
+ ReadfirstlaneArgs);
+ }
}
-
Chain = DAG.getCopyToReg(Chain, DL, Reg, Val, InGlue);
InGlue = Chain.getValue(1);
+ ArgIdx++;
}
// We don't usually want to end the call-sequence here because we would tidy
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
deleted file mode 100644
index 34f4476f7fd6a..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill-xfail.ll
+++ /dev/null
@@ -1,27 +0,0 @@
-; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -enable-var-scope %s
-
-; CHECK: illegal VGPR to SGPR copy
-
-declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
-declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
-declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
-
-define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
- call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
- call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
- ret void
-}
-
-define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
- call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
- ret void
-}
-
-attributes #0 = { nounwind }
-
-!llvm.module.flags = !{!0}
-!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
diff --git a/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
new file mode 100644
index 0000000000000..fae5fa5ceeef7
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/call-args-inreg-no-sgpr-for-csrspill.ll
@@ -0,0 +1,156 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 < %s | FileCheck -enable-var-scope %s
+
+declare hidden void @external_void_func_a15i32_inreg([15 x i32] inreg) #0
+declare hidden void @external_void_func_a16i32_inreg([16 x i32] inreg) #0
+declare hidden void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg, i32 inreg) #0
+
+define void @test_call_external_void_func_a15i32_inreg([15 x i32] inreg %arg0) #0 {
+; CHECK-LABEL: test_call_external_void_func_a15i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s27
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a15i32_inreg([15 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a16i32_inreg([16 x i32] inreg %arg0) #0 {
+; CHECK-LABEL: test_call_external_void_func_a16i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s41, s27
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: v_readfirstlane_b32 s27, v1
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a16i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a16i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s41
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a16i32_inreg([16 x i32] inreg %arg0)
+ ret void
+}
+
+define void @test_call_external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1) #0 {
+; CHECK-LABEL: test_call_external_void_func_a15i32_inreg_i32_inreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b32 s40, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b64 s[42:43], -1
+; CHECK-NEXT: buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[42:43]
+; CHECK-NEXT: v_writelane_b32 v40, s40, 2
+; CHECK-NEXT: s_addk_i32 s32, 0x400
+; CHECK-NEXT: s_mov_b32 s41, s27
+; CHECK-NEXT: s_mov_b32 s40, s26
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: v_readfirstlane_b32 s26, v0
+; CHECK-NEXT: v_readfirstlane_b32 s27, v1
+; CHECK-NEXT: s_getpc_b64 s[42:43]
+; CHECK-NEXT: s_add_u32 s42, s42, external_void_func_a15i32_inreg_i32_inreg at rel32@lo+4
+; CHECK-NEXT: s_addc_u32 s43, s43, external_void_func_a15i32_inreg_i32_inreg at rel32@hi+12
+; CHECK-NEXT: s_mov_b32 s3, s19
+; CHECK-NEXT: s_mov_b32 s2, s18
+; CHECK-NEXT: s_mov_b32 s1, s17
+; CHECK-NEXT: s_mov_b32 s0, s16
+; CHECK-NEXT: s_mov_b32 s16, s20
+; CHECK-NEXT: s_mov_b32 s17, s21
+; CHECK-NEXT: s_mov_b32 s18, s22
+; CHECK-NEXT: s_mov_b32 s19, s23
+; CHECK-NEXT: s_mov_b32 s20, s24
+; CHECK-NEXT: s_mov_b32 s21, s25
+; CHECK-NEXT: s_mov_b32 s22, s40
+; CHECK-NEXT: s_mov_b32 s23, s41
+; CHECK-NEXT: s_mov_b32 s24, s28
+; CHECK-NEXT: s_mov_b32 s25, s29
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[42:43]
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s4, v40, 2
+; CHECK-NEXT: s_or_saveexec_b64 s[6:7], -1
+; CHECK-NEXT: buffer_load_dword v40, off, s[0:3], s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[6:7]
+; CHECK-NEXT: s_mov_b32 s33, s4
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @external_void_func_a15i32_inreg_i32_inreg([15 x i32] inreg %arg0, i32 inreg %arg1)
+ ret void
+}
+
+attributes #0 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"amdhsa_code_object_version", i32 400}
More information about the llvm-commits
mailing list