[llvm-branch-commits] [llvm] [llvm][LoongArch] Add call and tail macro instruction support (PR #175357)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Jan 10 08:57:49 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-loongarch

Author: hev (heiher)

<details>
<summary>Changes</summary>

Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html

---
Full diff: https://github.com/llvm/llvm-project/pull/175357.diff


8 Files Affected:

- (modified) llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (+7) 
- (modified) llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (+21-10) 
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+1-2) 
- (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+21-15) 
- (modified) llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp (+1-1) 
- (modified) llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (+2-2) 
- (modified) llvm/test/CodeGen/LoongArch/expand-call.ll (+1-1) 
- (modified) llvm/test/MC/LoongArch/Macros/macros-call.s (+14) 


``````````diff
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index ef787a9352a9b..fa545f740b529 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -1560,12 +1560,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 fc999b9727521..6cc2f9175c6b7 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -8577,7 +8577,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)
@@ -8623,7 +8623,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 26315b13876c8..0923cfd87050f 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -511,7 +511,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>";
@@ -1621,21 +1621,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
@@ -1652,10 +1652,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)>,
@@ -1668,24 +1667,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
@@ -1702,10 +1699,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
@@ -1718,6 +1714,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..92499efddfadb 100644
--- a/llvm/test/MC/LoongArch/Macros/macros-call.s
+++ b/llvm/test/MC/LoongArch/Macros/macros-call.s
@@ -7,6 +7,20 @@
 # RELOC:      Relocations [
 # RELOC-NEXT:   Section ({{.*}}) .rela.text {
 
+call sym_call
+# CHECK:      pcaddu18i $ra, %call36(sym_call)
+# CHECK-NEXT: jirl $ra, $ra, 0
+
+# RELOC-NEXT: R_LARCH_CALL36 sym_call 0x0
+# RELAX-NEXT: R_LARCH_RELAX - 0x0
+
+tail $t0, sym_tail
+# CHECK:      pcaddu18i $t0, %call36(sym_tail)
+# CHECK-NEXT: jr $t0
+
+# 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

``````````

</details>


https://github.com/llvm/llvm-project/pull/175357


More information about the llvm-branch-commits mailing list