[llvm] [SPARC] Prevent RESTORE from sourcing from %o7 in call delay slots (PR #172593)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 30 22:47:09 PST 2025
https://github.com/koachan updated https://github.com/llvm/llvm-project/pull/172593
>From 8d1dc1d6bd0659bd509e863f7a741e46d9859aff Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 17 Dec 2025 08:48:44 +0700
Subject: [PATCH 1/4] [SPARC] Prevent RESTORE from sourcing from %o7 in call
delay slots
Combining instructions that reads from %o7 with a RESTORE in call delay slots
will result in a RESTORE instruction that reads from %o7, which has been
overwritten by the call instruction, resulting in junk values being produced.
This should fix the issue with `test-suite::lencod.test`.
---
llvm/lib/Target/Sparc/DelaySlotFiller.cpp | 49 ++++++--
llvm/lib/Target/Sparc/SparcInstrInfo.td | 4 +-
.../CodeGen/SPARC/2011-01-19-DelaySlot.ll | 111 ++++++++++++++----
3 files changed, 133 insertions(+), 31 deletions(-)
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index 024030d196ee3..c8caf7dffad2a 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -390,10 +390,10 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
return true;
}
-static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
+static bool combineRestoreADD(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator RestoreMI,
MachineBasicBlock::iterator AddMI,
- const TargetInstrInfo *TII)
-{
+ const TargetInstrInfo *TII) {
// Before: add <op0>, <op1>, %i[0-7]
// restore %g0, %g0, %i[0-7]
//
@@ -403,6 +403,21 @@ static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
if (reg < SP::I0 || reg > SP::I7)
return false;
+ // Check whether it uses %o7 as its source and the corresponding branch
+ // instruction is a call.
+ MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
+ bool IsCall = LastInst != MBB.end() && LastInst->isCall();
+
+ // Check whether it uses %o7 as its source.
+ if (IsCall && AddMI->getOpcode() == SP::ADDrr &&
+ (AddMI->getOperand(1).getReg() == SP::O7 ||
+ AddMI->getOperand(2).getReg() == SP::O7))
+ return false;
+
+ if (IsCall && AddMI->getOpcode() == SP::ADDri &&
+ AddMI->getOperand(1).getReg() == SP::O7)
+ return false;
+
// Erase RESTORE.
RestoreMI->eraseFromParent();
@@ -417,10 +432,10 @@ static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
return true;
}
-static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
+static bool combineRestoreOR(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator RestoreMI,
MachineBasicBlock::iterator OrMI,
- const TargetInstrInfo *TII)
-{
+ const TargetInstrInfo *TII) {
// Before: or <op0>, <op1>, %i[0-7]
// restore %g0, %g0, %i[0-7]
// and <op0> or <op1> is zero,
@@ -442,6 +457,20 @@ static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
&& (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
return false;
+ // Check whether it uses %o7 as its source and the corresponding branch
+ // instruction is a call.
+ MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
+ bool IsCall = LastInst != MBB.end() && LastInst->isCall();
+
+ if (IsCall && OrMI->getOpcode() == SP::ORrr &&
+ (OrMI->getOperand(1).getReg() == SP::O7 ||
+ OrMI->getOperand(2).getReg() == SP::O7))
+ return false;
+
+ if (IsCall && OrMI->getOpcode() == SP::ORrr &&
+ OrMI->getOperand(1).getReg() == SP::O7)
+ return false;
+
// Erase RESTORE.
RestoreMI->eraseFromParent();
@@ -520,9 +549,13 @@ bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
switch (PrevInst->getOpcode()) {
default: break;
case SP::ADDrr:
- case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
+ case SP::ADDri:
+ return combineRestoreADD(MBB, MBBI, PrevInst, TII);
+ break;
case SP::ORrr:
- case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break;
+ case SP::ORri:
+ return combineRestoreOR(MBB, MBBI, PrevInst, TII);
+ break;
case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
}
// It cannot combine with the previous instruction.
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index 107817fcab6df..c08599402daa8 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -1589,7 +1589,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
// Instructions for tail calls.
//===----------------------------------------------------------------------===//
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1,
- isTerminator = 1, isBarrier = 1 in {
+ isTerminator = 1, isBarrier = 1, isCall = 1 in {
def TAIL_CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops),
"call $disp",
[(tailcall tglobaladdr:$disp)]> {
@@ -1603,7 +1603,7 @@ def : Pat<(tailcall (iPTR texternalsym:$dst)),
(TAIL_CALL texternalsym:$dst)>;
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
- isBarrier = 1, rd = 0 in {
+ isBarrier = 1, isCall = 1, rd = 0 in {
def TAIL_CALLri : F3_2<2, 0b111000,
(outs), (ins (MEMri $rs1, $simm13):$addr, variable_ops),
"jmp $addr",
diff --git a/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll b/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
index 4a15e35e718fd..518020bc9ca3a 100644
--- a/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
+++ b/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
@@ -250,6 +250,75 @@ entry:
ret i32 %3
}
+define i32 @prevent_o7_in_restore_add_in_call_delay_slot(i32 %i0) #0 {
+; CHECK-LABEL: prevent_o7_in_restore_add_in_call_delay_slot:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: add %i0, 2, %o5
+; CHECK-NEXT: add %i0, 3, %o7
+; CHECK-NEXT: !APP
+; CHECK-NEXT: !NO_APP
+; CHECK-NEXT: add %o5, %o7, %i0
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore
+;
+; UNOPT-LABEL: prevent_o7_in_restore_add_in_call_delay_slot:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -104, %sp
+; UNOPT-NEXT: add %i0, 2, %o5
+; UNOPT-NEXT: st %o5, [%fp+-4] ! 4-byte Folded Spill
+; UNOPT-NEXT: add %i0, 3, %o7
+; UNOPT-NEXT: st %o7, [%fp+-8] ! 4-byte Folded Spill
+; UNOPT-NEXT: !APP
+; UNOPT-NEXT: !NO_APP
+; UNOPT-NEXT: ld [%fp+-8], %i1 ! 4-byte Folded Reload
+; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload
+; UNOPT-NEXT: add %i0, %i1, %i0
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore
+entry:
+ %0 = add nsw i32 %i0, 2
+ %1 = add nsw i32 %i0, 3
+ tail call void asm sideeffect "", "r,r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0, i32 %1)
+ %2 = add nsw i32 %0, %1
+ %3 = tail call i32 @bar(i32 %2)
+ ret i32 %2
+}
+
+define i32 @prevent_o7_in_restore_or_in_call_delay_slot(i32 %i0) #0 {
+; CHECK-LABEL: prevent_o7_in_restore_or_in_call_delay_slot:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: add %i0, 2, %o7
+; CHECK-NEXT: !APP
+; CHECK-NEXT: !NO_APP
+; CHECK-NEXT: mov %o7, %o0
+; CHECK-NEXT: call bar
+; CHECK-NEXT: nop
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: prevent_o7_in_restore_or_in_call_delay_slot:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: add %i0, 2, %o7
+; UNOPT-NEXT: st %o7, [%fp+-4] ! 4-byte Folded Spill
+; UNOPT-NEXT: !APP
+; UNOPT-NEXT: !NO_APP
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: ld [%fp+-4], %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
+entry:
+ %0 = add nsw i32 %i0, 2
+ tail call void asm sideeffect "", "r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0)
+ %1 = tail call i32 @bar(i32 %0)
+ ret i32 %1
+}
declare i32 @func(ptr)
@@ -379,12 +448,12 @@ define i32 @restore_sethi(i32 %a) {
; CHECK-NEXT: call bar
; CHECK-NEXT: mov %i0, %o0
; CHECK-NEXT: cmp %o0, 0
-; CHECK-NEXT: bne .LBB10_2
+; CHECK-NEXT: bne .LBB12_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %entry
; CHECK-NEXT: ret
; CHECK-NEXT: restore %g0, %g0, %o0
-; CHECK-NEXT: .LBB10_2:
+; CHECK-NEXT: .LBB12_2:
; CHECK-NEXT: ret
; CHECK-NEXT: restore %g0, 3072, %o0
;
@@ -401,12 +470,12 @@ define i32 @restore_sethi(i32 %a) {
; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill
; UNOPT-NEXT: sethi 3, %i0
; UNOPT-NEXT: cmp %o0, 0
-; UNOPT-NEXT: bne .LBB10_2
+; UNOPT-NEXT: bne .LBB12_2
; UNOPT-NEXT: st %i0, [%fp+-4]
; UNOPT-NEXT: ! %bb.1: ! %entry
; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill
-; UNOPT-NEXT: .LBB10_2: ! %entry
+; UNOPT-NEXT: .LBB12_2: ! %entry
; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: ret
; UNOPT-NEXT: restore
@@ -428,12 +497,12 @@ define i32 @restore_sethi_3bit(i32 %a) {
; CHECK-NEXT: call bar
; CHECK-NEXT: mov %i0, %o0
; CHECK-NEXT: cmp %o0, 0
-; CHECK-NEXT: bne .LBB11_2
+; CHECK-NEXT: bne .LBB13_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %entry
; CHECK-NEXT: ret
; CHECK-NEXT: restore %g0, %g0, %o0
-; CHECK-NEXT: .LBB11_2:
+; CHECK-NEXT: .LBB13_2:
; CHECK-NEXT: sethi 6, %i0
; CHECK-NEXT: ret
; CHECK-NEXT: restore
@@ -451,12 +520,12 @@ define i32 @restore_sethi_3bit(i32 %a) {
; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill
; UNOPT-NEXT: sethi 6, %i0
; UNOPT-NEXT: cmp %o0, 0
-; UNOPT-NEXT: bne .LBB11_2
+; UNOPT-NEXT: bne .LBB13_2
; UNOPT-NEXT: st %i0, [%fp+-4]
; UNOPT-NEXT: ! %bb.1: ! %entry
; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill
-; UNOPT-NEXT: .LBB11_2: ! %entry
+; UNOPT-NEXT: .LBB13_2: ! %entry
; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: ret
; UNOPT-NEXT: restore
@@ -478,12 +547,12 @@ define i32 @restore_sethi_large(i32 %a) {
; CHECK-NEXT: call bar
; CHECK-NEXT: mov %i0, %o0
; CHECK-NEXT: cmp %o0, 0
-; CHECK-NEXT: bne .LBB12_2
+; CHECK-NEXT: bne .LBB14_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %entry
; CHECK-NEXT: ret
; CHECK-NEXT: restore %g0, %g0, %o0
-; CHECK-NEXT: .LBB12_2:
+; CHECK-NEXT: .LBB14_2:
; CHECK-NEXT: sethi 4000, %i0
; CHECK-NEXT: ret
; CHECK-NEXT: restore
@@ -501,12 +570,12 @@ define i32 @restore_sethi_large(i32 %a) {
; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill
; UNOPT-NEXT: sethi 4000, %i0
; UNOPT-NEXT: cmp %o0, 0
-; UNOPT-NEXT: bne .LBB12_2
+; UNOPT-NEXT: bne .LBB14_2
; UNOPT-NEXT: st %i0, [%fp+-4]
; UNOPT-NEXT: ! %bb.1: ! %entry
; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill
-; UNOPT-NEXT: .LBB12_2: ! %entry
+; UNOPT-NEXT: .LBB14_2: ! %entry
; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: ret
; UNOPT-NEXT: restore
@@ -525,14 +594,14 @@ define i32 @test_generic_inst(i32 %arg) #0 {
; CHECK-NEXT: mov %i0, %o0
; CHECK-NEXT: andcc %o0, 1, %g0
; CHECK-NEXT: ! fake_use: $i0
-; CHECK-NEXT: bne .LBB13_2
+; CHECK-NEXT: bne .LBB15_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %true
; CHECK-NEXT: call bar
; CHECK-NEXT: nop
; CHECK-NEXT: ret
; CHECK-NEXT: restore %g0, %o0, %o0
-; CHECK-NEXT: .LBB13_2: ! %false
+; CHECK-NEXT: .LBB15_2: ! %false
; CHECK-NEXT: ret
; CHECK-NEXT: restore %o0, 1, %o0
;
@@ -547,21 +616,21 @@ define i32 @test_generic_inst(i32 %arg) #0 {
; UNOPT-NEXT: and %o0, 1, %i0
; UNOPT-NEXT: ! fake_use: $i1
; UNOPT-NEXT: cmp %i0, 0
-; UNOPT-NEXT: bne .LBB13_2
+; UNOPT-NEXT: bne .LBB15_2
; UNOPT-NEXT: nop
-; UNOPT-NEXT: ba .LBB13_1
+; UNOPT-NEXT: ba .LBB15_1
; UNOPT-NEXT: nop
-; UNOPT-NEXT: .LBB13_1: ! %true
+; UNOPT-NEXT: .LBB15_1: ! %true
; UNOPT-NEXT: call bar
; UNOPT-NEXT: ld [%fp+-4], %o0
-; UNOPT-NEXT: ba .LBB13_3
+; UNOPT-NEXT: ba .LBB15_3
; UNOPT-NEXT: st %o0, [%fp+-8]
-; UNOPT-NEXT: .LBB13_2: ! %false
+; UNOPT-NEXT: .LBB15_2: ! %false
; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: add %i0, 1, %i0
-; UNOPT-NEXT: ba .LBB13_3
+; UNOPT-NEXT: ba .LBB15_3
; UNOPT-NEXT: st %i0, [%fp+-8]
-; UNOPT-NEXT: .LBB13_3: ! %cont
+; UNOPT-NEXT: .LBB15_3: ! %cont
; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload
; UNOPT-NEXT: ret
; UNOPT-NEXT: restore
>From ff997f741afdffab80d40dea9d308722107ddc89 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 17 Dec 2025 11:37:42 +0700
Subject: [PATCH 2/4] Update tail call handling
---
llvm/lib/Target/Sparc/DelaySlotFiller.cpp | 12 +++++++++---
llvm/lib/Target/Sparc/SparcInstrInfo.td | 4 ++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index c8caf7dffad2a..7549966ed7e92 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -11,6 +11,7 @@
// NOP is placed.
//===----------------------------------------------------------------------===//
+#include "MCTargetDesc/SparcMCTargetDesc.h"
#include "Sparc.h"
#include "SparcSubtarget.h"
#include "llvm/ADT/SmallSet.h"
@@ -406,9 +407,11 @@ static bool combineRestoreADD(MachineBasicBlock &MBB,
// Check whether it uses %o7 as its source and the corresponding branch
// instruction is a call.
MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
- bool IsCall = LastInst != MBB.end() && LastInst->isCall();
+ unsigned CallOpc = LastInst->getOpcode();
+ bool IsCall = LastInst != MBB.end() &&
+ (LastInst->isCall() || CallOpc == SP::TAIL_CALL ||
+ CallOpc == SP::TAIL_CALLri);
- // Check whether it uses %o7 as its source.
if (IsCall && AddMI->getOpcode() == SP::ADDrr &&
(AddMI->getOperand(1).getReg() == SP::O7 ||
AddMI->getOperand(2).getReg() == SP::O7))
@@ -460,7 +463,10 @@ static bool combineRestoreOR(MachineBasicBlock &MBB,
// Check whether it uses %o7 as its source and the corresponding branch
// instruction is a call.
MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
- bool IsCall = LastInst != MBB.end() && LastInst->isCall();
+ unsigned CallOpc = LastInst->getOpcode();
+ bool IsCall = LastInst != MBB.end() &&
+ (LastInst->isCall() || CallOpc == SP::TAIL_CALL ||
+ CallOpc == SP::TAIL_CALLri);
if (IsCall && OrMI->getOpcode() == SP::ORrr &&
(OrMI->getOperand(1).getReg() == SP::O7 ||
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index c08599402daa8..107817fcab6df 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -1589,7 +1589,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
// Instructions for tail calls.
//===----------------------------------------------------------------------===//
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1,
- isTerminator = 1, isBarrier = 1, isCall = 1 in {
+ isTerminator = 1, isBarrier = 1 in {
def TAIL_CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops),
"call $disp",
[(tailcall tglobaladdr:$disp)]> {
@@ -1603,7 +1603,7 @@ def : Pat<(tailcall (iPTR texternalsym:$dst)),
(TAIL_CALL texternalsym:$dst)>;
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
- isBarrier = 1, isCall = 1, rd = 0 in {
+ isBarrier = 1, rd = 0 in {
def TAIL_CALLri : F3_2<2, 0b111000,
(outs), (ins (MEMri $rs1, $simm13):$addr, variable_ops),
"jmp $addr",
>From 48b4b7bb8f1c1c656d0258994c6b4e5095a8e3dd Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 17 Dec 2025 18:20:21 +0700
Subject: [PATCH 3/4] Remove stray include
---
llvm/lib/Target/Sparc/DelaySlotFiller.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index 7549966ed7e92..67a19a9fde7f7 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -11,7 +11,6 @@
// NOP is placed.
//===----------------------------------------------------------------------===//
-#include "MCTargetDesc/SparcMCTargetDesc.h"
#include "Sparc.h"
#include "SparcSubtarget.h"
#include "llvm/ADT/SmallSet.h"
>From 2704962fb4e67b1f9bb2fab82027046c66b69550 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 17 Dec 2025 19:25:35 +0700
Subject: [PATCH 4/4] Rework tail call handling
---
llvm/lib/Target/Sparc/DelaySlotFiller.cpp | 21 ++++++++++-----------
llvm/lib/Target/Sparc/SparcInstrInfo.td | 8 ++++----
2 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index 67a19a9fde7f7..a211cf1088b51 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -303,15 +303,20 @@ void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses)
{
- // Call defines o7, which is visible to the instruction in delay slot.
- RegDefs.insert(SP::O7);
-
+ // Regular calls define o7, which is visible to the instruction in delay slot.
+ // On the other hand, tail calls preserve it.
switch(MI->getOpcode()) {
default: llvm_unreachable("Unknown opcode.");
case SP::CALL:
+ RegDefs.insert(SP::O7);
+ break;
+ case SP::TAIL_CALL:
break;
case SP::CALLrr:
case SP::CALLri:
+ RegDefs.insert(SP::O7);
+ [[fallthrough]];
+ case SP::TAIL_CALLri:
assert(MI->getNumOperands() >= 2);
const MachineOperand &Reg = MI->getOperand(0);
assert(Reg.isReg() && "CALL first operand is not a register.");
@@ -406,10 +411,7 @@ static bool combineRestoreADD(MachineBasicBlock &MBB,
// Check whether it uses %o7 as its source and the corresponding branch
// instruction is a call.
MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
- unsigned CallOpc = LastInst->getOpcode();
- bool IsCall = LastInst != MBB.end() &&
- (LastInst->isCall() || CallOpc == SP::TAIL_CALL ||
- CallOpc == SP::TAIL_CALLri);
+ bool IsCall = LastInst != MBB.end() && LastInst->isCall();
if (IsCall && AddMI->getOpcode() == SP::ADDrr &&
(AddMI->getOperand(1).getReg() == SP::O7 ||
@@ -462,10 +464,7 @@ static bool combineRestoreOR(MachineBasicBlock &MBB,
// Check whether it uses %o7 as its source and the corresponding branch
// instruction is a call.
MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator();
- unsigned CallOpc = LastInst->getOpcode();
- bool IsCall = LastInst != MBB.end() &&
- (LastInst->isCall() || CallOpc == SP::TAIL_CALL ||
- CallOpc == SP::TAIL_CALLri);
+ bool IsCall = LastInst != MBB.end() && LastInst->isCall();
if (IsCall && OrMI->getOpcode() == SP::ORrr &&
(OrMI->getOperand(1).getReg() == SP::O7 ||
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index 107817fcab6df..5b738deeb22d5 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -1588,8 +1588,8 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
//===----------------------------------------------------------------------===//
// Instructions for tail calls.
//===----------------------------------------------------------------------===//
-let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1,
- isTerminator = 1, isBarrier = 1 in {
+let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
+ isBarrier = 1, isCall = 1 in {
def TAIL_CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops),
"call $disp",
[(tailcall tglobaladdr:$disp)]> {
@@ -1602,8 +1602,8 @@ let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1,
def : Pat<(tailcall (iPTR texternalsym:$dst)),
(TAIL_CALL texternalsym:$dst)>;
-let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
- isBarrier = 1, rd = 0 in {
+let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
+ isBarrier = 1, isCall = 1, rd = 0 in {
def TAIL_CALLri : F3_2<2, 0b111000,
(outs), (ins (MEMri $rs1, $simm13):$addr, variable_ops),
"jmp $addr",
More information about the llvm-commits
mailing list