aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp61
1 files changed, 61 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index 66a37fce5dda..46f63a4103f9 100644
--- a/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -121,6 +121,10 @@ class LoongArchAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo instruction "li.w/d $rd, $imm".
void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
+ // Helper to emit pseudo instruction "call36 sym" or "tail36 $rj, sym".
+ void emitFuncCall36(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ bool IsTailCall);
+
public:
enum LoongArchMatchResultTy {
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
@@ -400,6 +404,22 @@ public:
IsValidKind;
}
+ bool isSImm20pcaddu18i() const {
+ if (!isImm())
+ return false;
+
+ int64_t Imm;
+ LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
+ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
+ bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
+ VK == LoongArchMCExpr::VK_LoongArch_CALL36;
+
+ return IsConstantImm
+ ? isInt<20>(Imm) && IsValidKind
+ : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
+ IsValidKind;
+ }
+
bool isSImm21lsl2() const {
if (!isImm())
return false;
@@ -1110,6 +1130,35 @@ void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
}
}
+void LoongArchAsmParser::emitFuncCall36(MCInst &Inst, SMLoc IDLoc,
+ MCStreamer &Out, bool IsTailCall) {
+ // call36 sym
+ // expands to:
+ // pcaddu18i $ra, %call36(sym)
+ // jirl $ra, $ra, 0
+ //
+ // tail36 $rj, sym
+ // expands to:
+ // pcaddu18i $rj, %call36(sym)
+ // jirl $r0, $rj, 0
+ unsigned ScratchReg =
+ IsTailCall ? Inst.getOperand(0).getReg() : (unsigned)LoongArch::R1;
+ const MCExpr *Sym =
+ IsTailCall ? Inst.getOperand(1).getExpr() : Inst.getOperand(0).getExpr();
+ const LoongArchMCExpr *LE = LoongArchMCExpr::create(
+ Sym, llvm::LoongArchMCExpr::VK_LoongArch_CALL36, getContext());
+
+ Out.emitInstruction(
+ MCInstBuilder(LoongArch::PCADDU18I).addReg(ScratchReg).addExpr(LE),
+ getSTI());
+ Out.emitInstruction(
+ MCInstBuilder(LoongArch::JIRL)
+ .addReg(IsTailCall ? (unsigned)LoongArch::R0 : ScratchReg)
+ .addReg(ScratchReg)
+ .addImm(0),
+ getSTI());
+}
+
bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
OperandVector &Operands,
MCStreamer &Out) {
@@ -1158,6 +1207,12 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case LoongArch::PseudoLI_D:
emitLoadImm(Inst, IDLoc, Out);
return false;
+ case LoongArch::PseudoCALL36:
+ emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/false);
+ return false;
+ case LoongArch::PseudoTAIL36:
+ emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/true);
+ return false;
}
Out.emitInstruction(Inst, getSTI());
return false;
@@ -1439,6 +1494,12 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
/*Upper=*/(1 << 19) - 1,
"operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
"in the range");
+ case Match_InvalidSImm20pcaddu18i:
+ return generateImmOutOfRangeError(
+ Operands, ErrorInfo, /*Lower=*/-(1 << 19),
+ /*Upper=*/(1 << 19) - 1,
+ "operand must be a symbol with modifier (e.g. %call36) or an integer "
+ "in the range");
case Match_InvalidSImm21lsl2:
return generateImmOutOfRangeError(
Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,