Skip to content

Commit 2cf420d

Browse files
committed
[LoongArch] Emit function call code sequence as PCADDU18I+JIRL in medium code model
According to the description of the psABI v2.20: https://github.com/loongson/la-abi-specs/releases/tag/v2.20, adjustments are made to the function call instructions under the medium code model. At the same time, AsmParser has already supported parsing the call36 and tail36 macro instructions.
1 parent 597086c commit 2cf420d

15 files changed

+134
-29
lines changed

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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ class LoongArchAsmParser : public MCTargetAsmParser {
121121
// Helper to emit pseudo instruction "li.w/d $rd, $imm".
122122
void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
123123

124+
// Helper to emit pseudo instruction "call36 sym" or "tail36 $rj, sym".
125+
void emitFuncCall36(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
126+
bool IsTailCall);
127+
124128
public:
125129
enum LoongArchMatchResultTy {
126130
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
@@ -400,6 +404,22 @@ class LoongArchOperand : public MCParsedAsmOperand {
400404
IsValidKind;
401405
}
402406

407+
bool isSImm20pcaddu18i() const {
408+
if (!isImm())
409+
return false;
410+
411+
int64_t Imm;
412+
LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
413+
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
414+
bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
415+
VK == LoongArchMCExpr::VK_LoongArch_CALL36;
416+
417+
return IsConstantImm
418+
? isInt<20>(Imm) && IsValidKind
419+
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
420+
IsValidKind;
421+
}
422+
403423
bool isSImm21lsl2() const {
404424
if (!isImm())
405425
return false;
@@ -1110,6 +1130,35 @@ void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
11101130
}
11111131
}
11121132

1133+
void LoongArchAsmParser::emitFuncCall36(MCInst &Inst, SMLoc IDLoc,
1134+
MCStreamer &Out, bool IsTailCall) {
1135+
// call36 sym
1136+
// expands to:
1137+
// pcaddu18i $ra, %call36(sym)
1138+
// jirl $ra, $ra, 0
1139+
//
1140+
// tail36 $rj, sym
1141+
// expands to:
1142+
// pcaddu18i $rj, %call36(sym)
1143+
// jirl $r0, $rj, 0
1144+
unsigned ScratchReg =
1145+
IsTailCall ? Inst.getOperand(0).getReg() : (unsigned)LoongArch::R1;
1146+
const MCExpr *Sym =
1147+
IsTailCall ? Inst.getOperand(1).getExpr() : Inst.getOperand(0).getExpr();
1148+
const LoongArchMCExpr *LE = LoongArchMCExpr::create(
1149+
Sym, llvm::LoongArchMCExpr::VK_LoongArch_CALL36, getContext());
1150+
1151+
Out.emitInstruction(
1152+
MCInstBuilder(LoongArch::PCADDU18I).addReg(ScratchReg).addExpr(LE),
1153+
getSTI());
1154+
Out.emitInstruction(
1155+
MCInstBuilder(LoongArch::JIRL)
1156+
.addReg(IsTailCall ? (unsigned)LoongArch::R0 : ScratchReg)
1157+
.addReg(ScratchReg)
1158+
.addImm(0),
1159+
getSTI());
1160+
}
1161+
11131162
bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11141163
OperandVector &Operands,
11151164
MCStreamer &Out) {
@@ -1158,6 +1207,12 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11581207
case LoongArch::PseudoLI_D:
11591208
emitLoadImm(Inst, IDLoc, Out);
11601209
return false;
1210+
case LoongArch::PseudoCALL36:
1211+
emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/false);
1212+
return false;
1213+
case LoongArch::PseudoTAIL36:
1214+
emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/true);
1215+
return false;
11611216
}
11621217
Out.emitInstruction(Inst, getSTI());
11631218
return false;
@@ -1439,6 +1494,12 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
14391494
/*Upper=*/(1 << 19) - 1,
14401495
"operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
14411496
"in the range");
1497+
case Match_InvalidSImm20pcaddu18i:
1498+
return generateImmOutOfRangeError(
1499+
Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1500+
/*Upper=*/(1 << 19) - 1,
1501+
"operand must be a symbol with modifier (e.g. %call36) or an integer "
1502+
"in the range");
14421503
case Match_InvalidSImm21lsl2:
14431504
return generateImmOutOfRangeError(
14441505
Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,

llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -458,30 +458,27 @@ bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
458458
}
459459
case CodeModel::Medium: {
460460
// CALL:
461-
// pcalau12i $ra, %pc_hi20(func)
462-
// jirl $ra, $ra, %pc_lo12(func)
461+
// pcaddu18i $ra, %call36(func)
462+
// jirl $ra, $ra, 0
463463
// TAIL:
464-
// pcalau12i $scratch, %pc_hi20(func)
465-
// jirl $r0, $scratch, %pc_lo12(func)
464+
// pcaddu18i $scratch, %call36(func)
465+
// jirl $r0, $scratch, 0
466466
Opcode =
467467
IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
468468
Register ScratchReg =
469469
IsTailCall
470470
? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
471471
: LoongArch::R1;
472472
MachineInstrBuilder MIB =
473-
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg);
474-
CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg);
475-
if (Func.isSymbol()) {
476-
const char *FnName = Func.getSymbolName();
477-
MIB.addExternalSymbol(FnName, LoongArchII::MO_PCREL_HI);
478-
CALL.addExternalSymbol(FnName, LoongArchII::MO_PCREL_LO);
479-
break;
480-
}
481-
assert(Func.isGlobal() && "Expected a GlobalValue at this time");
482-
const GlobalValue *GV = Func.getGlobal();
483-
MIB.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_HI);
484-
CALL.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_LO);
473+
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
474+
475+
CALL =
476+
BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
477+
478+
if (Func.isSymbol())
479+
MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
480+
else
481+
MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
485482
break;
486483
}
487484
case CodeModel::Large: {

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ def simm20_lu32id : SImm20Operand {
377377
let ParserMatchClass = SImmAsmOperand<20, "lu32id">;
378378
}
379379

380+
def simm20_pcaddu18i : SImm20Operand {
381+
let ParserMatchClass = SImmAsmOperand<20, "pcaddu18i">;
382+
}
383+
380384
def simm21_lsl2 : Operand<OtherVT> {
381385
let ParserMatchClass = SImmAsmOperand<21, "lsl2">;
382386
let EncoderMethod = "getImmOpValueAsr<2>";
@@ -832,7 +836,7 @@ def LU32I_D : Fmt1RI20<0x16000000, (outs GPR:$dst),
832836
"$rd, $imm20">;
833837
}
834838
def LU52I_D : ALU_2RI12<0x03000000, simm12_lu52id>;
835-
def PCADDU18I : ALU_1RI20<0x1e000000, simm20>;
839+
def PCADDU18I : ALU_1RI20<0x1e000000, simm20_pcaddu18i>;
836840
def MUL_D : ALU_3R<0x001d8000>;
837841
def MULH_D : ALU_3R<0x001e0000>;
838842
def MULH_DU : ALU_3R<0x001e8000>;
@@ -1396,7 +1400,7 @@ def : Pat<(brind (add GPR:$rj, simm16_lsl2:$imm16)),
13961400
(PseudoBRIND GPR:$rj, simm16_lsl2:$imm16)>;
13971401

13981402
let isCall = 1, Defs = [R1] in
1399-
def PseudoCALL : Pseudo<(outs), (ins simm26_symbol:$func)>;
1403+
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func)>;
14001404

14011405
def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
14021406
def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
@@ -1416,7 +1420,7 @@ def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
14161420
PseudoInstExpansion<(JIRL R0, R1, 0)>;
14171421

14181422
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1419-
def PseudoTAIL : Pseudo<(outs), (ins simm26_symbol:$dst)>;
1423+
def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst)>;
14201424

14211425
def : Pat<(loongarch_tail (iPTR tglobaladdr:$dst)),
14221426
(PseudoTAIL tglobaladdr:$dst)>;
@@ -1439,6 +1443,19 @@ def PseudoJIRL_TAIL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
14391443
PseudoInstExpansion<(JIRL R0, GPR:$rj,
14401444
simm16_lsl2:$imm16)>;
14411445

1446+
/// call36/taill36 macro instructions
1447+
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
1448+
Defs = [R1], Size = 8, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
1449+
def PseudoCALL36 : Pseudo<(outs), (ins bare_symbol:$dst), [],
1450+
"call36", "$dst">,
1451+
Requires<[IsLA64]>;
1452+
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3],
1453+
isCodeGenOnly = 0, isAsmParserOnly = 1, Size = 8, hasSideEffects = 0,
1454+
mayStore = 0, mayLoad = 0 in
1455+
def PseudoTAIL36 : Pseudo<(outs), (ins GPR:$tmp, bare_symbol:$dst), [],
1456+
"tail36", "$tmp, $dst">,
1457+
Requires<[IsLA64]>;
1458+
14421459
/// Load address (la*) macro instructions.
14431460

14441461
// Define isCodeGenOnly = 0 to expose them to tablegened assembly parser.

llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
9595
case LoongArchII::MO_GD_PC_HI:
9696
Kind = LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20;
9797
break;
98+
case LoongArchII::MO_CALL36:
99+
Kind = LoongArchMCExpr::VK_LoongArch_CALL36;
100+
break;
98101
// TODO: Handle more target-flags.
99102
}
100103

llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp

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

6464
switch (*CM) {
6565
case CodeModel::Small:
66-
case CodeModel::Medium:
6766
return *CM;
67+
case CodeModel::Medium:
6868
case CodeModel::Large:
6969
if (!TT.isArch64Bit())
70-
report_fatal_error("Large code model requires LA64");
70+
report_fatal_error("Medium/Large code model requires LA64");
7171
return *CM;
7272
default:
7373
report_fatal_error(

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum {
4747
MO_IE_PC64_HI,
4848
MO_LD_PC_HI,
4949
MO_GD_PC_HI,
50+
MO_CALL36
5051
// TODO: Add more flags.
5152
};
5253
} // end namespace LoongArchII

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ unsigned LoongArchELFObjectWriter::getRelocType(MCContext &Ctx,
9090
return ELF::R_LARCH_TLS_LE64_LO20;
9191
case LoongArch::fixup_loongarch_tls_le64_hi12:
9292
return ELF::R_LARCH_TLS_LE64_HI12;
93+
case LoongArch::fixup_loongarch_call36:
94+
return ELF::R_LARCH_CALL36;
9395
// TODO: Handle more fixup-kinds.
9496
}
9597
}

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ enum Fixups {
108108
// 20-bit fixup corresponding to %gd_hi20(foo) for instruction lu12i.w.
109109
fixup_loongarch_tls_gd_hi20,
110110
// Generate an R_LARCH_RELAX which indicates the linker may relax here.
111-
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX
111+
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX,
112+
// 36-bit fixup corresponding to %call36(foo) for a pair instructions:
113+
// pcaddu18i+jirl.
114+
fixup_loongarch_call36 = FirstLiteralRelocationKind + ELF::R_LARCH_CALL36,
112115
};
113116
} // end namespace LoongArch
114117
} // end namespace llvm

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
241241
case LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20:
242242
FixupKind = LoongArch::fixup_loongarch_tls_gd_hi20;
243243
break;
244+
case LoongArchMCExpr::VK_LoongArch_CALL36:
245+
FixupKind = LoongArch::fixup_loongarch_call36;
246+
break;
244247
}
245248
} else if (Kind == MCExpr::SymbolRef &&
246249
cast<MCSymbolRefExpr>(Expr)->getKind() ==

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ StringRef LoongArchMCExpr::getVariantKindName(VariantKind Kind) {
138138
return "gd_pc_hi20";
139139
case VK_LoongArch_TLS_GD_HI20:
140140
return "gd_hi20";
141+
case VK_LoongArch_CALL36:
142+
return "call36";
141143
}
142144
}
143145

@@ -180,6 +182,7 @@ LoongArchMCExpr::getVariantKindForName(StringRef name) {
180182
.Case("ld_hi20", VK_LoongArch_TLS_LD_HI20)
181183
.Case("gd_pc_hi20", VK_LoongArch_TLS_GD_PC_HI20)
182184
.Case("gd_hi20", VK_LoongArch_TLS_GD_HI20)
185+
.Case("call36", VK_LoongArch_CALL36)
183186
.Default(VK_LoongArch_Invalid);
184187
}
185188

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class LoongArchMCExpr : public MCTargetExpr {
6161
VK_LoongArch_TLS_LD_HI20,
6262
VK_LoongArch_TLS_GD_PC_HI20,
6363
VK_LoongArch_TLS_GD_HI20,
64+
VK_LoongArch_CALL36,
6465
VK_LoongArch_Invalid // Must be the last item.
6566
};
6667

llvm/test/CodeGen/LoongArch/code-models.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ define i32 @call_globaladdress(i32 %a) nounwind {
2323
; MEDIUM: # %bb.0:
2424
; MEDIUM-NEXT: addi.d $sp, $sp, -16
2525
; MEDIUM-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
26-
; MEDIUM-NEXT: pcalau12i $ra, %pc_hi20(callee)
27-
; MEDIUM-NEXT: jirl $ra, $ra, %pc_lo12(callee)
26+
; MEDIUM-NEXT: pcaddu18i $ra, %call36(callee)
27+
; MEDIUM-NEXT: jirl $ra, $ra, 0
2828
; MEDIUM-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
2929
; MEDIUM-NEXT: addi.d $sp, $sp, 16
3030
; MEDIUM-NEXT: ret
@@ -68,8 +68,8 @@ define void @call_external_sym(ptr %dst) {
6868
; MEDIUM-NEXT: .cfi_offset 1, -8
6969
; MEDIUM-NEXT: ori $a2, $zero, 1000
7070
; MEDIUM-NEXT: move $a1, $zero
71-
; MEDIUM-NEXT: pcalau12i $ra, %pc_hi20(memset)
72-
; MEDIUM-NEXT: jirl $ra, $ra, %pc_lo12(memset)
71+
; MEDIUM-NEXT: pcaddu18i $ra, %call36(memset)
72+
; MEDIUM-NEXT: jirl $ra, $ra, 0
7373
; MEDIUM-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
7474
; MEDIUM-NEXT: addi.d $sp, $sp, 16
7575
; MEDIUM-NEXT: ret
@@ -105,8 +105,8 @@ define i32 @caller_tail(i32 %i) nounwind {
105105
;
106106
; MEDIUM-LABEL: caller_tail:
107107
; MEDIUM: # %bb.0: # %entry
108-
; MEDIUM-NEXT: pcalau12i $a1, %pc_hi20(callee_tail)
109-
; MEDIUM-NEXT: jirl $zero, $a1, %pc_lo12(callee_tail)
108+
; MEDIUM-NEXT: pcaddu18i $a1, %call36(callee_tail)
109+
; MEDIUM-NEXT: jr $a1
110110
;
111111
; LARGE-LABEL: caller_tail:
112112
; LARGE: # %bb.0: # %entry

llvm/test/MC/LoongArch/Basic/Integer/invalid64.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ addu16i.d $a0, $a0, 32768
6565

6666
## simm20
6767
pcaddu18i $a0, 0x80000
68-
# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287]
68+
# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %call36) or an integer in the range [-524288, 524287]
6969

7070
## simm20_lu32id
7171
lu32i.d $a0, 0x80000
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RUN: llvm-mc --triple=loongarch64 %s | FileCheck %s
2+
3+
call36 sym_call
4+
# CHECK: pcaddu18i $ra, %call36(sym_call)
5+
# CHECK-NEXT: jirl $ra, $ra, 0
6+
7+
tail36 $t0, sym_tail
8+
# CHECK: pcaddu18i $t0, %call36(sym_tail)
9+
# CHECK-NEXT: jr $t0

llvm/test/MC/LoongArch/Relocations/relocations.s

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,8 @@ lu12i.w $t1, %gd_hi20(foo)
218218
# RELOC: R_LARCH_TLS_GD_HI20 foo 0x0
219219
# INSTR: lu12i.w $t1, %gd_hi20(foo)
220220
# FIXUP: fixup A - offset: 0, value: %gd_hi20(foo), kind: FK_NONE
221+
222+
pcaddu18i $t1, %call36(foo)
223+
# RELOC: R_LARCH_CALL36 foo 0x0
224+
# INSTR: pcaddu18i $t1, %call36(foo)
225+
# FIXUP: fixup A - offset: 0, value: %call36(foo), kind: FK_NONE

0 commit comments

Comments
 (0)