Skip to content

Commit 9267fd0

Browse files
committed
[LoongArch] Ensure pcaddu18i and jirl adjacency in tail calls for correct relocation
Prior to this patch, both `pcaddu18i` and `jirl` were marked as scheduling boundaries to prevent instruction reordering that would disrupt their adjacency. However, in certain cases, epilogues were still being inserted between these two instructions, breaking the required proximity. This patch ensures that `pcaddu18i` and `jirl` remain adjacent even in the presence of epilogues, maintaining correct relocation behavior for tail calls on LoongArch.
1 parent 53f7f8e commit 9267fd0

File tree

4 files changed

+118
-38
lines changed

4 files changed

+118
-38
lines changed

llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,9 @@ bool LoongArchPreRAExpandPseudo::expandMI(
165165
case LoongArch::PseudoLA_TLS_DESC_LARGE:
166166
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
167167
case LoongArch::PseudoCALL:
168-
case LoongArch::PseudoCALL_MEDIUM:
169168
case LoongArch::PseudoCALL_LARGE:
170169
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
171170
case LoongArch::PseudoTAIL:
172-
case LoongArch::PseudoTAIL_MEDIUM:
173171
case LoongArch::PseudoTAIL_LARGE:
174172
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
175173
case LoongArch::PseudoBRIND:
@@ -556,31 +554,6 @@ bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
556554
CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);
557555
break;
558556
}
559-
case CodeModel::Medium: {
560-
// CALL:
561-
// pcaddu18i $ra, %call36(func)
562-
// jirl $ra, $ra, 0
563-
// TAIL:
564-
// pcaddu18i $scratch, %call36(func)
565-
// jirl $r0, $scratch, 0
566-
Opcode =
567-
IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
568-
Register ScratchReg =
569-
IsTailCall
570-
? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
571-
: LoongArch::R1;
572-
MachineInstrBuilder MIB =
573-
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
574-
575-
CALL =
576-
BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
577-
578-
if (Func.isSymbol())
579-
MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
580-
else
581-
MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
582-
break;
583-
}
584557
case CodeModel::Large: {
585558
// Emit the 5-insn large address load sequence, either directly or
586559
// indirectly in case of going through the GOT, then JIRL_TAIL or
@@ -671,6 +644,10 @@ class LoongArchExpandPseudo : public MachineFunctionPass {
671644
MachineBasicBlock::iterator &NextMBBI);
672645
bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
673646
MachineBasicBlock::iterator &NextMBBI);
647+
bool expandFunctionCALL(MachineBasicBlock &MBB,
648+
MachineBasicBlock::iterator MBBI,
649+
MachineBasicBlock::iterator &NextMBBI,
650+
bool IsTailCall);
674651
};
675652

676653
char LoongArchExpandPseudo::ID = 0;
@@ -705,6 +682,10 @@ bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
705682
switch (MBBI->getOpcode()) {
706683
case LoongArch::PseudoCopyCFR:
707684
return expandCopyCFR(MBB, MBBI, NextMBBI);
685+
case LoongArch::PseudoCALL_MEDIUM:
686+
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
687+
case LoongArch::PseudoTAIL_MEDIUM:
688+
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
708689
}
709690

710691
return false;
@@ -763,6 +744,54 @@ bool LoongArchExpandPseudo::expandCopyCFR(
763744
return true;
764745
}
765746

747+
bool LoongArchExpandPseudo::expandFunctionCALL(
748+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
749+
MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
750+
MachineFunction *MF = MBB.getParent();
751+
MachineInstr &MI = *MBBI;
752+
DebugLoc DL = MI.getDebugLoc();
753+
const MachineOperand &Func = MI.getOperand(0);
754+
MachineInstrBuilder CALL;
755+
unsigned Opcode;
756+
757+
switch (MF->getTarget().getCodeModel()) {
758+
default:
759+
report_fatal_error("Unsupported code model");
760+
break;
761+
case CodeModel::Medium: {
762+
// CALL:
763+
// pcaddu18i $ra, %call36(func)
764+
// jirl $ra, $ra, 0
765+
// TAIL:
766+
// pcaddu18i $t8, %call36(func)
767+
// jirl $r0, $t8, 0
768+
Opcode =
769+
IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
770+
Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
771+
MachineInstrBuilder MIB =
772+
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
773+
774+
CALL =
775+
BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
776+
777+
if (Func.isSymbol())
778+
MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
779+
else
780+
MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
781+
break;
782+
}
783+
}
784+
785+
// Transfer implicit operands.
786+
CALL.copyImplicitOps(MI);
787+
788+
// Transfer MI flags.
789+
CALL.setMIFlags(MI.getFlags());
790+
791+
MI.eraseFromParent();
792+
return true;
793+
}
794+
766795
} // end namespace
767796

768797
INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",

llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,6 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
391391
//
392392
// The following instruction patterns are prohibited from being reordered:
393393
//
394-
// * pcaddu18 $ra, %call36(s)
395-
// jirl $ra, $ra, 0
396-
//
397394
// * pcalau12i $a0, %pc_hi20(s)
398395
// addi.d $a1, $zero, %pc_lo12(s)
399396
// lu32i.d $a1, %pc64_lo20(s)
@@ -413,10 +410,6 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
413410
// boundaries, and the instructions between them are guaranteed to be
414411
// ordered according to data dependencies.
415412
switch (MI.getOpcode()) {
416-
case LoongArch::PCADDU18I:
417-
if (MI.getOperand(1).getTargetFlags() == LoongArchII::MO_CALL36)
418-
return true;
419-
break;
420413
case LoongArch::PCALAU12I: {
421414
auto AddI = std::next(MII);
422415
if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,7 +1484,7 @@ def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
14841484
def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
14851485

14861486
// Function call with 'Medium' code model.
1487-
let isCall = 1, Defs = [R1] in
1487+
let isCall = 1, Defs = [R1, R20] in
14881488
def PseudoCALL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$func)>;
14891489

14901490
let Predicates = [IsLA64] in {
@@ -1533,7 +1533,8 @@ def : Pat<(loongarch_tail (iPTR texternalsym:$dst)),
15331533
(PseudoTAIL texternalsym:$dst)>;
15341534

15351535
// Tail call with 'Medium' code model.
1536-
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1536+
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
1537+
Uses = [R3], Defs = [R20] in
15371538
def PseudoTAIL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$dst)>;
15381539

15391540
let Predicates = [IsLA64] in {

llvm/test/CodeGen/LoongArch/code-models.ll

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ define i32 @caller_tail(i32 %i) nounwind {
105105
;
106106
; MEDIUM-LABEL: caller_tail:
107107
; MEDIUM: # %bb.0: # %entry
108-
; MEDIUM-NEXT: pcaddu18i $a1, %call36(callee_tail)
109-
; MEDIUM-NEXT: jr $a1
108+
; MEDIUM-NEXT: pcaddu18i $t8, %call36(callee_tail)
109+
; MEDIUM-NEXT: jr $t8
110110
;
111111
; LARGE-LABEL: caller_tail:
112112
; LARGE: # %bb.0: # %entry
@@ -120,3 +120,60 @@ entry:
120120
%r = tail call i32 @callee_tail(i32 %i)
121121
ret i32 %r
122122
}
123+
124+
define i32 @caller_call_tail(i32 %i) nounwind {
125+
; SMALL-LABEL: caller_call_tail:
126+
; SMALL: # %bb.0: # %entry
127+
; SMALL-NEXT: addi.d $sp, $sp, -16
128+
; SMALL-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
129+
; SMALL-NEXT: st.d $fp, $sp, 0 # 8-byte Folded Spill
130+
; SMALL-NEXT: move $fp, $a0
131+
; SMALL-NEXT: bl %plt(callee_tail)
132+
; SMALL-NEXT: move $a0, $fp
133+
; SMALL-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload
134+
; SMALL-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
135+
; SMALL-NEXT: addi.d $sp, $sp, 16
136+
; SMALL-NEXT: b %plt(callee_tail)
137+
;
138+
; MEDIUM-LABEL: caller_call_tail:
139+
; MEDIUM: # %bb.0: # %entry
140+
; MEDIUM-NEXT: addi.d $sp, $sp, -16
141+
; MEDIUM-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
142+
; MEDIUM-NEXT: st.d $fp, $sp, 0 # 8-byte Folded Spill
143+
; MEDIUM-NEXT: move $fp, $a0
144+
; MEDIUM-NEXT: pcaddu18i $ra, %call36(callee_tail)
145+
; MEDIUM-NEXT: jirl $ra, $ra, 0
146+
; MEDIUM-NEXT: move $a0, $fp
147+
; MEDIUM-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload
148+
; MEDIUM-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
149+
; MEDIUM-NEXT: addi.d $sp, $sp, 16
150+
; MEDIUM-NEXT: pcaddu18i $t8, %call36(callee_tail)
151+
; MEDIUM-NEXT: jr $t8
152+
;
153+
; LARGE-LABEL: caller_call_tail:
154+
; LARGE: # %bb.0: # %entry
155+
; LARGE-NEXT: addi.d $sp, $sp, -16
156+
; LARGE-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
157+
; LARGE-NEXT: st.d $fp, $sp, 0 # 8-byte Folded Spill
158+
; LARGE-NEXT: move $fp, $a0
159+
; LARGE-NEXT: pcalau12i $a1, %got_pc_hi20(callee_tail)
160+
; LARGE-NEXT: addi.d $ra, $zero, %got_pc_lo12(callee_tail)
161+
; LARGE-NEXT: lu32i.d $ra, %got64_pc_lo20(callee_tail)
162+
; LARGE-NEXT: lu52i.d $ra, $ra, %got64_pc_hi12(callee_tail)
163+
; LARGE-NEXT: ldx.d $ra, $ra, $a1
164+
; LARGE-NEXT: jirl $ra, $ra, 0
165+
; LARGE-NEXT: move $a0, $fp
166+
; LARGE-NEXT: pcalau12i $a1, %got_pc_hi20(callee_tail)
167+
; LARGE-NEXT: addi.d $a2, $zero, %got_pc_lo12(callee_tail)
168+
; LARGE-NEXT: lu32i.d $a2, %got64_pc_lo20(callee_tail)
169+
; LARGE-NEXT: lu52i.d $a2, $a2, %got64_pc_hi12(callee_tail)
170+
; LARGE-NEXT: ldx.d $a1, $a2, $a1
171+
; LARGE-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload
172+
; LARGE-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
173+
; LARGE-NEXT: addi.d $sp, $sp, 16
174+
; LARGE-NEXT: jr $a1
175+
entry:
176+
call i32 @callee_tail(i32 %i)
177+
%r = tail call i32 @callee_tail(i32 %i)
178+
ret i32 %r
179+
}

0 commit comments

Comments
 (0)