[llvm] e202421 - [RISCV] Preserve call-preserved reg mask for LPAD-aligned calls (#210868)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 21 23:17:14 PDT 2026
Author: Jerry Zhang Jian
Date: 2026-07-22T14:17:10+08:00
New Revision: e20242130eeaa668e5c782643d4afed0b0ab2a6b
URL: https://github.com/llvm/llvm-project/commit/e20242130eeaa668e5c782643d4afed0b0ab2a6b
DIFF: https://github.com/llvm/llvm-project/commit/e20242130eeaa668e5c782643d4afed0b0ab2a6b.diff
LOG: [RISCV] Preserve call-preserved reg mask for LPAD-aligned calls (#210868)
RISCVISelDAGToDAG's lowering of RISCVISD::LPAD_CALL / LPAD_CALL_INDIRECT
to PseudoCALLLpadAlign / PseudoCALLIndirectLpadAlign (introduced in
#177515) only copied the callee, lpad label, chain, and glue operands,
dropping the argument-register and register-mask operands in between.
Without the register-mask operand, the register allocator treats these
calls as clobbering nothing but ra, so values live across the call are
not spilled/reloaded even though the callee is free to clobber
caller-saved registers. This caused a miscompile where a pointer held
live across a call to getcontext() (a returns_twice function) was
corrupted after the call returned, leading to a SIGSEGV in
llvm-test-suite's siod test.
Fix the operand copy to include the argument-register and register-mask
operands, matching the pseudo-instruction operands of a regular
PseudoCALL/PseudoCALLIndirect.
Signed-off-by: Jerry Zhang Jian <jerry.zhangjian at sifive.com>
Added:
llvm/test/CodeGen/RISCV/lpad-setjmp-regmask.ll
Modified:
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index ae341a3a78f7c..611306b6ab7b3 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3244,12 +3244,22 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
LpadLabel = PreferredLandingPadLabel;
}
- SmallVector<SDValue, 4> Ops;
+ // Preserve the argument-register and register-mask operands, between
+ // Callee and the optional glue, so the pseudo call still reports its
+ // call-preserved mask to the register allocator.
+ SmallVector<SDValue, 8> Ops;
Ops.push_back(Node->getOperand(1));
Ops.push_back(CurDAG->getTargetConstant(LpadLabel, DL, XLenVT));
+
+ unsigned NumOps = Node->getNumOperands();
+ bool HasGlue = Node->getGluedNode() != nullptr;
+ unsigned RegOperandsEnd = HasGlue ? NumOps - 1 : NumOps;
+ for (unsigned I = 2; I != RegOperandsEnd; ++I)
+ Ops.push_back(Node->getOperand(I));
+
Ops.push_back(Node->getOperand(0));
- if (Node->getGluedNode())
- Ops.push_back(Node->getOperand(Node->getNumOperands() - 1));
+ if (HasGlue)
+ Ops.push_back(Node->getOperand(NumOps - 1));
ReplaceNode(Node,
CurDAG->getMachineNode(PseudoOpc, DL, Node->getVTList(), Ops));
diff --git a/llvm/test/CodeGen/RISCV/lpad-setjmp-regmask.ll b/llvm/test/CodeGen/RISCV/lpad-setjmp-regmask.ll
new file mode 100644
index 0000000000000..15e1f783a73d0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/lpad-setjmp-regmask.ll
@@ -0,0 +1,35 @@
+; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=RV32
+; RUN: llc -mtriple=riscv64 -target-abi=lp64 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=RV64
+
+; PseudoCALLLpadAlign/PseudoCALLIndirectLpadAlign must carry the same
+; call-preserved register mask as PseudoCALL/PseudoCALLIndirect, otherwise
+; values live across a returns_twice call are not spilled/reloaded and get
+; corrupted when the callee clobbers them.
+
+declare i32 @setjmp(ptr) returns_twice
+declare void @use(ptr, ptr)
+
+define void @test_direct_call_preserved_mask(ptr %buf) {
+ ; RV32-LABEL: name: test_direct_call_preserved_mask
+ ; RV32: PseudoCALLLpadAlign target-flags(riscv-call) @setjmp, 0, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit-def $x2, implicit-def $x10
+ ; RV64-LABEL: name: test_direct_call_preserved_mask
+ ; RV64: PseudoCALLLpadAlign target-flags(riscv-call) @setjmp, 0, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit-def $x2, implicit-def $x10
+ %call = call i32 @setjmp(ptr %buf)
+ call void @use(ptr %buf, ptr %buf)
+ ret void
+}
+
+define void @test_indirect_call_preserved_mask(ptr %fptr, ptr %buf) {
+ ; RV32-LABEL: name: test_indirect_call_preserved_mask
+ ; RV32: PseudoCALLIndirectLpadAlign %{{[0-9]+}}, 0, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit-def $x2, implicit-def $x10
+ ; RV64-LABEL: name: test_indirect_call_preserved_mask
+ ; RV64: PseudoCALLIndirectLpadAlign %{{[0-9]+}}, 0, csr_ilp32_lp64, implicit-def dead $x1, implicit $x10, implicit-def $x2, implicit-def $x10
+ %call = call i32 %fptr(ptr %buf) #0
+ call void @use(ptr %buf, ptr %buf)
+ ret void
+}
+
+attributes #0 = { returns_twice }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
More information about the llvm-commits
mailing list