[llvm] [SPARC] Prevent RESTORE from consuming an indirect call's target (PR #228198)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 11:55:50 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-sparc
Author: Imre Kaloz (kaloz)
<details>
<summary>Changes</summary>
Folding an ADD into a RESTORE in a call delay slot moves the addition
into the register window switch, so its destination is no longer
written before the call. An indirect tail call jumps through that
register, so the jump reads only the ADD's first operand and calls
base instead of base + offset; the correct sum lands in an out
register nothing reads.
Keep the ADD when the terminator's target register is the one it
writes. A direct call names its callee instead, so the folded sum, an
outgoing argument, still combines.
Signed-off-by: Imre Kaloz <kaloz@<!-- -->kernel.org>
---
Full diff: https://github.com/llvm/llvm-project/pull/228198.diff
2 Files Affected:
- (modified) llvm/lib/Target/Sparc/DelaySlotFiller.cpp (+9)
- (added) llvm/test/CodeGen/SPARC/tailcall-restore-fold.ll (+21)
``````````diff
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index c60b78fcecaf5..d5d6d57c700c9 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -393,6 +393,15 @@ static bool combineRestoreADD(MachineBasicBlock &MBB,
AddMI->readsRegister(SP::O7, TRI))
return false;
+ // An indirect tail call jumps through the register in its first operand. If
+ // this ADD computes that address, folding it into the RESTORE leaves the jump
+ // reading only the ADD's first operand, silently calling base instead of
+ // base + offset. A direct call names its callee here instead, and the folded
+ // sum is an outgoing argument.
+ if (IsCall && LastInst->getOperand(0).isReg() &&
+ LastInst->getOperand(0).getReg() == reg)
+ return false;
+
// Erase RESTORE.
RestoreMI->eraseFromParent();
diff --git a/llvm/test/CodeGen/SPARC/tailcall-restore-fold.ll b/llvm/test/CodeGen/SPARC/tailcall-restore-fold.ll
new file mode 100644
index 0000000000000..d4e24858f039d
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/tailcall-restore-fold.ll
@@ -0,0 +1,21 @@
+; RUN: llc -mtriple=sparc64 < %s | FileCheck %s
+
+;; DelaySlotFiller folds `add a, b, %iN; restore %g0, %g0, %g0` into
+;; `restore a, b, %oN`. When %iN is the target of an indirect tail call the
+;; fold must not happen: the jump would read only the ADD's first operand and
+;; call base instead of base + offset, with the sum computed into an out
+;; register nothing reads.
+
+declare void @clobber()
+
+define void @tailcall_computed_target(ptr %base, i64 %off) nounwind {
+; CHECK-LABEL: tailcall_computed_target:
+; CHECK: add %i0, %i1, %[[T:i[0-7]]]
+; CHECK-NEXT: jmp %[[T]]
+; CHECK-NEXT: restore{{$}}
+entry:
+ call void @clobber()
+ %tp = getelementptr i8, ptr %base, i64 %off
+ tail call void %tp()
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/228198
More information about the llvm-commits
mailing list