Author: hev Date: 2026-01-22T08:27:35Z New Revision: e8c6fcc3f7147b4143ecec38cae22dda059b4eba
URL: https://github.com/llvm/llvm-project/commit/e8c6fcc3f7147b4143ecec38cae22dda059b4eba DIFF: https://github.com/llvm/llvm-project/commit/e8c6fcc3f7147b4143ecec38cae22dda059b4eba.diff LOG: [llvm][LoongArch] Add call and tail macro instruction support (#175357) Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html (cherry picked from commit 9f7af289728002487b032a8278bc2c540a02ff59) Added: Modified: llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp llvm/lib/Target/LoongArch/LoongArchInstrInfo.td llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp llvm/test/CodeGen/LoongArch/expand-call.ll llvm/test/MC/LoongArch/Macros/macros-call.s Removed: ################################################################################ diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp index 483be6b9a1a57..5a6a0927a8974 100644 --- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -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; diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp index 7aef4ab53e4ea..6cef279c6131c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp @@ -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; } } diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index bc9ae3eafb3b2..8451adcfa5faa 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -8628,7 +8628,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) @@ -8674,7 +8674,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: diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 6f840dae3f0ae..555dc31e77755 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -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 diff --git a/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp b/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp index 0e5acff5d1cbc..b91724e0112a9 100644 --- a/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp @@ -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 // diff --git a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp index 92a9388e5cb7b..8054cb2d5e896 100644 --- a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp @@ -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( diff --git a/llvm/test/CodeGen/LoongArch/expand-call.ll b/llvm/test/CodeGen/LoongArch/expand-call.ll index 495cf04c95b32..7a9a5067c54ce 100644 --- a/llvm/test/CodeGen/LoongArch/expand-call.ll +++ b/llvm/test/CodeGen/LoongArch/expand-call.ll @@ -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 diff --git a/llvm/test/MC/LoongArch/Macros/macros-call.s b/llvm/test/MC/LoongArch/Macros/macros-call.s index 0fbc2160c14f5..49b2fa5af848f 100644 --- a/llvm/test/MC/LoongArch/Macros/macros-call.s +++ b/llvm/test/MC/LoongArch/Macros/macros-call.s @@ -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 +.ifdef LA64 + call36 sym_call -# CHECK: pcaddu18i $ra, %call36(sym_call) -# CHECK-NEXT: jirl $ra, $ra, 0 +# LA64: pcaddu18i $ra, %call36(sym_call) +# LA64-NEXT: jirl $ra, $ra, 0 -# RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0 -# RELAX-NEXT: R_LARCH_RELAX - 0x0 +# 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: ] _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
