[llvm][LoongArch] Add call and tail macro instruction support (#175357)

Link:
https://sourceware.org/pipermail/binutils/2025-December/146091.html
This commit is contained in:
hev 2026-01-14 07:49:16 +08:00 committed by GitHub
parent 0f24d0fb6c
commit 9f7af28972
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 97 additions and 45 deletions

View File

@ -1576,12 +1576,19 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case LoongArch::PseudoLI_D:
emitLoadImm(Inst, IDLoc, Out);
return false;
case LoongArch::PseudoCALL:
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false,
/*IsCall36=*/is64Bit());
return false;
case LoongArch::PseudoCALL30:
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false, /*IsCall36=*/false);
return false;
case LoongArch::PseudoCALL36:
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/false, /*IsCall36=*/true);
return false;
case LoongArch::PseudoTAIL:
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/true, /*IsCall36=*/is64Bit());
return false;
case LoongArch::PseudoTAIL30:
emitFuncCall(Inst, IDLoc, Out, /*IsTailCall=*/true, /*IsCall36=*/false);
return false;

View File

@ -161,10 +161,10 @@ bool LoongArchPreRAExpandPseudo::expandMI(
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
case LoongArch::PseudoLA_TLS_DESC_LARGE:
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
case LoongArch::PseudoCALL:
case LoongArch::PseudoCALL_SMALL:
case LoongArch::PseudoCALL_LARGE:
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
case LoongArch::PseudoTAIL:
case LoongArch::PseudoTAIL_SMALL:
case LoongArch::PseudoTAIL_LARGE:
return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
case LoongArch::PseudoBRIND:
@ -784,25 +784,36 @@ bool LoongArchExpandPseudo::expandFunctionCALL(
report_fatal_error("Unexpected code model");
break;
case CodeModel::Medium: {
// for la32 expands to:
// CALL:
// pcaddu18i $ra, %call36(func)
// jirl $ra, $ra, 0
// pcaddu12i $ra, %call30(func)
// jirl $ra, $ra, 0
// TAIL:
// pcaddu18i $t8, %call36(func)
// jirl $r0, $t8, 0
// pcaddu12i $t8, %call30(func)
// jirl $r0, $t8, 0
//
// for la64 expands to:
// CALL:
// pcaddu18i $ra, %call36(func)
// jirl $ra, $ra, 0
// TAIL:
// pcaddu18i $t8, %call36(func)
// jirl $r0, $t8, 0
Opcode =
IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
bool Is64Bit = MF->getSubtarget<LoongArchSubtarget>().is64Bit();
unsigned PC = Is64Bit ? LoongArch::PCADDU18I : LoongArch::PCADDU12I;
unsigned MO = Is64Bit ? LoongArchII::MO_CALL36 : LoongArchII::MO_CALL30;
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(PC), ScratchReg);
CALL =
BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
if (Func.isSymbol())
MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
MIB.addExternalSymbol(Func.getSymbolName(), MO);
else
MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
MIB.addDisp(Func, 0, MO);
break;
}
}

View File

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

View File

@ -515,7 +515,7 @@ def SImm26OperandBL: AsmOperandClass {
let ParserMethod = "parseSImm26Operand";
}
// A symbol or an imm used in BL/PseudoCALL/PseudoTAIL.
// A symbol or an imm used in BL/PseudoCALL_SMALL/PseudoTAIL_SMALL.
def simm26_symbol : Operand<GRLenVT> {
let ParserMatchClass = SImm26OperandBL;
let EncoderMethod = "getImmOpValueAsr<2>";
@ -1625,21 +1625,21 @@ def : Pat<(brind (add GPRJR:$rj, simm16_lsl2:$imm16)),
// Function call with 'Small' code model.
let isCall = 1, Defs = [R1] in
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func)>;
def PseudoCALL_SMALL : Pseudo<(outs), (ins bare_symbol:$func)>;
def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
def : Pat<(loongarch_call tglobaladdr:$func),
(PseudoCALL_SMALL tglobaladdr:$func)>;
def : Pat<(loongarch_call texternalsym:$func),
(PseudoCALL_SMALL texternalsym:$func)>;
// Function call with 'Medium' code model.
let isCall = 1, Defs = [R1, R20], Size = 8 in
def PseudoCALL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$func)>;
let Predicates = [IsLA64] in {
def : Pat<(loongarch_call_medium tglobaladdr:$func),
(PseudoCALL_MEDIUM tglobaladdr:$func)>;
def : Pat<(loongarch_call_medium texternalsym:$func),
(PseudoCALL_MEDIUM texternalsym:$func)>;
} // Predicates = [IsLA64]
// Function call with 'Large' code model.
let isCall = 1, Defs = [R1] in
@ -1656,10 +1656,9 @@ let isCall = 1, Defs = [R1] in
def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rj),
[(loongarch_call GPR:$rj)]>,
PseudoInstExpansion<(JIRL R1, GPR:$rj, 0)>;
let Predicates = [IsLA64] in {
def : Pat<(loongarch_call_medium GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
let Predicates = [IsLA64] in
def : Pat<(loongarch_call_large GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
}
let isCall = 1, hasSideEffects = 0, mayStore = 0, mayLoad = 0, Defs = [R1] in
def PseudoJIRL_CALL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
@ -1672,24 +1671,22 @@ def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
// Tail call with 'Small' code model.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst)>;
def PseudoTAIL_SMALL : Pseudo<(outs), (ins bare_symbol:$dst)>;
def : Pat<(loongarch_tail (iPTR tglobaladdr:$dst)),
(PseudoTAIL tglobaladdr:$dst)>;
(PseudoTAIL_SMALL tglobaladdr:$dst)>;
def : Pat<(loongarch_tail (iPTR texternalsym:$dst)),
(PseudoTAIL texternalsym:$dst)>;
(PseudoTAIL_SMALL texternalsym:$dst)>;
// Tail call with 'Medium' code model.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
Uses = [R3], Defs = [R20], Size = 8 in
def PseudoTAIL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$dst)>;
let Predicates = [IsLA64] in {
def : Pat<(loongarch_tail_medium (iPTR tglobaladdr:$dst)),
(PseudoTAIL_MEDIUM tglobaladdr:$dst)>;
def : Pat<(loongarch_tail_medium (iPTR texternalsym:$dst)),
(PseudoTAIL_MEDIUM texternalsym:$dst)>;
} // Predicates = [IsLA64]
// Tail call with 'Large' code model.
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
def PseudoTAILIndirect : Pseudo<(outs), (ins GPRT:$rj),
[(loongarch_tail GPRT:$rj)]>,
PseudoInstExpansion<(JIRL R0, GPR:$rj, 0)>;
let Predicates = [IsLA64] in {
def : Pat<(loongarch_tail_medium GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
let Predicates = [IsLA64] in
def : Pat<(loongarch_tail_large GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
}
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
hasSideEffects = 0, mayStore = 0, mayLoad = 0, Uses = [R3] in
@ -1722,6 +1718,16 @@ def PseudoJIRL_TAIL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
PseudoInstExpansion<(JIRL R0, GPR:$rj,
simm16_lsl2:$imm16)>;
/// call/tail macro instructions
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
Defs = [R1], hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$dst), [], "call", "$dst">;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3],
isCodeGenOnly = 0, isAsmParserOnly = 1, hasSideEffects = 0,
mayStore = 0, mayLoad = 0 in
def PseudoTAIL : Pseudo<(outs), (ins GPR:$tmp, bare_symbol:$dst), [],
"tail", "$tmp, $dst">;
/// call30/tail30 macro instructions
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
Defs = [R1], hasSideEffects = 0, mayStore = 0, mayLoad = 0 in

View File

@ -561,7 +561,7 @@ static bool isSignExtendedW(Register SrcReg, const LoongArchSubtarget &ST,
if (CopySrcReg == LoongArch::R4) {
// For a method return value, we check the ZExt/SExt flags in attribute.
// We assume the following code sequence for method call.
// PseudoCALL @bar, ...
// PseudoCALL_SMALL @bar, ...
// ADJCALLSTACKUP 0, 0, implicit-def dead $r3, implicit $r3
// %0:gpr = COPY $r4
//

View File

@ -79,11 +79,11 @@ getEffectiveLoongArchCodeModel(const Triple &TT,
switch (*CM) {
case CodeModel::Small:
return *CM;
case CodeModel::Medium:
return *CM;
case CodeModel::Large:
if (!TT.isArch64Bit())
report_fatal_error("Medium/Large code model requires LA64");
report_fatal_error("Large code model requires LA64");
return *CM;
default:
report_fatal_error(

View File

@ -7,7 +7,7 @@ declare void @callee()
define void @caller() nounwind {
; NOEXPAND-LABEL: name: caller
; NOEXPAND: PseudoCALL target-flags{{.*}}callee
; NOEXPAND: PseudoCALL_SMALL target-flags{{.*}}callee
;
; EXPAND-LABEL: name: caller
; EXPAND: BL target-flags{{.*}}callee

View File

@ -1,12 +1,37 @@
# RUN: llvm-mc --triple=loongarch64 %s | FileCheck %s
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.relax
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX
# RUN: llvm-mc --triple=loongarch32 %s | FileCheck %s --check-prefixes=CHECK,LA32
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=-relax %s -o %t
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefixes=RELOC,LA32-RELOC
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.relax
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX,LA32-RELOC
# RUN: llvm-mc --triple=loongarch64 %s --defsym=LA64=1 | FileCheck %s --check-prefixes=CHECK,LA64
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t --defsym=LA64=1
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefixes=RELOC,LA64-RELOC
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.relax --defsym=LA64=1
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX,LA64-RELOC,LA64-RELAX
# RELOC: Relocations [
# RELOC-NEXT: Section ({{.*}}) .rela.text {
call sym_call
# LA32: pcaddu12i $ra, %call30(sym_call)
# LA32-NEXT: jirl $ra, $ra, 0
# LA64: pcaddu18i $ra, %call36(sym_call)
# LA64-NEXT: jirl $ra, $ra, 0
# LA32-RELOC-NEXT: R_LARCH_CALL30 sym_call 0x0
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
tail $t0, sym_tail
# LA32: pcaddu12i $t0, %call30(sym_tail)
# LA32-NEXT: jr $t0
# LA64: pcaddu18i $t0, %call36(sym_tail)
# LA64-NEXT: jr $t0
# LA32-RELOC-NEXT: R_LARCH_CALL30 sym_tail 0x0
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
call30 sym_call
# CHECK: pcaddu12i $ra, %call30(sym_call)
# CHECK-NEXT: jirl $ra, $ra, 0
@ -21,19 +46,23 @@ tail30 $t0, sym_tail
# RELOC-NEXT: R_LARCH_CALL30 sym_tail 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
call36 sym_call
# CHECK: pcaddu18i $ra, %call36(sym_call)
# CHECK-NEXT: jirl $ra, $ra, 0
.ifdef LA64
# RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
call36 sym_call
# LA64: pcaddu18i $ra, %call36(sym_call)
# LA64-NEXT: jirl $ra, $ra, 0
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
# LA64-RELAX-NEXT: R_LARCH_RELAX - 0x0
tail36 $t0, sym_tail
# CHECK: pcaddu18i $t0, %call36(sym_tail)
# CHECK-NEXT: jr $t0
# LA64: pcaddu18i $t0, %call36(sym_tail)
# LA64-NEXT: jr $t0
# RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
# LA64-RELOC-NEXT: R_LARCH_CALL36 sym_tail 0x0
# LA64-RELAX-NEXT: R_LARCH_RELAX - 0x0
.endif
# RELOC-NEXT: }
# RELOC-NEXT: ]