Skip to content

Commit 416ff08

Browse files
wangleiatAmi-zhang
authored andcommitted
[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. (cherry picked from commit 2cf420d) Change-Id: I15ee49332280531f31a9f483a90635bef37528c7
1 parent 7ae21a3 commit 416ff08

15 files changed

+133
-28
lines changed

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

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

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

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

1134+
void LoongArchAsmParser::emitFuncCall36(MCInst &Inst, SMLoc IDLoc,
1135+
MCStreamer &Out, bool IsTailCall) {
1136+
// call36 sym
1137+
// expands to:
1138+
// pcaddu18i $ra, %call36(sym)
1139+
// jirl $ra, $ra, 0
1140+
//
1141+
// tail36 $rj, sym
1142+
// expands to:
1143+
// pcaddu18i $rj, %call36(sym)
1144+
// jirl $r0, $rj, 0
1145+
unsigned ScratchReg =
1146+
IsTailCall ? Inst.getOperand(0).getReg() : (unsigned)LoongArch::R1;
1147+
const MCExpr *Sym =
1148+
IsTailCall ? Inst.getOperand(1).getExpr() : Inst.getOperand(0).getExpr();
1149+
const LoongArchMCExpr *LE = LoongArchMCExpr::create(
1150+
Sym, llvm::LoongArchMCExpr::VK_LoongArch_CALL36, getContext());
1151+
1152+
Out.emitInstruction(
1153+
MCInstBuilder(LoongArch::PCADDU18I).addReg(ScratchReg).addExpr(LE),
1154+
getSTI());
1155+
Out.emitInstruction(
1156+
MCInstBuilder(LoongArch::JIRL)
1157+
.addReg(IsTailCall ? (unsigned)LoongArch::R0 : ScratchReg)
1158+
.addReg(ScratchReg)
1159+
.addImm(0),
1160+
getSTI());
1161+
}
1162+
11141163
bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11151164
OperandVector &Operands,
11161165
MCStreamer &Out) {
@@ -1159,6 +1208,12 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11591208
case LoongArch::PseudoLI_D:
11601209
emitLoadImm(Inst, IDLoc, Out);
11611210
return false;
1211+
case LoongArch::PseudoCALL36:
1212+
emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/false);
1213+
return false;
1214+
case LoongArch::PseudoTAIL36:
1215+
emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/true);
1216+
return false;
11621217
}
11631218
Out.emitInstruction(Inst, getSTI());
11641219
return false;
@@ -1440,6 +1495,12 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
14401495
/*Upper=*/(1 << 19) - 1,
14411496
"operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
14421497
"in the range");
1498+
case Match_InvalidSImm20pcaddu18i:
1499+
return generateImmOutOfRangeError(
1500+
Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1501+
/*Upper=*/(1 << 19) - 1,
1502+
"operand must be a symbol with modifier (e.g. %call36) or an integer "
1503+
"in the range");
14431504
case Match_InvalidSImm21lsl2:
14441505
return generateImmOutOfRangeError(
14451506
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
@@ -351,6 +351,10 @@ def simm20_lu32id : SImm20Operand {
351351
let ParserMatchClass = SImmAsmOperand<20, "lu32id">;
352352
}
353353

354+
def simm20_pcaddu18i : SImm20Operand {
355+
let ParserMatchClass = SImmAsmOperand<20, "pcaddu18i">;
356+
}
357+
354358
def simm21_lsl2 : Operand<OtherVT> {
355359
let ParserMatchClass = SImmAsmOperand<21, "lsl2">;
356360
let EncoderMethod = "getImmOpValueAsr<2>";
@@ -772,7 +776,7 @@ def LU32I_D : Fmt1RI20<0x16000000, (outs GPR:$dst),
772776
"$rd, $imm20">;
773777
}
774778
def LU52I_D : ALU_2RI12<0x03000000, simm12_lu52id>;
775-
def PCADDU18I : ALU_1RI20<0x1e000000, simm20>;
779+
def PCADDU18I : ALU_1RI20<0x1e000000, simm20_pcaddu18i>;
776780
def MUL_D : ALU_3R<0x001d8000>;
777781
def MULH_D : ALU_3R<0x001e0000>;
778782
def MULH_DU : ALU_3R<0x001e8000>;
@@ -1324,7 +1328,7 @@ def : Pat<(brind (add GPR:$rj, simm16_lsl2:$imm16)),
13241328
(PseudoBRIND GPR:$rj, simm16_lsl2:$imm16)>;
13251329

13261330
let isCall = 1, Defs = [R1] in
1327-
def PseudoCALL : Pseudo<(outs), (ins simm26_symbol:$func)>;
1331+
def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func)>;
13281332

13291333
def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
13301334
def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
@@ -1344,7 +1348,7 @@ def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
13441348
PseudoInstExpansion<(JIRL R0, R1, 0)>;
13451349

13461350
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1347-
def PseudoTAIL : Pseudo<(outs), (ins simm26_symbol:$dst)>;
1351+
def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst)>;
13481352

13491353
def : Pat<(loongarch_tail (iPTR tglobaladdr:$dst)),
13501354
(PseudoTAIL tglobaladdr:$dst)>;
@@ -1367,6 +1371,19 @@ def PseudoJIRL_TAIL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
13671371
PseudoInstExpansion<(JIRL R0, GPR:$rj,
13681372
simm16_lsl2:$imm16)>;
13691373

1374+
/// call36/taill36 macro instructions
1375+
let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
1376+
Defs = [R1], Size = 8, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
1377+
def PseudoCALL36 : Pseudo<(outs), (ins bare_symbol:$dst), [],
1378+
"call36", "$dst">,
1379+
Requires<[IsLA64]>;
1380+
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3],
1381+
isCodeGenOnly = 0, isAsmParserOnly = 1, Size = 8, hasSideEffects = 0,
1382+
mayStore = 0, mayLoad = 0 in
1383+
def PseudoTAIL36 : Pseudo<(outs), (ins GPR:$tmp, bare_symbol:$dst), [],
1384+
"tail36", "$tmp, $dst">,
1385+
Requires<[IsLA64]>;
1386+
13701387
/// Load address (la*) macro instructions.
13711388

13721389
// 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ enum Fixups {
111111
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX,
112112
// Generate an R_LARCH_ALIGN which indicates the linker may fixup align here.
113113
fixup_loongarch_align = FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN,
114+
// 36-bit fixup corresponding to %call36(foo) for a pair instructions:
115+
// pcaddu18i+jirl.
116+
fixup_loongarch_call36 = FirstLiteralRelocationKind + ELF::R_LARCH_CALL36,
114117
};
115118
} // end namespace LoongArch
116119
} // 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)