Skip to content

Commit 9f7af28

Browse files
authored
[llvm][LoongArch] Add call and tail macro instruction support (#175357)
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
1 parent 0f24d0f commit 9f7af28

File tree

8 files changed

+96
-44
lines changed

8 files changed

+96
-44
lines changed

llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,12 +1576,19 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
15761576
case LoongArch::PseudoLI_D:
15771577
emitLoadImm(Inst, IDLoc, Out);
15781578
return false;
1579+
case LoongArch::PseudoCALL:
1580+
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false,
1581+
/*IsCall36=*/is64Bit());
1582+
return false;
15791583
case LoongArch::PseudoCALL30:
15801584
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false, /*IsCall36=*/false);
15811585
return false;
15821586
case LoongArch::PseudoCALL36:
15831587
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false, /*IsCall36=*/true);
15841588
return false;
1589+
case LoongArch::PseudoTAIL:
1590+
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/true, /*IsCall36=*/is64Bit());
1591+
return false;
15851592
case LoongArch::PseudoTAIL30:
15861593
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/true, /*IsCall36=*/false);
15871594
return false;

llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,10 @@ bool LoongArchPreRAExpandPseudo::expandMI(
161161
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
162162
case LoongArch::PseudoLA_TLS_DESC_LARGE:
163163
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
164-
case LoongArch::PseudoCALL:
164+
case LoongArch::PseudoCALL_SMALL:
165165
case LoongArch::PseudoCALL_LARGE:
166166
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
167-
case LoongArch::PseudoTAIL:
167+
case LoongArch::PseudoTAIL_SMALL:
168168
case LoongArch::PseudoTAIL_LARGE:
169169
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
170170
case LoongArch::PseudoBRIND:
@@ -784,25 +784,36 @@ bool LoongArchExpandPseudo::expandFunctionCALL(
784784
report_fatal_error("Unexpected code model");
785785
break;
786786
case CodeModel::Medium: {
787+
// for la32 expands to:
787788
// CALL:
788-
// pcaddu18i $ra, %call36(func)
789-
// jirl $ra, $ra, 0
789+
// pcaddu12i $ra, %call30(func)
790+
// jirl $ra, $ra, 0
790791
// TAIL:
791-
// pcaddu18i $t8, %call36(func)
792-
// jirl $r0, $t8, 0
792+
// pcaddu12i $t8, %call30(func)
793+
// jirl $r0, $t8, 0
794+
//
795+
// for la64 expands to:
796+
// CALL:
797+
// pcaddu18i $ra, %call36(func)
798+
// jirl $ra, $ra, 0
799+
// TAIL:
800+
// pcaddu18i $t8, %call36(func)
801+
// jirl $r0, $t8, 0
793802
Opcode =
794803
IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
795804
Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
796-
MachineInstrBuilder MIB =
797-
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
805+
bool Is64Bit = MF->getSubtarget<LoongArchSubtarget>().is64Bit();
806+
unsigned PC = Is64Bit ? LoongArch::PCADDU18I : LoongArch::PCADDU12I;
807+
unsigned MO = Is64Bit ? LoongArchII::MO_CALL36 : LoongArchII::MO_CALL30;
808+
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(PC), ScratchReg);
798809

799810
CALL =
800811
BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
801812

802813
if (Func.isSymbol())
803-
MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
814+
MIB.addExternalSymbol(Func.getSymbolName(), MO);
804815
else
805-
MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
816+
MIB.addDisp(Func, 0, MO);
806817
break;
807818
}
808819
}

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8634,7 +8634,7 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
86348634

86358635
// If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
86368636
// TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
8637-
// split it and then direct call can be matched by PseudoCALL.
8637+
// split it and then direct call can be matched by PseudoCALL_SMALL.
86388638
if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
86398639
const GlobalValue *GV = S->getGlobal();
86408640
unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
@@ -8680,7 +8680,6 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
86808680
Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
86818681
break;
86828682
case CodeModel::Medium:
8683-
assert(Subtarget.is64Bit() && "Medium code model requires LA64");
86848683
Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
86858684
break;
86868685
case CodeModel::Large:

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ def SImm26OperandBL: AsmOperandClass {
515515
let ParserMethod = "parseSImm26Operand";
516516
}
517517

518-
// A symbol or an imm used in BL/PseudoCALL/PseudoTAIL.
518+
// A symbol or an imm used in BL/PseudoCALL_SMALL/PseudoTAIL_SMALL.
519519
def simm26_symbol : Operand<GRLenVT> {
520520
let ParserMatchClass = SImm26OperandBL;
521521
let EncoderMethod = "getImmOpValueAsr<2>";
@@ -1625,21 +1625,21 @@ def : Pat<(brind (add GPRJR:$rj, simm16_lsl2:$imm16)),
16251625

16261626
// Function call with 'Small' code model.
16271627
let isCall = 1, Defs = [R1] in
1628-
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func)>;
1628+
def PseudoCALL_SMALL : Pseudo<(outs), (ins bare_symbol:$func)>;
16291629

1630-
def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
1631-
def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
1630+
def : Pat<(loongarch_call tglobaladdr:$func),
1631+
(PseudoCALL_SMALL tglobaladdr:$func)>;
1632+
def : Pat<(loongarch_call texternalsym:$func),
1633+
(PseudoCALL_SMALL texternalsym:$func)>;
16321634

16331635
// Function call with 'Medium' code model.
16341636
let isCall = 1, Defs = [R1, R20], Size = 8 in
16351637
def PseudoCALL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$func)>;
16361638

1637-
let Predicates = [IsLA64] in {
16381639
def : Pat<(loongarch_call_medium tglobaladdr:$func),
16391640
(PseudoCALL_MEDIUM tglobaladdr:$func)>;
16401641
def : Pat<(loongarch_call_medium texternalsym:$func),
16411642
(PseudoCALL_MEDIUM texternalsym:$func)>;
1642-
} // Predicates = [IsLA64]
16431643

16441644
// Function call with 'Large' code model.
16451645
let isCall = 1, Defs = [R1] in
@@ -1656,10 +1656,9 @@ let isCall = 1, Defs = [R1] in
16561656
def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rj),
16571657
[(loongarch_call GPR:$rj)]>,
16581658
PseudoInstExpansion<(JIRL R1, GPR:$rj, 0)>;
1659-
let Predicates = [IsLA64] in {
16601659
def : Pat<(loongarch_call_medium GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
1660+
let Predicates = [IsLA64] in
16611661
def : Pat<(loongarch_call_large GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
1662-
}
16631662

16641663
let isCall = 1, hasSideEffects = 0, mayStore = 0, mayLoad = 0, Defs = [R1] in
16651664
def PseudoJIRL_CALL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
@@ -1672,24 +1671,22 @@ def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
16721671

16731672
// Tail call with 'Small' code model.
16741673
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1675-
def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst)>;
1674+
def PseudoTAIL_SMALL : Pseudo<(outs), (ins bare_symbol:$dst)>;
16761675

16771676
def : Pat<(loongarch_tail (iPTR tglobaladdr:$dst)),
1678-
(PseudoTAIL tglobaladdr:$dst)>;
1677+
(PseudoTAIL_SMALL tglobaladdr:$dst)>;
16791678
def : Pat<(loongarch_tail (iPTR texternalsym:$dst)),
1680-
(PseudoTAIL texternalsym:$dst)>;
1679+
(PseudoTAIL_SMALL texternalsym:$dst)>;
16811680

16821681
// Tail call with 'Medium' code model.
16831682
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
16841683
Uses = [R3], Defs = [R20], Size = 8 in
16851684
def PseudoTAIL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$dst)>;
16861685

1687-
let Predicates = [IsLA64] in {
16881686
def : Pat<(loongarch_tail_medium (iPTR tglobaladdr:$dst)),
16891687
(PseudoTAIL_MEDIUM tglobaladdr:$dst)>;
16901688
def : Pat<(loongarch_tail_medium (iPTR texternalsym:$dst)),
16911689
(PseudoTAIL_MEDIUM texternalsym:$dst)>;
1692-
} // Predicates = [IsLA64]
16931690

16941691
// Tail call with 'Large' code model.
16951692
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
@@ -1706,10 +1703,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
17061703
def PseudoTAILIndirect : Pseudo<(outs), (ins GPRT:$rj),
17071704
[(loongarch_tail GPRT:$rj)]>,
17081705
PseudoInstExpansion<(JIRL R0, GPR:$rj, 0)>;
1709-
let Predicates = [IsLA64] in {
17101706
def : Pat<(loongarch_tail_medium GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
1707+
let Predicates = [IsLA64] in
17111708
def : Pat<(loongarch_tail_large GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
1712-
}
17131709

17141710
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
17151711
hasSideEffects = 0, mayStore = 0, mayLoad = 0, Uses = [R3] in
@@ -1722,6 +1718,16 @@ def PseudoJIRL_TAIL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
17221718
PseudoInstExpansion<(JIRL R0, GPR:$rj,
17231719
simm16_lsl2:$imm16)>;
17241720

1721+
/// call/tail macro instructions
1722+
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
1723+
Defs = [R1], hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
1724+
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$dst), [], "call", "$dst">;
1725+
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3],
1726+
isCodeGenOnly = 0, isAsmParserOnly = 1, hasSideEffects = 0,
1727+
mayStore = 0, mayLoad = 0 in
1728+
def PseudoTAIL : Pseudo<(outs), (ins GPR:$tmp, bare_symbol:$dst), [],
1729+
"tail", "$tmp, $dst">;
1730+
17251731
/// call30/tail30 macro instructions
17261732
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
17271733
Defs = [R1], hasSideEffects = 0, mayStore = 0, mayLoad = 0 in

llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ static bool isSignExtendedW(Register SrcReg, const LoongArchSubtarget &ST,
561561
if (CopySrcReg == LoongArch::R4) {
562562
// For a method return value, we check the ZExt/SExt flags in attribute.
563563
// We assume the following code sequence for method call.
564-
// PseudoCALL @bar, ...
564+
// PseudoCALL_SMALL @bar, ...
565565
// ADJCALLSTACKUP 0, 0, implicit-def dead $r3, implicit $r3
566566
// %0:gpr = COPY $r4
567567
//

llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ getEffectiveLoongArchCodeModel(const Triple &TT,
7979

8080
switch (*CM) {
8181
case CodeModel::Small:
82-
return *CM;
8382
case CodeModel::Medium:
83+
return *CM;
8484
case CodeModel::Large:
8585
if (!TT.isArch64Bit())
86-
report_fatal_error("Medium/Large code model requires LA64");
86+
report_fatal_error("Large code model requires LA64");
8787
return *CM;
8888
default:
8989
report_fatal_error(

llvm/test/CodeGen/LoongArch/expand-call.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ declare void @callee()
77

88
define void @caller() nounwind {
99
; NOEXPAND-LABEL: name: caller
10-
; NOEXPAND: PseudoCALL target-flags{{.*}}callee
10+
; NOEXPAND: PseudoCALL_SMALL target-flags{{.*}}callee
1111
;
1212
; EXPAND-LABEL: name: caller
1313
; EXPAND: BL target-flags{{.*}}callee
Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
1-
# RUN: llvm-mc --triple=loongarch64 %s | FileCheck %s
2-
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t
3-
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
4-
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.relax
5-
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX
1+
# RUN: llvm-mc --triple=loongarch32 %s | FileCheck %s --check-prefixes=CHECK,LA32
2+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=-relax %s -o %t
3+
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefixes=RELOC,LA32-RELOC
4+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.relax
5+
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX,LA32-RELOC
6+
# RUN: llvm-mc --triple=loongarch64 %s --defsym=LA64=1 | FileCheck %s --check-prefixes=CHECK,LA64
7+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t --defsym=LA64=1
8+
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefixes=RELOC,LA64-RELOC
9+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.relax --defsym=LA64=1
10+
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX,LA64-RELOC,LA64-RELAX
611

712
# RELOC: Relocations [
813
# RELOC-NEXT: Section ({{.*}}) .rela.text {
914

15+
call sym_call
16+
# LA32: pcaddu12i $ra, %call30(sym_call)
17+
# LA32-NEXT: jirl $ra, $ra, 0
18+
# LA64: pcaddu18i $ra, %call36(sym_call)
19+
# LA64-NEXT: jirl $ra, $ra, 0
20+
21+
# LA32-RELOC-NEXT: R_LARCH_CALL30 sym_call 0x0
22+
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
23+
# RELAX-NEXT: R_LARCH_RELAX - 0x0
24+
25+
tail $t0, sym_tail
26+
# LA32: pcaddu12i $t0, %call30(sym_tail)
27+
# LA32-NEXT: jr $t0
28+
# LA64: pcaddu18i $t0, %call36(sym_tail)
29+
# LA64-NEXT: jr $t0
30+
31+
# LA32-RELOC-NEXT: R_LARCH_CALL30 sym_tail 0x0
32+
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
33+
# RELAX-NEXT: R_LARCH_RELAX - 0x0
34+
1035
call30 sym_call
1136
# CHECK: pcaddu12i $ra, %call30(sym_call)
1237
# CHECK-NEXT: jirl $ra, $ra, 0
@@ -21,19 +46,23 @@ tail30 $t0, sym_tail
2146
# RELOC-NEXT: R_LARCH_CALL30 sym_tail 0x0
2247
# RELAX-NEXT: R_LARCH_RELAX - 0x0
2348

49+
.ifdef LA64
50+
2451
call36 sym_call
25-
# CHECK: pcaddu18i $ra, %call36(sym_call)
26-
# CHECK-NEXT: jirl $ra, $ra, 0
52+
# LA64: pcaddu18i $ra, %call36(sym_call)
53+
# LA64-NEXT: jirl $ra, $ra, 0
2754

28-
# RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
29-
# RELAX-NEXT: R_LARCH_RELAX - 0x0
55+
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
56+
# LA64-RELAX-NEXT: R_LARCH_RELAX - 0x0
3057

3158
tail36 $t0, sym_tail
32-
# CHECK: pcaddu18i $t0, %call36(sym_tail)
33-
# CHECK-NEXT: jr $t0
59+
# LA64: pcaddu18i $t0, %call36(sym_tail)
60+
# LA64-NEXT: jr $t0
3461

35-
# RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
36-
# RELAX-NEXT: R_LARCH_RELAX - 0x0
62+
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
63+
# LA64-RELAX-NEXT: R_LARCH_RELAX - 0x0
64+
65+
.endif
3766

3867
# RELOC-NEXT: }
3968
# RELOC-NEXT: ]

0 commit comments

Comments
 (0)