[llvm] [X86] Clear regcall arg aliases in dynamic CSR masks (PR #225262)
Demetrios Chiuratto Agourakis via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 26 17:21:19 PDT 2026
https://github.com/agourakis82 updated https://github.com/llvm/llvm-project/pull/225262
>From 7cdecec4a5c07372b16bb9dad80b14331fb836e5 Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Tue, 22 Sep 2026 01:44:49 +0000
Subject: [PATCH 1/3] [X86] Clear regcall arg and return aliases in dynamic CSR
masks
When constructing a dynamic call-preserved mask for conventions that
disable argument or return registers (notably x86_regcallcc), clearing
only subregs_inclusive leaves overlapping superregisters marked preserved.
An i32 argument or return value in R14D therefore still left R14 preserved,
so a live i64 in R14 could be incorrectly kept across the call and read
back after the callee clobbered it.
Use MCRegAliasIterator for both argument and return dynamic mask
updates, matching callee-side disableCalleeSavedRegister behavior.
Fixes #225057
---
llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 17 ++++++---
.../CodeGen/X86/regcall-subreg-argmask.ll | 38 +++++++++++++++++++
2 files changed, 49 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/regcall-subreg-argmask.ll
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 9a03da14ee10e..70f6a3222ebbe 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -1167,8 +1167,9 @@ SDValue X86TargetLowering::LowerCallResult(
// In some calling conventions we need to remove the used registers
// from the register mask.
if (RegMask) {
- for (MCPhysReg SubReg : TRI->subregs_inclusive(VA.getLocReg()))
- RegMask[SubReg / 32] &= ~(1u << (SubReg % 32));
+ for (MCRegAliasIterator Alias(VA.getLocReg(), TRI, true); Alias.isValid();
+ ++Alias)
+ RegMask[*Alias / 32] &= ~(1u << (*Alias % 32));
}
// Report an error if there was an attempt to return FP values via XMM
@@ -2682,12 +2683,16 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
unsigned RegMaskSize = MachineOperand::getRegMaskSize(TRI->getNumRegs());
memcpy(RegMask, Mask, sizeof(RegMask[0]) * RegMaskSize);
- // Make sure all sub registers of the argument registers are reset
- // in the RegMask.
+ // Make sure all aliases of the argument registers are reset in the
+ // RegMask, including superregisters. Clearing only subregs_inclusive is
+ // insufficient: an i32 argument in R14D must also remove R14 from the
+ // preserved set, otherwise a live 64-bit value in R14 can be incorrectly
+ // kept across the call (see llvm/llvm-project#225057).
if (ShouldDisableArgRegs) {
for (auto const &RegPair : RegsToPass)
- for (MCPhysReg SubReg : TRI->subregs_inclusive(RegPair.first))
- RegMask[SubReg / 32] &= ~(1u << (SubReg % 32));
+ for (MCRegAliasIterator Alias(RegPair.first, TRI, true); Alias.isValid();
+ ++Alias)
+ RegMask[*Alias / 32] &= ~(1u << (*Alias % 32));
}
// Create the RegMask Operand according to our updated mask.
diff --git a/llvm/test/CodeGen/X86/regcall-subreg-argmask.ll b/llvm/test/CodeGen/X86/regcall-subreg-argmask.ll
new file mode 100644
index 0000000000000..0818435e91ebd
--- /dev/null
+++ b/llvm/test/CodeGen/X86/regcall-subreg-argmask.ll
@@ -0,0 +1,38 @@
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -O2 -stop-after=finalize-isel | FileCheck %s
+
+; When an x86_regcall argument or return value uses a 32-bit subregister (such
+; as R14D), the dynamic call-preserved mask must clear all aliases including the
+; 64-bit superregister (R14). Otherwise a live value in the superregister can be
+; incorrectly assumed preserved across the call.
+;
+; Fixes llvm/llvm-project#225057.
+
+%struct.R = type { i64, i64, i64, i64, i64, i64, i64, i64, i64, i32 }
+
+declare x86_regcallcc void @callee_arg(i64, i64, i64, i64, i64, i64, i64, i64, i64, i32)
+declare x86_regcallcc %struct.R @callee_ret()
+
+; In test_arg_subreg, %a9 is passed in R14D. R14 must be cleared from the call
+; preserved mask (CustomRegMask).
+define void @test_arg_subreg(i32 %arg) nounwind {
+; CHECK-LABEL: name: test_arg_subreg
+; CHECK: CALL64m {{.*}} CustomRegMask(
+; CHECK-NOT: $r14,
+; CHECK-SAME: ), {{.*}} implicit $r14d
+entry:
+ call x86_regcallcc void @callee_arg(i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i32 %arg)
+ ret void
+}
+
+; In test_ret_subreg, the 10th return value is returned in R14D. R14 must be
+; cleared from the call preserved mask (CustomRegMask).
+define i32 @test_ret_subreg() nounwind {
+; CHECK-LABEL: name: test_ret_subreg
+; CHECK: CALL64m {{.*}} CustomRegMask(
+; CHECK-NOT: $r14,
+; CHECK-SAME: ), {{.*}} implicit-def $r14d
+entry:
+ %ret = call x86_regcallcc %struct.R @callee_ret()
+ %val = extractvalue %struct.R %ret, 9
+ ret i32 %val
+}
>From 666b3454e26247597e8c58be0a32966ed0a8c100 Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Sat, 26 Sep 2026 21:14:23 -0300
Subject: [PATCH 2/3] Fix indentation in X86ISelLoweringCall.cpp
---
llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 70f6a3222ebbe..84415fa7828ca 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2690,8 +2690,8 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// kept across the call (see llvm/llvm-project#225057).
if (ShouldDisableArgRegs) {
for (auto const &RegPair : RegsToPass)
- for (MCRegAliasIterator Alias(RegPair.first, TRI, true); Alias.isValid();
- ++Alias)
+ for (MCRegAliasIterator Alias(RegPair.first, TRI, true);
+ Alias.isValid(); ++Alias)
RegMask[*Alias / 32] &= ~(1u << (*Alias % 32));
}
>From dc1da868e61550591416dbf19f5bfe0356182d3e Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Sat, 26 Sep 2026 21:21:05 -0300
Subject: [PATCH 3/3] Fix indentation and formatting in X86ISelLoweringCall.cpp
Indent fix
---
llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 84415fa7828ca..eff7c6817a11b 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2690,11 +2690,10 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// kept across the call (see llvm/llvm-project#225057).
if (ShouldDisableArgRegs) {
for (auto const &RegPair : RegsToPass)
- for (MCRegAliasIterator Alias(RegPair.first, TRI, true);
+ for (MCRegAliasIterator Alias(RegPair.first, TRI, true);
Alias.isValid(); ++Alias)
RegMask[*Alias / 32] &= ~(1u << (*Alias % 32));
}
-
// Create the RegMask Operand according to our updated mask.
Ops.push_back(DAG.getRegisterMask(RegMask));
} else {
More information about the llvm-commits
mailing list