[llvm] c2ee21c - [LoongArch] Add some fixups and relocations
Weining Lu via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 19 20:46:23 PDT 2022
Author: wanglei
Date: 2022-08-20T11:19:24+08:00
New Revision: c2ee21cf3f863dbe48bd6decf896b41891808647
URL: https://github.com/llvm/llvm-project/commit/c2ee21cf3f863dbe48bd6decf896b41891808647
DIFF: https://github.com/llvm/llvm-project/commit/c2ee21cf3f863dbe48bd6decf896b41891808647.diff
LOG: [LoongArch] Add some fixups and relocations
This patch only add %pc_hi20/%pc_lo12/%plt relocations in order
to be able to generate gnu ld linkable relocation file for the
`hello world` IR :
```
@.str = private unnamed_addr constant [14 x i8] c"Hello world!\0A\00", align 1
define dso_local signext i32 @main() nounwind {
entry:
%call = call signext i32 (ptr, ...) @printf(ptr noundef @.str)
ret i32 0
}
declare dso_local signext i32 @printf(ptr noundef, ...)
```
This patch also updates some test cases due to new modifiers introduced.
New test: test/MC/LoongArch/Relocations/relocations.s
Differential Revision: https://reviews.llvm.org/D132108
Added:
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h
llvm/test/MC/LoongArch/Relocations/relocations.s
Modified:
llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
llvm/test/CodeGen/LoongArch/analyze-branch.ll
llvm/test/CodeGen/LoongArch/bnez-beqz.ll
llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll
llvm/test/CodeGen/LoongArch/eh-dwarf-cfa.ll
llvm/test/CodeGen/LoongArch/frame.ll
llvm/test/CodeGen/LoongArch/fsqrt.ll
llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
llvm/test/CodeGen/LoongArch/ir-instruction/load-store-atomic.ll
llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll
llvm/test/CodeGen/LoongArch/ir-instruction/sdiv-udiv-srem-urem.ll
llvm/test/CodeGen/LoongArch/vararg.ll
llvm/test/MC/LoongArch/Basic/Integer/invalid.s
llvm/test/MC/LoongArch/Basic/Integer/invalid64.s
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index 9793c7bc3532c..2559069e3813b 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/LoongArchInstPrinter.h"
+#include "MCTargetDesc/LoongArchMCExpr.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "TargetInfo/LoongArchTargetInfo.h"
#include "llvm/MC/MCContext.h"
@@ -17,6 +18,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
@@ -62,6 +64,8 @@ class LoongArchAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseRegister(OperandVector &Operands);
OperandMatchResultTy parseImmediate(OperandVector &Operands);
+ OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
+ OperandMatchResultTy parseSImm26Operand(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
@@ -75,6 +79,9 @@ class LoongArchAsmParser : public MCTargetAsmParser {
#undef GET_OPERAND_DIAGNOSTIC_TYPES
};
+ static bool classifySymbolRef(const MCExpr *Expr,
+ LoongArchMCExpr::VariantKind &Kind);
+
LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, STI, MII) {
@@ -120,7 +127,13 @@ class LoongArchOperand : public MCParsedAsmOperand {
bool isMem() const override { return false; }
void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
- static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
+ static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
+ LoongArchMCExpr::VariantKind &VK) {
+ if (auto *LE = dyn_cast<LoongArchMCExpr>(Expr)) {
+ VK = LE->getKind();
+ return false;
+ }
+
if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
Imm = CE->getValue();
return true;
@@ -134,8 +147,10 @@ class LoongArchOperand : public MCParsedAsmOperand {
return false;
int64_t Imm;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
- return IsConstantImm && isUInt<N>(Imm - P);
+ LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
+ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
+ return IsConstantImm && isUInt<N>(Imm - P) &&
+ VK == LoongArchMCExpr::VK_LoongArch_None;
}
template <unsigned N, unsigned S = 0> bool isSImm() const {
@@ -143,8 +158,10 @@ class LoongArchOperand : public MCParsedAsmOperand {
return false;
int64_t Imm;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
- return IsConstantImm && isShiftedInt<N, S>(Imm);
+ LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
+ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
+ return IsConstantImm && isShiftedInt<N, S>(Imm) &&
+ VK == LoongArchMCExpr::VK_LoongArch_None;
}
bool isUImm2() const { return isUImm<2>(); }
@@ -156,13 +173,59 @@ class LoongArchOperand : public MCParsedAsmOperand {
bool isUImm12() const { return isUImm<12>(); }
bool isUImm14() const { return isUImm<14>(); }
bool isUImm15() const { return isUImm<15>(); }
- bool isSImm12() const { return isSImm<12>(); }
+
+ bool isSImm12() 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_PCREL_LO;
+
+ return IsConstantImm
+ ? (isInt<12>(Imm) &&
+ (VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind))
+ : (LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
+ IsValidKind);
+ }
+
bool isSImm14lsl2() const { return isSImm<14, 2>(); }
bool isSImm16() const { return isSImm<16>(); }
bool isSImm16lsl2() const { return isSImm<16, 2>(); }
bool isSImm20() const { return isSImm<20>(); }
+
+ bool isSImm20pcalau12i() 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_PCREL_HI;
+
+ return IsConstantImm
+ ? (isInt<20>(Imm) &&
+ (VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind))
+ : (LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
+ IsValidKind);
+ }
+
bool isSImm21lsl2() const { return isSImm<21, 2>(); }
- bool isSImm26lsl2() const { return isSImm<26, 2>(); }
+
+ bool isSImm26Operand() const {
+ int64_t Imm;
+ LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
+ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
+ bool IsValidKind = (VK == LoongArchMCExpr::VK_LoongArch_CALL ||
+ VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT);
+
+ return IsConstantImm
+ ? (isShiftedInt<26, 2>(Imm) &&
+ (VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind))
+ : (LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
+ IsValidKind);
+ }
/// Gets location of the first token of this operand.
SMLoc getStartLoc() const override { return StartLoc; }
@@ -289,6 +352,21 @@ OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo,
llvm_unreachable("Unimplemented function.");
}
+bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr,
+ LoongArchMCExpr::VariantKind &Kind) {
+ Kind = LoongArchMCExpr::VK_LoongArch_None;
+
+ if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Expr)) {
+ Kind = RE->getKind();
+ Expr = RE->getSubExpr();
+ }
+
+ MCValue Res;
+ if (Expr->evaluateAsRelocatable(Res, nullptr, nullptr))
+ return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None;
+ return false;
+}
+
OperandMatchResultTy
LoongArchAsmParser::parseRegister(OperandVector &Operands) {
if (getLexer().getTok().isNot(AsmToken::Dollar))
@@ -319,9 +397,91 @@ LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
SMLoc E;
const MCExpr *Res;
- if (getParser().parseExpression(Res, E))
+ switch (getLexer().getKind()) {
+ default:
+ return MatchOperand_NoMatch;
+ case AsmToken::LParen:
+ case AsmToken::Dot:
+ case AsmToken::Minus:
+ case AsmToken::Plus:
+ case AsmToken::Exclaim:
+ case AsmToken::Tilde:
+ case AsmToken::Integer:
+ case AsmToken::String:
+ case AsmToken::Identifier:
+ if (getParser().parseExpression(Res, E))
+ return MatchOperand_ParseFail;
+ break;
+ case AsmToken::Percent:
+ return parseOperandWithModifier(Operands);
+ }
+
+ Operands.push_back(LoongArchOperand::createImm(Res, S, E));
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy
+LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ SMLoc E;
+
+ if (getLexer().getKind() != AsmToken::Percent) {
+ Error(getLoc(), "expected '%' for operand modifier");
+ return MatchOperand_ParseFail;
+ }
+
+ getParser().Lex(); // Eat '%'
+
+ if (getLexer().getKind() != AsmToken::Identifier) {
+ Error(getLoc(), "expected valid identifier for operand modifier");
+ return MatchOperand_ParseFail;
+ }
+ StringRef Identifier = getParser().getTok().getIdentifier();
+ LoongArchMCExpr::VariantKind VK =
+ LoongArchMCExpr::getVariantKindForName(Identifier);
+ if (VK == LoongArchMCExpr::VK_LoongArch_Invalid) {
+ Error(getLoc(), "unrecognized operand modifier");
+ return MatchOperand_ParseFail;
+ }
+
+ getParser().Lex(); // Eat the identifier
+ if (getLexer().getKind() != AsmToken::LParen) {
+ Error(getLoc(), "expected '('");
+ return MatchOperand_ParseFail;
+ }
+ getParser().Lex(); // Eat '('
+
+ const MCExpr *SubExpr;
+ if (getParser().parseParenExpression(SubExpr, E)) {
+ return MatchOperand_ParseFail;
+ }
+
+ const MCExpr *ModExpr = LoongArchMCExpr::create(SubExpr, VK, getContext());
+ Operands.push_back(LoongArchOperand::createImm(ModExpr, S, E));
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy
+LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ const MCExpr *Res;
+
+ if (getLexer().getKind() == AsmToken::Percent)
+ return parseOperandWithModifier(Operands);
+
+ if (getLexer().getKind() != AsmToken::Identifier)
+ return MatchOperand_NoMatch;
+
+ StringRef Identifier;
+ if (getParser().parseIdentifier(Identifier))
return MatchOperand_ParseFail;
+ SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+ Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
+ Res = LoongArchMCExpr::create(Res, LoongArchMCExpr::VK_LoongArch_CALL,
+ getContext());
Operands.push_back(LoongArchOperand::createImm(Res, S, E));
return MatchOperand_Success;
}
@@ -330,6 +490,15 @@ LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
/// information, adding to Operands. Return true upon an error.
bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
StringRef Mnemonic) {
+ // Check if the current operand has a custom associated parser, if so, try to
+ // custom parse the operand, or fallback to the general approach.
+ OperandMatchResultTy Result =
+ MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
+ if (Result == MatchOperand_Success)
+ return false;
+ if (Result == MatchOperand_ParseFail)
+ return true;
+
if (parseRegister(Operands) == MatchOperand_Success ||
parseImmediate(Operands) == MatchOperand_Success)
return false;
@@ -522,8 +691,11 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
/*Upper=*/(1 << 15) - 1);
case Match_InvalidSImm12:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
- /*Upper=*/(1 << 11) - 1);
+ return generateImmOutOfRangeError(
+ Operands, ErrorInfo, /*Lower=*/-(1 << 11),
+ /*Upper=*/(1 << 11) - 1,
+ "operand must be a symbol with modifier (e.g. %pc_lo12) or an integer "
+ "in the range");
case Match_InvalidSImm14lsl2:
return generateImmOutOfRangeError(
Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
@@ -538,14 +710,21 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidSImm20:
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
/*Upper=*/(1 << 19) - 1);
+ case Match_InvalidSImm20pcalau12i:
+ return generateImmOutOfRangeError(
+ Operands, ErrorInfo, /*Lower=*/-(1 << 19),
+ /*Upper=*/(1 << 19) - 1,
+ "operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
+ "in the range");
case Match_InvalidSImm21lsl2:
return generateImmOutOfRangeError(
Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
"immediate must be a multiple of 4 in the range");
- case Match_InvalidSImm26lsl2:
+ case Match_InvalidSImm26Operand:
return generateImmOutOfRangeError(
Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
- "immediate must be a multiple of 4 in the range");
+ "operand must be a bare symbol name or an immediate must be a multiple "
+ "of 4 in the range");
}
llvm_unreachable("Unknown match type detected!");
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index de6c758bdfdda..63ffe125b5418 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -17,6 +17,7 @@
#include "LoongArchRegisterInfo.h"
#include "LoongArchSubtarget.h"
#include "LoongArchTargetMachine.h"
+#include "MCTargetDesc/LoongArchBaseInfo.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/ISDOpcodes.h"
@@ -278,10 +279,13 @@ SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
// TODO: Support dso_preemptable and target flags.
if (GV->isDSOLocal()) {
- SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty);
- SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, GA), 0);
- SDValue Addr(DAG.getMachineNode(ADDIOp, DL, Ty, AddrHi, GA), 0);
- return Addr;
+ SDValue GAHi =
+ DAG.getTargetGlobalAddress(GV, DL, Ty, 0, LoongArchII::MO_PCREL_HI);
+ SDValue GALo =
+ DAG.getTargetGlobalAddress(GV, DL, Ty, 0, LoongArchII::MO_PCREL_LO);
+ SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, GAHi), 0);
+
+ return SDValue(DAG.getMachineNode(ADDIOp, DL, Ty, AddrHi, GALo), 0);
}
report_fatal_error("Unable to lowerGlobalAddress");
}
@@ -1601,11 +1605,20 @@ 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.
- // FIXME: Add target flags for relocation.
- if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee))
- Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT);
- else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
- Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT);
+ if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ const GlobalValue *GV = S->getGlobal();
+ unsigned OpFlags =
+ getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
+ ? LoongArchII::MO_CALL
+ : LoongArchII::MO_CALL_PLT;
+ Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
+ } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
+ *MF.getFunction().getParent(), nullptr)
+ ? LoongArchII::MO_CALL
+ : LoongArchII::MO_CALL_PLT;
+ Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
+ }
// The first call operand is the chain and the second is the target address.
SmallVector<SDValue> Ops;
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index fa73ea2fbc64b..29c3255aa9189 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -150,19 +150,42 @@ def simm16_lsl2_br : Operand<OtherVT> {
let DecoderMethod = "decodeSImmOperand<16, 2>";
}
-def simm20 : Operand<GRLenVT> {
- let ParserMatchClass = SImmAsmOperand<20>;
+class SImm20Operand : Operand<GRLenVT> {
let DecoderMethod = "decodeSImmOperand<20>";
}
+def simm20 : SImm20Operand {
+ let ParserMatchClass = SImmAsmOperand<20>;
+}
+
+def simm20_pcalau12i : SImm20Operand {
+ let ParserMatchClass = SImmAsmOperand<20, "pcalau12i">;
+}
+
def simm21_lsl2 : Operand<OtherVT> {
let ParserMatchClass = SImmAsmOperand<21, "lsl2">;
let EncoderMethod = "getImmOpValueAsr2";
let DecoderMethod = "decodeSImmOperand<21, 2>";
}
-def simm26_lsl2 : Operand<OtherVT> {
- let ParserMatchClass = SImmAsmOperand<26, "lsl2">;
+// TODO: Need split the ParserMethod/PredicateMethod for call/jump/tailcall.
+def SImm26Operand: AsmOperandClass {
+ let Name = "SImm26Operand";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidSImm26Operand";
+ let ParserMethod = "parseSImm26Operand";
+}
+
+// A symbol or an imm used in B/PseudoBR.
+def simm26_b : Operand<OtherVT> {
+ let ParserMatchClass = SImm26Operand;
+ let EncoderMethod = "getImmOpValueAsr2";
+ let DecoderMethod = "decodeSImmOperand<26, 2>";
+}
+
+// A symbol or an imm used in BL/PseudoCALL.
+def simm26_bl : Operand<GRLenVT> {
+ let ParserMatchClass = SImm26Operand;
let EncoderMethod = "getImmOpValueAsr2";
let DecoderMethod = "decodeSImmOperand<26, 2>";
}
@@ -190,17 +213,6 @@ def ImmSubFrom32 : SDNodeXForm<imm, [{
N->getValueType(0));
}]>;
-def CallSymbol: AsmOperandClass {
- let Name = "CallSymbol";
- let RenderMethod = "addImmOperands";
- let PredicateMethod = "isImm";
-}
-
-// A bare symbol used in call only.
-def call_symbol : Operand<iPTR> {
- let ParserMatchClass = CallSymbol;
-}
-
def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
//===----------------------------------------------------------------------===//
@@ -259,7 +271,7 @@ class BrCCZ_1RI21<bits<6> op, string opstr>
let isTerminator = 1;
}
class Br_I26<bits<6> op, string opstr>
- : FmtI26<op, (outs), (ins simm26_lsl2:$imm26), opstr, "$imm26"> {
+ : FmtI26<op, (outs), (ins simm26_b:$imm26), opstr, "$imm26"> {
let isBranch = 1;
let isTerminator = 1;
}
@@ -323,7 +335,7 @@ def SLTI : ALU_2RI12<0b0000001000, "slti", simm12>;
def SLTUI : ALU_2RI12<0b0000001001, "sltui", simm12>;
def PCADDI : ALU_1RI20<0b0001100, "pcaddi", simm20>;
def PCADDU12I : ALU_1RI20<0b0001110, "pcaddu12i", simm20>;
-def PCALAU12I : ALU_1RI20<0b0001101, "pcalau12i", simm20>;
+def PCALAU12I : ALU_1RI20<0b0001101, "pcalau12i", simm20_pcalau12i>;
def AND : ALU_3R<0b00000000000101001, "and">;
def OR : ALU_3R<0b00000000000101010, "or">;
def NOR : ALU_3R<0b00000000000101000, "nor">;
@@ -387,8 +399,8 @@ def BEQZ : BrCCZ_1RI21<0b010000, "beqz">;
def BNEZ : BrCCZ_1RI21<0b010001, "bnez">;
def B : Br_I26<0b010100, "b">;
-let isCall = 1 in
-def BL : FmtI26<0b010101, (outs), (ins simm26_lsl2:$imm26), "bl", "$imm26">;
+let isCall = 1, Defs=[R1] in
+def BL : FmtI26<0b010101, (outs), (ins simm26_bl:$imm26), "bl", "$imm26">;
def JIRL : Fmt2RI16<0b010011, (outs GPR:$rd),
(ins GPR:$rj, simm16_lsl2:$imm16), "jirl",
"$rd, $rj, $imm16">;
@@ -827,8 +839,8 @@ def : Pat<(brcond (GRLenVT (setne GPR:$rj, 0)), bb:$imm21),
(BNEZ GPR:$rj, bb:$imm21)>;
let isBarrier = 1, isBranch = 1, isTerminator = 1 in
-def PseudoBR : Pseudo<(outs), (ins simm26_lsl2:$imm26), [(br bb:$imm26)]>,
- PseudoInstExpansion<(B simm26_lsl2:$imm26)>;
+def PseudoBR : Pseudo<(outs), (ins simm26_b:$imm26), [(br bb:$imm26)]>,
+ PseudoInstExpansion<(B simm26_b:$imm26)>;
let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
def PseudoBRIND : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16), []>,
@@ -839,7 +851,7 @@ def : Pat<(brind (add GPR:$rj, simm16_lsl2:$imm16)),
(PseudoBRIND GPR:$rj, simm16_lsl2:$imm16)>;
let isCall = 1, Defs = [R1] in
-def PseudoCALL : Pseudo<(outs), (ins call_symbol:$func), []> {
+def PseudoCALL : Pseudo<(outs), (ins simm26_bl:$func), []> {
let AsmString = "bl\t$func";
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
index 488c66f47863c..328cbb56aabf5 100644
--- a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
@@ -13,6 +13,8 @@
#include "LoongArch.h"
#include "LoongArchSubtarget.h"
+#include "MCTargetDesc/LoongArchBaseInfo.h"
+#include "MCTargetDesc/LoongArchMCExpr.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineInstr.h"
@@ -25,8 +27,28 @@ using namespace llvm;
static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
const AsmPrinter &AP) {
MCContext &Ctx = AP.OutContext;
+ LoongArchMCExpr::VariantKind Kind;
- // TODO: Processing target flags.
+ switch (MO.getTargetFlags()) {
+ default:
+ llvm_unreachable("Unknown target flag on GV operand");
+ case LoongArchII::MO_None:
+ Kind = LoongArchMCExpr::VK_LoongArch_None;
+ break;
+ case LoongArchII::MO_CALL:
+ Kind = LoongArchMCExpr::VK_LoongArch_CALL;
+ break;
+ case LoongArchII::MO_CALL_PLT:
+ Kind = LoongArchMCExpr::VK_LoongArch_CALL_PLT;
+ break;
+ case LoongArchII::MO_PCREL_HI:
+ Kind = LoongArchMCExpr::VK_LoongArch_PCREL_HI;
+ break;
+ case LoongArchII::MO_PCREL_LO:
+ Kind = LoongArchMCExpr::VK_LoongArch_PCREL_LO;
+ break;
+ // TODO: Handle more target-flags.
+ }
const MCExpr *ME =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
@@ -35,6 +57,8 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
ME = MCBinaryExpr::createAdd(
ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
+ if (Kind != LoongArchMCExpr::VK_LoongArch_None)
+ ME = LoongArchMCExpr::create(ME, Kind, Ctx);
return MCOperand::createExpr(ME);
}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt
index 42832d0ffe8eb..6b572a93e38ef 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt
@@ -5,8 +5,9 @@ add_llvm_component_library(LLVMLoongArchDesc
LoongArchELFStreamer.cpp
LoongArchInstPrinter.cpp
LoongArchMCAsmInfo.cpp
- LoongArchMCTargetDesc.cpp
LoongArchMCCodeEmitter.cpp
+ LoongArchMCExpr.cpp
+ LoongArchMCTargetDesc.cpp
LoongArchMatInt.cpp
LoongArchTargetStreamer.cpp
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
index 94a068897f8c5..ea2c92b553810 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
@@ -22,6 +22,30 @@
using namespace llvm;
+const MCFixupKindInfo &
+LoongArchAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
+ const static MCFixupKindInfo Infos[] = {
+ // This table *must* be in the order that the fixup_* kinds are defined in
+ // LoongArchFixupKinds.h.
+ //
+ // {name, offset, bits, flags}
+ {"fixup_loongarch_b26", 0, 26, 0},
+ {"fixup_loongarch_pcala_hi20", 5, 20, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_loongarch_pcala_lo12", 10, 12, MCFixupKindInfo::FKF_IsPCRel},
+ // TODO: Add more fixup kinds.
+ };
+
+ static_assert((array_lengthof(Infos)) == LoongArch::NumTargetFixupKinds,
+ "Not all fixup kinds added to Infos array");
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ return Infos[Kind - FirstTargetFixupKind];
+}
+
void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target,
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
index a5f0b816c972c..449554f55a774 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
@@ -14,6 +14,7 @@
#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHASMBACKEND_H
#include "MCTargetDesc/LoongArchBaseInfo.h"
+#include "MCTargetDesc/LoongArchFixupKinds.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCFixupKindInfo.h"
@@ -45,10 +46,11 @@ class LoongArchAsmBackend : public MCAsmBackend {
}
unsigned getNumFixupKinds() const override {
- // FIXME: Implement this when we define fixup kind
- return 0;
+ return LoongArch::NumTargetFixupKinds;
}
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override {}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
index fee247a0c02c6..72afab3ec3051 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
@@ -22,6 +22,19 @@
namespace llvm {
+// This namespace holds all of the target specific flags that instruction info
+// tracks.
+namespace LoongArchII {
+enum {
+ MO_None,
+ MO_CALL,
+ MO_CALL_PLT,
+ MO_PCREL_HI,
+ MO_PCREL_LO,
+ // TODO: Add more flags.
+};
+} // end namespace LoongArchII
+
namespace LoongArchABI {
enum ABI {
ABI_ILP32S,
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index 1850b0d8a756c..3c09b30cebe1e 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#include "MCTargetDesc/LoongArchFixupKinds.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixup.h"
@@ -52,9 +54,26 @@ unsigned LoongArchELFObjectWriter::getRelocType(MCContext &Ctx,
return Kind - FirstLiteralRelocationKind;
switch (Kind) {
- // TODO: Implement this when we defined fixup kind.
default:
+ Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type");
return ELF::R_LARCH_NONE;
+ case FK_Data_1:
+ Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
+ return ELF::R_LARCH_NONE;
+ case FK_Data_2:
+ Ctx.reportError(Fixup.getLoc(), "2-byte data relocations not supported");
+ return ELF::R_LARCH_NONE;
+ case FK_Data_4:
+ return ELF::R_LARCH_32;
+ case FK_Data_8:
+ return ELF::R_LARCH_64;
+ case LoongArch::fixup_loongarch_pcala_hi20:
+ return ELF::R_LARCH_PCALA_HI20;
+ case LoongArch::fixup_loongarch_pcala_lo12:
+ return ELF::R_LARCH_PCALA_LO12;
+ case LoongArch::fixup_loongarch_b26:
+ return ELF::R_LARCH_B26;
+ // TODO: Handle more fixup-kinds.
}
}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
new file mode 100644
index 0000000000000..46d40d304c918
--- /dev/null
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
@@ -0,0 +1,39 @@
+//===- LoongArchFixupKinds.h - LoongArch Specific Fixup Entries -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHFIXUPKINDS_H
+#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHFIXUPKINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+#undef LoongArch
+
+namespace llvm {
+namespace LoongArch {
+//
+// This table *must* be in the same order of
+// MCFixupKindInfo Infos[LoongArch::NumTargetFixupKinds] in
+// LoongArchAsmBackend.cpp.
+//
+enum Fixups {
+ // 26-bit fixup for symbol references in the b/bl instructions.
+ fixup_loongarch_b26 = FirstTargetFixupKind,
+ // 20-bit fixup corresponding to %pc_hi20(foo) for instruction pcalau12i.
+ fixup_loongarch_pcala_hi20,
+ // 12-bit fixup corresponding to %pc_lo12(foo) for instructions addi.w/d.
+ fixup_loongarch_pcala_lo12,
+ // TODO: Add more fixup kind.
+
+ // Used as a sentinel, must be the last.
+ fixup_loongarch_invalid,
+ NumTargetFixupKinds = fixup_loongarch_invalid - FirstTargetFixupKind
+};
+} // end namespace LoongArch
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
index 01a370a90403c..1a08f352b52fb 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
@@ -10,13 +10,16 @@
//
//===----------------------------------------------------------------------===//
+#include "LoongArchFixupKinds.h"
#include "MCTargetDesc/LoongArchBaseInfo.h"
+#include "MCTargetDesc/LoongArchMCExpr.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/EndianStream.h"
using namespace llvm;
@@ -40,6 +43,10 @@ class LoongArchMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
+ void expandFunctionCall(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
/// TableGen'erated function for getting the binary encoding for an
/// instruction.
uint64_t getBinaryCodeForInstr(const MCInst &MI,
@@ -68,6 +75,10 @@ class LoongArchMCCodeEmitter : public MCCodeEmitter {
unsigned getImmOpValueAsr2(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+
+ unsigned getExprOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
};
} // end namespace
@@ -82,7 +93,9 @@ LoongArchMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
if (MO.isImm())
return static_cast<unsigned>(MO.getImm());
- llvm_unreachable("Unhandled expression!");
+ // MO must be an Expr.
+ assert(MO.isExpr());
+ return getExprOpValue(MI, MO, Fixups, STI);
}
unsigned
@@ -96,9 +109,62 @@ unsigned
LoongArchMCCodeEmitter::getImmOpValueAsr2(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
- unsigned Res = MI.getOperand(OpNo).getImm();
- assert((Res & 3) == 0 && "lowest 2 bits are non-zero");
- return Res >> 2;
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ if (MO.isImm()) {
+ unsigned Res = MI.getOperand(OpNo).getImm();
+ assert((Res & 3) == 0 && "lowest 2 bits are non-zero");
+ return Res >> 2;
+ }
+
+ return getExprOpValue(MI, MO, Fixups, STI);
+}
+
+unsigned
+LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ assert(MO.isExpr() && "getExprOpValue expects only expressions");
+ const MCExpr *Expr = MO.getExpr();
+ MCExpr::ExprKind Kind = Expr->getKind();
+ LoongArch::Fixups FixupKind = LoongArch::fixup_loongarch_invalid;
+ if (Kind == MCExpr::Target) {
+ const LoongArchMCExpr *LAExpr = cast<LoongArchMCExpr>(Expr);
+
+ switch (LAExpr->getKind()) {
+ case LoongArchMCExpr::VK_LoongArch_None:
+ case LoongArchMCExpr::VK_LoongArch_Invalid:
+ llvm_unreachable("Unhandled fixup kind!");
+ case LoongArchMCExpr::VK_LoongArch_PCREL_HI:
+ FixupKind = LoongArch::fixup_loongarch_pcala_hi20;
+ break;
+ case LoongArchMCExpr::VK_LoongArch_PCREL_LO:
+ FixupKind = LoongArch::fixup_loongarch_pcala_lo12;
+ break;
+ case LoongArchMCExpr::VK_LoongArch_CALL:
+ case LoongArchMCExpr::VK_LoongArch_CALL_PLT:
+ FixupKind = LoongArch::fixup_loongarch_b26;
+ break;
+ }
+ }
+
+ assert(FixupKind != LoongArch::fixup_loongarch_invalid &&
+ "Unhandled expression!");
+
+ Fixups.push_back(
+ MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc()));
+ return 0;
+}
+
+void LoongArchMCCodeEmitter::expandFunctionCall(
+ const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCOperand Func = MI.getOperand(0);
+ MCInst TmpInst = Func.isExpr()
+ ? MCInstBuilder(LoongArch::BL).addExpr(Func.getExpr())
+ : MCInstBuilder(LoongArch::BL).addImm(Func.getImm());
+ uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ support::endian::write(OS, Binary, support::little);
}
void LoongArchMCCodeEmitter::encodeInstruction(
@@ -108,6 +174,9 @@ void LoongArchMCCodeEmitter::encodeInstruction(
// Get byte count of instruction.
unsigned Size = Desc.getSize();
+ if (MI.getOpcode() == LoongArch::PseudoCALL)
+ return expandFunctionCall(MI, OS, Fixups, STI);
+
switch (Size) {
default:
llvm_unreachable("Unhandled encodeInstruction length!");
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp
new file mode 100644
index 0000000000000..bbf6de6375569
--- /dev/null
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp
@@ -0,0 +1,82 @@
+//===-- LoongArchMCExpr.cpp - LoongArch specific MC expression classes ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the assembly expression modifiers
+// accepted by the LoongArch architecture.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoongArchMCExpr.h"
+#include "LoongArchAsmBackend.h"
+#include "LoongArchFixupKinds.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "loongarch-mcexpr"
+
+const LoongArchMCExpr *
+LoongArchMCExpr::create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx) {
+ return new (Ctx) LoongArchMCExpr(Expr, Kind);
+}
+
+void LoongArchMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ VariantKind Kind = getKind();
+ bool HasVariant =
+ ((Kind != VK_LoongArch_None) && (Kind != VK_LoongArch_CALL));
+
+ if (HasVariant)
+ OS << '%' << getVariantKindName(getKind()) << '(';
+ Expr->print(OS, MAI);
+ if (HasVariant)
+ OS << ')';
+}
+
+bool LoongArchMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ // Explicitly drop the layout and assembler to prevent any symbolic folding in
+ // the expression handling. This is required to preserve symbolic
diff erence
+ // expressions to emit the paired relocations.
+ if (!getSubExpr()->evaluateAsRelocatable(Res, nullptr, nullptr))
+ return false;
+
+ Res =
+ MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind());
+ // Custom fixup types are not valid with symbol
diff erence expressions.
+ return Res.getSymB() ? getKind() == VK_LoongArch_None : true;
+}
+
+void LoongArchMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
+ Streamer.visitUsedExpr(*getSubExpr());
+}
+
+StringRef LoongArchMCExpr::getVariantKindName(VariantKind Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Invalid ELF symbol kind");
+ case VK_LoongArch_CALL_PLT:
+ return "plt";
+ case VK_LoongArch_PCREL_HI:
+ return "pc_hi20";
+ case VK_LoongArch_PCREL_LO:
+ return "pc_lo12";
+ }
+}
+
+LoongArchMCExpr::VariantKind
+LoongArchMCExpr::getVariantKindForName(StringRef name) {
+ return StringSwitch<LoongArchMCExpr::VariantKind>(name)
+ .Case("pc_hi20", VK_LoongArch_PCREL_HI)
+ .Case("pc_lo12", VK_LoongArch_PCREL_LO)
+ .Case("plt", VK_LoongArch_CALL_PLT)
+ .Default(VK_LoongArch_Invalid);
+}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h
new file mode 100644
index 0000000000000..e37c625382d22
--- /dev/null
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h
@@ -0,0 +1,69 @@
+//= LoongArchMCExpr.h - LoongArch specific MC expression classes -*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes LoongArch-specific MCExprs, used for modifiers like
+// "%pc_hi20" or "%pc_lo12" etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHMCEXPR_H
+#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHMCEXPR_H
+
+#include "llvm/MC/MCExpr.h"
+
+namespace llvm {
+
+class StringRef;
+
+class LoongArchMCExpr : public MCTargetExpr {
+public:
+ enum VariantKind {
+ // TODO: Add more target kinds.
+ VK_LoongArch_None,
+ VK_LoongArch_CALL,
+ VK_LoongArch_CALL_PLT,
+ VK_LoongArch_PCREL_HI,
+ VK_LoongArch_PCREL_LO,
+ VK_LoongArch_Invalid // Must be the last item.
+ };
+
+private:
+ const MCExpr *Expr;
+ const VariantKind Kind;
+
+ explicit LoongArchMCExpr(const MCExpr *Expr, VariantKind Kind)
+ : Expr(Expr), Kind(Kind) {}
+
+public:
+ static const LoongArchMCExpr *create(const MCExpr *Expr, VariantKind Kind,
+ MCContext &Ctx);
+
+ VariantKind getKind() const { return Kind; }
+ const MCExpr *getSubExpr() const { return Expr; }
+
+ void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
+ bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const override;
+ void visitUsedExpr(MCStreamer &Streamer) const override;
+ MCFragment *findAssociatedFragment() const override {
+ return getSubExpr()->findAssociatedFragment();
+ }
+
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+
+ static StringRef getVariantKindName(VariantKind Kind);
+ static VariantKind getVariantKindForName(StringRef name);
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/test/CodeGen/LoongArch/analyze-branch.ll b/llvm/test/CodeGen/LoongArch/analyze-branch.ll
index 7ce61f84df384..9b61cd7f40053 100644
--- a/llvm/test/CodeGen/LoongArch/analyze-branch.ll
+++ b/llvm/test/CodeGen/LoongArch/analyze-branch.ll
@@ -19,13 +19,13 @@ define void @test_bcc_fallthrough_taken(i64 %in) nounwind {
; CHECK-NEXT: ori $a1, $zero, 42
; CHECK-NEXT: bne $a0, $a1, .LBB0_3
; CHECK-NEXT: # %bb.1: # %true
-; CHECK-NEXT: bl test_true
+; CHECK-NEXT: bl %plt(test_true)
; CHECK-NEXT: .LBB0_2: # %true
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
; CHECK-NEXT: .LBB0_3: # %false
-; CHECK-NEXT: bl test_false
+; CHECK-NEXT: bl %plt(test_false)
; CHECK-NEXT: b .LBB0_2
%tst = icmp eq i64 %in, 42
br i1 %tst, label %true, label %false, !prof !0
@@ -51,13 +51,13 @@ define void @test_bcc_fallthrough_nottaken(i64 %in) nounwind {
; CHECK-NEXT: ori $a1, $zero, 42
; CHECK-NEXT: beq $a0, $a1, .LBB1_1
; CHECK-NEXT: # %bb.3: # %false
-; CHECK-NEXT: bl test_false
+; CHECK-NEXT: bl %plt(test_false)
; CHECK-NEXT: .LBB1_2: # %true
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
; CHECK-NEXT: .LBB1_1: # %true
-; CHECK-NEXT: bl test_true
+; CHECK-NEXT: bl %plt(test_true)
; CHECK-NEXT: b .LBB1_2
%tst = icmp eq i64 %in, 42
br i1 %tst, label %true, label %false, !prof !1
diff --git a/llvm/test/CodeGen/LoongArch/bnez-beqz.ll b/llvm/test/CodeGen/LoongArch/bnez-beqz.ll
index 782dd121e666a..b4b2c3e160e2a 100644
--- a/llvm/test/CodeGen/LoongArch/bnez-beqz.ll
+++ b/llvm/test/CodeGen/LoongArch/bnez-beqz.ll
@@ -11,7 +11,7 @@ define void @bnez_i32(i32 signext %0) nounwind {
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: bnez $a0, .LBB0_2
; LA32-NEXT: # %bb.1: # %t
-; LA32-NEXT: bl bar
+; LA32-NEXT: bl %plt(bar)
; LA32-NEXT: .LBB0_2: # %f
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
@@ -23,7 +23,7 @@ define void @bnez_i32(i32 signext %0) nounwind {
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-NEXT: bnez $a0, .LBB0_2
; LA64-NEXT: # %bb.1: # %t
-; LA64-NEXT: bl bar
+; LA64-NEXT: bl %plt(bar)
; LA64-NEXT: .LBB0_2: # %f
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
@@ -47,7 +47,7 @@ define void @beqz_i32(i32 signext %0) nounwind {
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: beqz $a0, .LBB1_2
; LA32-NEXT: # %bb.1: # %t
-; LA32-NEXT: bl bar
+; LA32-NEXT: bl %plt(bar)
; LA32-NEXT: .LBB1_2: # %f
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
@@ -59,7 +59,7 @@ define void @beqz_i32(i32 signext %0) nounwind {
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-NEXT: beqz $a0, .LBB1_2
; LA64-NEXT: # %bb.1: # %t
-; LA64-NEXT: bl bar
+; LA64-NEXT: bl %plt(bar)
; LA64-NEXT: .LBB1_2: # %f
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
@@ -84,7 +84,7 @@ define void @bnez_i64(i64 %0) nounwind {
; LA32-NEXT: or $a0, $a0, $a1
; LA32-NEXT: bnez $a0, .LBB2_2
; LA32-NEXT: # %bb.1: # %t
-; LA32-NEXT: bl bar
+; LA32-NEXT: bl %plt(bar)
; LA32-NEXT: .LBB2_2: # %f
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
@@ -96,7 +96,7 @@ define void @bnez_i64(i64 %0) nounwind {
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-NEXT: bnez $a0, .LBB2_2
; LA64-NEXT: # %bb.1: # %t
-; LA64-NEXT: bl bar
+; LA64-NEXT: bl %plt(bar)
; LA64-NEXT: .LBB2_2: # %f
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
@@ -121,7 +121,7 @@ define void @beqz_i64(i64 %0) nounwind {
; LA32-NEXT: or $a0, $a0, $a1
; LA32-NEXT: beqz $a0, .LBB3_2
; LA32-NEXT: # %bb.1: # %t
-; LA32-NEXT: bl bar
+; LA32-NEXT: bl %plt(bar)
; LA32-NEXT: .LBB3_2: # %f
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
@@ -133,7 +133,7 @@ define void @beqz_i64(i64 %0) nounwind {
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-NEXT: beqz $a0, .LBB3_2
; LA64-NEXT: # %bb.1: # %t
-; LA64-NEXT: bl bar
+; LA64-NEXT: bl %plt(bar)
; LA64-NEXT: .LBB3_2: # %f
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
diff --git a/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll b/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll
index 5876786720351..28f571e5c6289 100644
--- a/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll
+++ b/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll
@@ -21,7 +21,7 @@ define i64 @caller_i128_in_regs() nounwind {
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: ori $a1, $zero, 2
; CHECK-NEXT: move $a2, $zero
-; CHECK-NEXT: bl callee_i128_in_regs
+; CHECK-NEXT: bl %plt(callee_i128_in_regs)
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
@@ -79,7 +79,7 @@ define i64 @caller_many_scalars() nounwind {
; CHECK-NEXT: ori $a6, $zero, 6
; CHECK-NEXT: ori $a7, $zero, 7
; CHECK-NEXT: move $a5, $zero
-; CHECK-NEXT: bl callee_many_scalars
+; CHECK-NEXT: bl %plt(callee_many_scalars)
; CHECK-NEXT: ld.d $ra, $sp, 24 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 32
; CHECK-NEXT: ret
@@ -131,7 +131,7 @@ define i64 @caller_large_scalars() nounwind {
; CHECK-NEXT: st.d $a0, $sp, 32
; CHECK-NEXT: addi.d $a0, $sp, 32
; CHECK-NEXT: addi.d $a1, $sp, 0
-; CHECK-NEXT: bl callee_large_scalars
+; CHECK-NEXT: bl %plt(callee_large_scalars)
; CHECK-NEXT: ld.d $ra, $sp, 72 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 80
; CHECK-NEXT: ret
@@ -196,7 +196,7 @@ define i64 @caller_large_scalars_exhausted_regs() nounwind {
; CHECK-NEXT: ori $a5, $zero, 6
; CHECK-NEXT: ori $a6, $zero, 7
; CHECK-NEXT: addi.d $a7, $sp, 48
-; CHECK-NEXT: bl callee_large_scalars_exhausted_regs
+; CHECK-NEXT: bl %plt(callee_large_scalars_exhausted_regs)
; CHECK-NEXT: ld.d $ra, $sp, 88 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 96
; CHECK-NEXT: ret
@@ -243,7 +243,7 @@ define i64 @caller_large_struct() nounwind {
; CHECK-NEXT: st.d $a0, $sp, 64
; CHECK-NEXT: st.d $a0, $sp, 32
; CHECK-NEXT: addi.d $a0, $sp, 8
-; CHECK-NEXT: bl callee_large_struct
+; CHECK-NEXT: bl %plt(callee_large_struct)
; CHECK-NEXT: ld.d $ra, $sp, 72 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 80
; CHECK-NEXT: ret
@@ -276,7 +276,7 @@ define i64 @caller_small_scalar_ret() nounwind {
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; CHECK-NEXT: bl callee_small_scalar_ret
+; CHECK-NEXT: bl %plt(callee_small_scalar_ret)
; CHECK-NEXT: addi.w $a2, $zero, -2
; CHECK-NEXT: xor $a0, $a0, $a2
; CHECK-NEXT: orn $a0, $a0, $a1
@@ -308,7 +308,7 @@ define i64 @caller_small_struct_ret() nounwind {
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; CHECK-NEXT: bl callee_small_struct_ret
+; CHECK-NEXT: bl %plt(callee_small_struct_ret)
; CHECK-NEXT: add.d $a0, $a0, $a1
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
@@ -343,7 +343,7 @@ define void @caller_large_scalar_ret() nounwind {
; CHECK-NEXT: addi.d $sp, $sp, -48
; CHECK-NEXT: st.d $ra, $sp, 40 # 8-byte Folded Spill
; CHECK-NEXT: addi.d $a0, $sp, 0
-; CHECK-NEXT: bl callee_large_scalar_ret
+; CHECK-NEXT: bl %plt(callee_large_scalar_ret)
; CHECK-NEXT: ld.d $ra, $sp, 40 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 48
; CHECK-NEXT: ret
@@ -386,7 +386,7 @@ define i64 @caller_large_struct_ret() nounwind {
; CHECK-NEXT: addi.d $sp, $sp, -48
; CHECK-NEXT: st.d $ra, $sp, 40 # 8-byte Folded Spill
; CHECK-NEXT: addi.d $a0, $sp, 8
-; CHECK-NEXT: bl callee_large_struct_ret
+; CHECK-NEXT: bl %plt(callee_large_struct_ret)
; CHECK-NEXT: ld.d $a0, $sp, 32
; CHECK-NEXT: ld.d $a1, $sp, 8
; CHECK-NEXT: add.d $a0, $a1, $a0
@@ -430,7 +430,7 @@ define i64 @caller_float_in_fpr() nounwind {
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: movgr2fr.w $fa0, $zero
; CHECK-NEXT: movgr2fr.d $fa1, $zero
-; CHECK-NEXT: bl callee_float_in_fpr
+; CHECK-NEXT: bl %plt(callee_float_in_fpr)
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
@@ -489,7 +489,7 @@ define i64 @caller_double_in_gpr_exhausted_fprs() nounwind {
; CHECK-NEXT: ori $a0, $zero, 0
; CHECK-NEXT: lu32i.d $a0, 131072
; CHECK-NEXT: lu52i.d $a0, $a0, 1026
-; CHECK-NEXT: bl callee_double_in_gpr_exhausted_fprs
+; CHECK-NEXT: bl %plt(callee_double_in_gpr_exhausted_fprs)
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
@@ -516,7 +516,7 @@ define i64 @caller_double_ret() nounwind {
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; CHECK-NEXT: bl callee_double_ret
+; CHECK-NEXT: bl %plt(callee_double_ret)
; CHECK-NEXT: movfr2gr.d $a0, $fa0
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
diff --git a/llvm/test/CodeGen/LoongArch/eh-dwarf-cfa.ll b/llvm/test/CodeGen/LoongArch/eh-dwarf-cfa.ll
index 83c47fea79108..796ada3a1a024 100644
--- a/llvm/test/CodeGen/LoongArch/eh-dwarf-cfa.ll
+++ b/llvm/test/CodeGen/LoongArch/eh-dwarf-cfa.ll
@@ -10,7 +10,7 @@ define void @dwarf() {
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
; LA32-NEXT: addi.w $a0, $sp, 16
-; LA32-NEXT: bl foo
+; LA32-NEXT: bl %plt(foo)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -22,7 +22,7 @@ define void @dwarf() {
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-NEXT: .cfi_offset 1, -8
; LA64-NEXT: addi.d $a0, $sp, 16
-; LA64-NEXT: bl foo
+; LA64-NEXT: bl %plt(foo)
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
; LA64-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/frame.ll b/llvm/test/CodeGen/LoongArch/frame.ll
index d80c6dd63f676..a3806bcd57a48 100644
--- a/llvm/test/CodeGen/LoongArch/frame.ll
+++ b/llvm/test/CodeGen/LoongArch/frame.ll
@@ -12,7 +12,7 @@ define i32 @test() nounwind {
; CHECK-NEXT: st.d $zero, $sp, 8
; CHECK-NEXT: st.d $zero, $sp, 0
; CHECK-NEXT: addi.d $a0, $sp, 4
-; CHECK-NEXT: bl test1
+; CHECK-NEXT: bl %plt(test1)
; CHECK-NEXT: move $a0, $zero
; CHECK-NEXT: ld.d $ra, $sp, 24 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 32
diff --git a/llvm/test/CodeGen/LoongArch/fsqrt.ll b/llvm/test/CodeGen/LoongArch/fsqrt.ll
index 296c3c01bd8a1..776de7f729ec4 100644
--- a/llvm/test/CodeGen/LoongArch/fsqrt.ll
+++ b/llvm/test/CodeGen/LoongArch/fsqrt.ll
@@ -36,7 +36,7 @@ define double @fsqrt_f64(double %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl sqrt
+; LA32F-NEXT: bl %plt(sqrt)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -50,7 +50,7 @@ define double @fsqrt_f64(double %a) nounwind {
; LA64F: # %bb.0:
; LA64F-NEXT: addi.d $sp, $sp, -16
; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; LA64F-NEXT: bl sqrt
+; LA64F-NEXT: bl %plt(sqrt)
; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64F-NEXT: addi.d $sp, $sp, 16
; LA64F-NEXT: ret
@@ -93,12 +93,12 @@ define double @frsqrt_f64(double %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl sqrt
+; LA32F-NEXT: bl %plt(sqrt)
; LA32F-NEXT: move $a2, $a0
; LA32F-NEXT: move $a3, $a1
; LA32F-NEXT: lu12i.w $a1, 261888
; LA32F-NEXT: move $a0, $zero
-; LA32F-NEXT: bl __divdf3
+; LA32F-NEXT: bl %plt(__divdf3)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -112,10 +112,10 @@ define double @frsqrt_f64(double %a) nounwind {
; LA64F: # %bb.0:
; LA64F-NEXT: addi.d $sp, $sp, -16
; LA64F-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; LA64F-NEXT: bl sqrt
+; LA64F-NEXT: bl %plt(sqrt)
; LA64F-NEXT: move $a1, $a0
; LA64F-NEXT: lu52i.d $a0, $zero, 1023
-; LA64F-NEXT: bl __divdf3
+; LA64F-NEXT: bl %plt(__divdf3)
; LA64F-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64F-NEXT: addi.d $sp, $sp, 16
; LA64F-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
index 5b499fa21690c..90ee9490de74e 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
@@ -9,7 +9,7 @@ define i32 @test_call_external(i32 %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl external_function
+; LA32-NEXT: bl %plt(external_function)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -18,7 +18,7 @@ define i32 @test_call_external(i32 %a) nounwind {
; LA64: # %bb.0:
; LA64-NEXT: addi.d $sp, $sp, -16
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; LA64-NEXT: bl external_function
+; LA64-NEXT: bl %plt(external_function)
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
; LA64-NEXT: ret
@@ -45,7 +45,7 @@ define i32 @test_call_defined(i32 %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl defined_function
+; LA32-NEXT: bl %plt(defined_function)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -54,7 +54,7 @@ define i32 @test_call_defined(i32 %a) nounwind {
; LA64: # %bb.0:
; LA64-NEXT: addi.d $sp, $sp, -16
; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
-; LA64-NEXT: bl defined_function
+; LA64-NEXT: bl %plt(defined_function)
; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-NEXT: addi.d $sp, $sp, 16
; LA64-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
index d1b83cdff06bf..eaa3feba36205 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
@@ -83,7 +83,7 @@ define double @convert_i64_to_double(i64 %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl __floatdidf
+; LA32-NEXT: bl %plt(__floatdidf)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -147,7 +147,7 @@ define i64 @convert_double_to_i64(double %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl __fixdfdi
+; LA32-NEXT: bl %plt(__fixdfdi)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -166,7 +166,7 @@ define i64 @convert_double_to_u64(double %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl __fixunsdfdi
+; LA32-NEXT: bl %plt(__fixunsdfdi)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -262,7 +262,7 @@ define double @convert_u64_to_double(i64 %a) nounwind {
; LA32: # %bb.0:
; LA32-NEXT: addi.w $sp, $sp, -16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT: bl __floatundidf
+; LA32-NEXT: bl %plt(__floatundidf)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
index 4a0f2ff685f3d..3661d709fb042 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
@@ -93,7 +93,7 @@ define i64 @convert_float_to_i64(float %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl __fixsfdi
+; LA32F-NEXT: bl %plt(__fixsfdi)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -102,7 +102,7 @@ define i64 @convert_float_to_i64(float %a) nounwind {
; LA32D: # %bb.0:
; LA32D-NEXT: addi.w $sp, $sp, -16
; LA32D-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32D-NEXT: bl __fixsfdi
+; LA32D-NEXT: bl %plt(__fixsfdi)
; LA32D-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32D-NEXT: addi.w $sp, $sp, 16
; LA32D-NEXT: ret
@@ -250,7 +250,7 @@ define i64 @convert_float_to_u64(float %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl __fixunssfdi
+; LA32F-NEXT: bl %plt(__fixunssfdi)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -259,7 +259,7 @@ define i64 @convert_float_to_u64(float %a) nounwind {
; LA32D: # %bb.0:
; LA32D-NEXT: addi.w $sp, $sp, -16
; LA32D-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32D-NEXT: bl __fixunssfdi
+; LA32D-NEXT: bl %plt(__fixunssfdi)
; LA32D-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32D-NEXT: addi.w $sp, $sp, 16
; LA32D-NEXT: ret
@@ -396,7 +396,7 @@ define float @convert_i64_to_float(i64 %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl __floatdisf
+; LA32F-NEXT: bl %plt(__floatdisf)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -405,7 +405,7 @@ define float @convert_i64_to_float(i64 %a) nounwind {
; LA32D: # %bb.0:
; LA32D-NEXT: addi.w $sp, $sp, -16
; LA32D-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32D-NEXT: bl __floatdisf
+; LA32D-NEXT: bl %plt(__floatdisf)
; LA32D-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32D-NEXT: addi.w $sp, $sp, 16
; LA32D-NEXT: ret
@@ -552,7 +552,7 @@ define float @convert_u64_to_float(i64 %a) nounwind {
; LA32F: # %bb.0:
; LA32F-NEXT: addi.w $sp, $sp, -16
; LA32F-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32F-NEXT: bl __floatundisf
+; LA32F-NEXT: bl %plt(__floatundisf)
; LA32F-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32F-NEXT: addi.w $sp, $sp, 16
; LA32F-NEXT: ret
@@ -561,7 +561,7 @@ define float @convert_u64_to_float(i64 %a) nounwind {
; LA32D: # %bb.0:
; LA32D-NEXT: addi.w $sp, $sp, -16
; LA32D-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32D-NEXT: bl __floatundisf
+; LA32D-NEXT: bl %plt(__floatundisf)
; LA32D-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32D-NEXT: addi.w $sp, $sp, 16
; LA32D-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/load-store-atomic.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/load-store-atomic.ll
index 8dde4251fb262..9600bf0762ff7 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/load-store-atomic.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/load-store-atomic.ll
@@ -58,7 +58,7 @@ define i64 @load_acquire_i64(ptr %ptr) {
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
; LA32-NEXT: ori $a1, $zero, 2
-; LA32-NEXT: bl __atomic_load_8
+; LA32-NEXT: bl %plt(__atomic_load_8)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -128,7 +128,7 @@ define void @store_release_i64(ptr %ptr, i64 %v) {
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
; LA32-NEXT: ori $a3, $zero, 3
-; LA32-NEXT: bl __atomic_store_8
+; LA32-NEXT: bl %plt(__atomic_store_8)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll
index 4564b8ed1c005..37a5e64b4200d 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll
@@ -11,18 +11,18 @@ define i32 @load_store_global() nounwind {
; ALL-LABEL: load_store_global:
; ALL: # %bb.0:
-; LA32NOPIC-NEXT: pcalau12i $a0, G
-; LA32NOPIC-NEXT: addi.w $a1, $a0, G
-; LA32PIC-NEXT: pcalau12i $a0, .LG$local
-; LA32PIC-NEXT: addi.w $a1, $a0, .LG$local
+; LA32NOPIC-NEXT: pcalau12i $a0, %pc_hi20(G)
+; LA32NOPIC-NEXT: addi.w $a1, $a0, %pc_lo12(G)
+; LA32PIC-NEXT: pcalau12i $a0, %pc_hi20(.LG$local)
+; LA32PIC-NEXT: addi.w $a1, $a0, %pc_lo12(.LG$local)
; LA32-NEXT: ld.w $a0, $a1, 0
; LA32-NEXT: addi.w $a0, $a0, 1
; LA32-NEXT: st.w $a0, $a1, 0
-; LA64NOPIC-NEXT: pcalau12i $a0, G
-; LA64NOPIC-NEXT: addi.d $a1, $a0, G
-; LA64PIC-NEXT: pcalau12i $a0, .LG$local
-; LA64PIC-NEXT: addi.d $a1, $a0, .LG$local
+; LA64NOPIC-NEXT: pcalau12i $a0, %pc_hi20(G)
+; LA64NOPIC-NEXT: addi.d $a1, $a0, %pc_lo12(G)
+; LA64PIC-NEXT: pcalau12i $a0, %pc_hi20(.LG$local)
+; LA64PIC-NEXT: addi.d $a1, $a0, %pc_lo12(.LG$local)
; LA64-NEXT: ld.w $a0, $a1, 0
; LA64-NEXT: addi.d $a0, $a0, 1
; LA64-NEXT: st.w $a0, $a1, 0
@@ -39,10 +39,10 @@ define i32 @load_store_global_array(i32 %a) nounwind {
; ALL-LABEL: load_store_global_array:
; ALL: # %bb.0:
-; LA32NOPIC-NEXT: pcalau12i $a1, arr
-; LA32NOPIC-NEXT: addi.w $a2, $a1, arr
-; LA32PIC-NEXT: pcalau12i $a1, .Larr$local
-; LA32PIC-NEXT: addi.w $a2, $a1, .Larr$local
+; LA32NOPIC-NEXT: pcalau12i $a1, %pc_hi20(arr)
+; LA32NOPIC-NEXT: addi.w $a2, $a1, %pc_lo12(arr)
+; LA32PIC-NEXT: pcalau12i $a1, %pc_hi20(.Larr$local)
+; LA32PIC-NEXT: addi.w $a2, $a1, %pc_lo12(.Larr$local)
; LA32-NEXT: ld.w $a1, $a2, 0
; LA32-NEXT: st.w $a0, $a2, 0
; LA32NOPIC-NEXT: ld.w $a3, $a2, 36
@@ -50,10 +50,10 @@ define i32 @load_store_global_array(i32 %a) nounwind {
; LA32PIC-NEXT: ld.w $a3, $a2, 36
; LA32PIC-NEXT: st.w $a0, $a2, 36
-; LA64NOPIC-NEXT: pcalau12i $a1, arr
-; LA64NOPIC-NEXT: addi.d $a2, $a1, arr
-; LA64PIC-NEXT: pcalau12i $a1, .Larr$local
-; LA64PIC-NEXT: addi.d $a2, $a1, .Larr$local
+; LA64NOPIC-NEXT: pcalau12i $a1, %pc_hi20(arr)
+; LA64NOPIC-NEXT: addi.d $a2, $a1, %pc_lo12(arr)
+; LA64PIC-NEXT: pcalau12i $a1, %pc_hi20(.Larr$local)
+; LA64PIC-NEXT: addi.d $a2, $a1, %pc_lo12(.Larr$local)
; LA64-NEXT: ld.w $a1, $a2, 0
; LA64-NEXT: st.w $a0, $a2, 0
; LA64NOPIC-NEXT: ld.w $a3, $a2, 36
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/sdiv-udiv-srem-urem.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/sdiv-udiv-srem-urem.ll
index a5d9214597bae..9c94bfeeadc06 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/sdiv-udiv-srem-urem.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/sdiv-udiv-srem-urem.ll
@@ -155,7 +155,7 @@ define i64 @sdiv_i64(i64 %a, i64 %b) {
; LA32-NEXT: .cfi_def_cfa_offset 16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
-; LA32-NEXT: bl __divdi3
+; LA32-NEXT: bl %plt(__divdi3)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -171,7 +171,7 @@ define i64 @sdiv_i64(i64 %a, i64 %b) {
; LA32-TRAP-NEXT: .cfi_def_cfa_offset 16
; LA32-TRAP-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-TRAP-NEXT: .cfi_offset 1, -4
-; LA32-TRAP-NEXT: bl __divdi3
+; LA32-TRAP-NEXT: bl %plt(__divdi3)
; LA32-TRAP-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-TRAP-NEXT: addi.w $sp, $sp, 16
; LA32-TRAP-NEXT: ret
@@ -336,7 +336,7 @@ define i64 @udiv_i64(i64 %a, i64 %b) {
; LA32-NEXT: .cfi_def_cfa_offset 16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
-; LA32-NEXT: bl __udivdi3
+; LA32-NEXT: bl %plt(__udivdi3)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -352,7 +352,7 @@ define i64 @udiv_i64(i64 %a, i64 %b) {
; LA32-TRAP-NEXT: .cfi_def_cfa_offset 16
; LA32-TRAP-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-TRAP-NEXT: .cfi_offset 1, -4
-; LA32-TRAP-NEXT: bl __udivdi3
+; LA32-TRAP-NEXT: bl %plt(__udivdi3)
; LA32-TRAP-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-TRAP-NEXT: addi.w $sp, $sp, 16
; LA32-TRAP-NEXT: ret
@@ -521,7 +521,7 @@ define i64 @srem_i64(i64 %a, i64 %b) {
; LA32-NEXT: .cfi_def_cfa_offset 16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
-; LA32-NEXT: bl __moddi3
+; LA32-NEXT: bl %plt(__moddi3)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -537,7 +537,7 @@ define i64 @srem_i64(i64 %a, i64 %b) {
; LA32-TRAP-NEXT: .cfi_def_cfa_offset 16
; LA32-TRAP-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-TRAP-NEXT: .cfi_offset 1, -4
-; LA32-TRAP-NEXT: bl __moddi3
+; LA32-TRAP-NEXT: bl %plt(__moddi3)
; LA32-TRAP-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-TRAP-NEXT: addi.w $sp, $sp, 16
; LA32-TRAP-NEXT: ret
@@ -706,7 +706,7 @@ define i64 @urem_i64(i64 %a, i64 %b) {
; LA32-NEXT: .cfi_def_cfa_offset 16
; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-NEXT: .cfi_offset 1, -4
-; LA32-NEXT: bl __umoddi3
+; LA32-NEXT: bl %plt(__umoddi3)
; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-NEXT: addi.w $sp, $sp, 16
; LA32-NEXT: ret
@@ -722,7 +722,7 @@ define i64 @urem_i64(i64 %a, i64 %b) {
; LA32-TRAP-NEXT: .cfi_def_cfa_offset 16
; LA32-TRAP-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
; LA32-TRAP-NEXT: .cfi_offset 1, -4
-; LA32-TRAP-NEXT: bl __umoddi3
+; LA32-TRAP-NEXT: bl %plt(__umoddi3)
; LA32-TRAP-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
; LA32-TRAP-NEXT: addi.w $sp, $sp, 16
; LA32-TRAP-NEXT: ret
diff --git a/llvm/test/CodeGen/LoongArch/vararg.ll b/llvm/test/CodeGen/LoongArch/vararg.ll
index 94c6f93cc24dc..90881e2aa4cbd 100644
--- a/llvm/test/CodeGen/LoongArch/vararg.ll
+++ b/llvm/test/CodeGen/LoongArch/vararg.ll
@@ -132,7 +132,7 @@ define i64 @va1_va_arg_alloca(ptr %fmt, ...) nounwind {
; LA64-FPELIM-NEXT: st.d $s0, $fp, 8
; LA64-FPELIM-NEXT: sub.d $a0, $sp, $a0
; LA64-FPELIM-NEXT: move $sp, $a0
-; LA64-FPELIM-NEXT: bl notdead
+; LA64-FPELIM-NEXT: bl %plt(notdead)
; LA64-FPELIM-NEXT: move $a0, $s0
; LA64-FPELIM-NEXT: addi.d $sp, $fp, -32
; LA64-FPELIM-NEXT: ld.d $s0, $sp, 8 # 8-byte Folded Reload
@@ -163,7 +163,7 @@ define i64 @va1_va_arg_alloca(ptr %fmt, ...) nounwind {
; LA64-WITHFP-NEXT: st.d $s0, $fp, 8
; LA64-WITHFP-NEXT: sub.d $a0, $sp, $a0
; LA64-WITHFP-NEXT: move $sp, $a0
-; LA64-WITHFP-NEXT: bl notdead
+; LA64-WITHFP-NEXT: bl %plt(notdead)
; LA64-WITHFP-NEXT: move $a0, $s0
; LA64-WITHFP-NEXT: addi.d $sp, $fp, -32
; LA64-WITHFP-NEXT: ld.d $s0, $sp, 8 # 8-byte Folded Reload
@@ -187,7 +187,7 @@ define void @va1_caller() nounwind {
; LA64-FPELIM-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; LA64-FPELIM-NEXT: lu52i.d $a1, $zero, 1023
; LA64-FPELIM-NEXT: ori $a2, $zero, 2
-; LA64-FPELIM-NEXT: bl va1
+; LA64-FPELIM-NEXT: bl %plt(va1)
; LA64-FPELIM-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-FPELIM-NEXT: addi.d $sp, $sp, 16
; LA64-FPELIM-NEXT: ret
@@ -200,7 +200,7 @@ define void @va1_caller() nounwind {
; LA64-WITHFP-NEXT: addi.d $fp, $sp, 16
; LA64-WITHFP-NEXT: lu52i.d $a1, $zero, 1023
; LA64-WITHFP-NEXT: ori $a2, $zero, 2
-; LA64-WITHFP-NEXT: bl va1
+; LA64-WITHFP-NEXT: bl %plt(va1)
; LA64-WITHFP-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: addi.d $sp, $sp, 16
@@ -230,7 +230,7 @@ define void @va_aligned_register_caller() nounwind {
; LA64-FPELIM-NEXT: ori $a0, $zero, 2
; LA64-FPELIM-NEXT: ori $a1, $zero, 1111
; LA64-FPELIM-NEXT: move $a2, $zero
-; LA64-FPELIM-NEXT: bl va_aligned_register
+; LA64-FPELIM-NEXT: bl %plt(va_aligned_register)
; LA64-FPELIM-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-FPELIM-NEXT: addi.d $sp, $sp, 16
; LA64-FPELIM-NEXT: ret
@@ -252,7 +252,7 @@ define void @va_aligned_register_caller() nounwind {
; LA64-WITHFP-NEXT: ori $a0, $zero, 2
; LA64-WITHFP-NEXT: ori $a1, $zero, 1111
; LA64-WITHFP-NEXT: move $a2, $zero
-; LA64-WITHFP-NEXT: bl va_aligned_register
+; LA64-WITHFP-NEXT: bl %plt(va_aligned_register)
; LA64-WITHFP-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: addi.d $sp, $sp, 16
@@ -302,7 +302,7 @@ define void @va_aligned_stack_caller() nounwind {
; LA64-FPELIM-NEXT: ori $a0, $zero, 1
; LA64-FPELIM-NEXT: move $a6, $zero
; LA64-FPELIM-NEXT: move $a7, $a0
-; LA64-FPELIM-NEXT: bl va_aligned_stack_callee
+; LA64-FPELIM-NEXT: bl %plt(va_aligned_stack_callee)
; LA64-FPELIM-NEXT: ld.d $ra, $sp, 104 # 8-byte Folded Reload
; LA64-FPELIM-NEXT: addi.d $sp, $sp, 112
; LA64-FPELIM-NEXT: ret
@@ -343,7 +343,7 @@ define void @va_aligned_stack_caller() nounwind {
; LA64-WITHFP-NEXT: ori $a0, $zero, 1
; LA64-WITHFP-NEXT: move $a6, $zero
; LA64-WITHFP-NEXT: move $a7, $a0
-; LA64-WITHFP-NEXT: bl va_aligned_stack_callee
+; LA64-WITHFP-NEXT: bl %plt(va_aligned_stack_callee)
; LA64-WITHFP-NEXT: ld.d $fp, $sp, 96 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: ld.d $ra, $sp, 104 # 8-byte Folded Reload
; LA64-WITHFP-NEXT: addi.d $sp, $sp, 112
diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s
index 94b3976f5bfd0..861d382688c11 100644
--- a/llvm/test/MC/LoongArch/Basic/Integer/invalid.s
+++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s
@@ -44,29 +44,29 @@ xori $a0, $a0, 4096
## simm12
addi.w $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:18: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
slti $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
sltui $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:17: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
preld 0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:15: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:15: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.b $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.h $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.w $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.bu $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:17: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.hu $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:17: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
st.b $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
st.h $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
st.w $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
## simm14_lsl2
ll.w $a0, $a0, -32772
@@ -101,8 +101,10 @@ pcaddi $a0, -0x80001
# CHECK: :[[#@LINE-1]]:13: error: immediate must be an integer in the range [-524288, 524287]
pcaddu12i $a0, 0x80000
# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287]
+
+## simm20_pcalau12i
pcalau12i $a0, 0x80000
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_hi20) or an integer in the range [-524288, 524287]
## simm21_lsl2
beqz $a0, -0x400001
@@ -116,13 +118,13 @@ bnez $a0, 0x400000
## simm26_lsl2
b -0x8000001
-# CHECK: :[[#@LINE-1]]:3: error: immediate must be a multiple of 4 in the range [-134217728, 134217724]
+# CHECK: :[[#@LINE-1]]:3: error: operand must be a bare symbol name or an immediate must be a multiple of 4 in the range [-134217728, 134217724]
b 0x1
-# CHECK: :[[#@LINE-1]]:3: error: immediate must be a multiple of 4 in the range [-134217728, 134217724]
+# CHECK: :[[#@LINE-1]]:3: error: operand must be a bare symbol name or an immediate must be a multiple of 4 in the range [-134217728, 134217724]
bl 0x7FFFFFF
-# CHECK: :[[#@LINE-1]]:4: error: immediate must be a multiple of 4 in the range [-134217728, 134217724]
+# CHECK: :[[#@LINE-1]]:4: error: operand must be a bare symbol name or an immediate must be a multiple of 4 in the range [-134217728, 134217724]
bl 0x8000000
-# CHECK: :[[#@LINE-1]]:4: error: immediate must be a multiple of 4 in the range [-134217728, 134217724]
+# CHECK: :[[#@LINE-1]]:4: error: operand must be a bare symbol name or an immediate must be a multiple of 4 in the range [-134217728, 134217724]
## Invalid mnemonics
nori $a0, $a0, 0
diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s
index a8b175a886cc3..e910a3b086ff9 100644
--- a/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s
+++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s
@@ -31,15 +31,15 @@ bstrpick.d $a0, $a0, 64, 0
## simm12
addi.d $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:18: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
lu52i.d $a0, $a0, -2049
-# CHECK: :[[#@LINE-1]]:19: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:19: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.wu $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:17: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
ld.d $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
st.d $a0, $a0, 2048
-# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047]
+# CHECK: :[[#@LINE-1]]:16: error: operand must be a symbol with modifier (e.g. %pc_lo12) or an integer in the range [-2048, 2047]
## simm14_lsl2
ldptr.w $a0, $a0, -32772
diff --git a/llvm/test/MC/LoongArch/Relocations/relocations.s b/llvm/test/MC/LoongArch/Relocations/relocations.s
new file mode 100644
index 0000000000000..a6bc7c80471a1
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Relocations/relocations.s
@@ -0,0 +1,55 @@
+# RUN: llvm-mc --triple=loongarch64 < %s --show-encoding \
+# RUN: | FileCheck --check-prefixes=INSTR,FIXUP %s
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 < %s \
+# RUN: | llvm-readobj -r - | FileCheck --check-prefix=RELOC %s
+
+## Check prefixes:
+## RELOC - Check the relocation in the object.
+## FIXUP - Check the fixup on the instruction.
+## INSTR - Check the instruction is handled properly by the ASMPrinter.
+
+.long foo
+# RELOC: R_LARCH_32 foo
+
+.quad foo
+# RELOC: R_LARCH_64 foo
+
+pcalau12i $t1, %pc_hi20(foo)
+# RELOC: R_LARCH_PCALA_HI20 foo 0x0
+# INSTR: pcalau12i $t1, %pc_hi20(foo)
+# FIXUP: fixup A - offset: 0, value: %pc_hi20(foo), kind: fixup_loongarch_pcala_hi20
+
+pcalau12i $t1, %pc_hi20(foo+4)
+# RELOC: R_LARCH_PCALA_HI20 foo 0x4
+# INSTR: pcalau12i $t1, %pc_hi20(foo+4)
+# FIXUP: fixup A - offset: 0, value: %pc_hi20(foo+4), kind: fixup_loongarch_pcala_hi20
+
+addi.d $t1, $t1, %pc_lo12(foo)
+# RELOC: R_LARCH_PCALA_LO12 foo 0x0
+# INSTR: addi.d $t1, $t1, %pc_lo12(foo)
+# FIXUP: fixup A - offset: 0, value: %pc_lo12(foo), kind: fixup_loongarch_pcala_lo12
+
+addi.d $t1, $t1, %pc_lo12(foo+4)
+# RELOC: R_LARCH_PCALA_LO12 foo 0x4
+# INSTR: addi.d $t1, $t1, %pc_lo12(foo+4)
+# FIXUP: fixup A - offset: 0, value: %pc_lo12(foo+4), kind: fixup_loongarch_pcala_lo12
+
+st.b $t1, $a2, %pc_lo12(foo)
+# RELOC: R_LARCH_PCALA_LO12 foo 0x0
+# INSTR: st.b $t1, $a2, %pc_lo12(foo)
+# FIXUP: fixup A - offset: 0, value: %pc_lo12(foo), kind: fixup_loongarch_pcala_lo12
+
+st.b $t1, $a2, %pc_lo12(foo+4)
+# RELOC: R_LARCH_PCALA_LO12 foo 0x4
+# INSTR: st.b $t1, $a2, %pc_lo12(foo+4)
+# FIXUP: fixup A - offset: 0, value: %pc_lo12(foo+4), kind: fixup_loongarch_pcala_lo12
+
+bl %plt(foo)
+# RELOC: R_LARCH_B26
+# INSTR: bl %plt(foo)
+# FIXUP: fixup A - offset: 0, value: %plt(foo), kind: fixup_loongarch_b26
+
+bl foo
+# RELOC: R_LARCH_B26
+# INSTR: bl foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_loongarch_b26
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected
index b2ba71c8292d7..5aef9c356c655 100644
--- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected
@@ -121,8 +121,8 @@ attributes #0 = { noredzone nounwind ssp uwtable "frame-pointer"="all" }
; CHECK-NEXT: .cfi_offset 22, -8
; CHECK-NEXT: addi.w $fp, $sp, 32
; CHECK-NEXT: .cfi_def_cfa 22, 0
-; CHECK-NEXT: pcalau12i $a0, x
-; CHECK-NEXT: addi.w $a0, $a0, x
+; CHECK-NEXT: pcalau12i $a0, %pc_hi20(x)
+; CHECK-NEXT: addi.w $a0, $a0, %pc_lo12(x)
; CHECK-NEXT: ori $a1, $zero, 1
; CHECK-NEXT: st.w $a1, $a0, 0
; CHECK-NEXT: st.w $zero, $fp, -12
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected
index acccb9923b7d6..d816f29355d4f 100644
--- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected
@@ -98,8 +98,8 @@ define dso_local i32 @main() #0 {
; CHECK-NEXT: .cfi_offset 22, -8
; CHECK-NEXT: addi.w $fp, $sp, 32
; CHECK-NEXT: .cfi_def_cfa 22, 0
-; CHECK-NEXT: pcalau12i $a0, x
-; CHECK-NEXT: addi.w $a0, $a0, x
+; CHECK-NEXT: pcalau12i $a0, %pc_hi20(x)
+; CHECK-NEXT: addi.w $a0, $a0, %pc_lo12(x)
; CHECK-NEXT: ori $a1, $zero, 1
; CHECK-NEXT: st.w $a1, $a0, 0
; CHECK-NEXT: st.w $zero, $fp, -12
More information about the llvm-commits
mailing list