[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:
parent
0f24d0fb6c
commit
9f7af28972
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
//
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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: ]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user