2121#include " llvm/MC/MCExpr.h"
2222#include " llvm/MC/MCInst.h"
2323#include " llvm/MC/MCInstBuilder.h"
24+ #include " llvm/MC/MCObjectFileInfo.h"
2425#include " llvm/MC/MCParser/MCAsmLexer.h"
2526#include " llvm/MC/MCParser/MCParsedAsmOperand.h"
2627#include " llvm/MC/MCParser/MCTargetAsmParser.h"
@@ -79,9 +80,18 @@ class RISCVAsmParser : public MCTargetAsmParser {
7980 // synthesize the desired immedate value into the destination register.
8081 void emitLoadImm (unsigned DestReg, int64_t Value, MCStreamer &Out);
8182
83+ // Helper to emit a combination of AUIPC and SecondOpcode. Used to implement
84+ // helpers such as emitLoadLocalAddress and emitLoadAddress.
85+ void emitAuipcInstPair (MCOperand DestReg, MCOperand TmpReg,
86+ const MCExpr *Symbol, RISCVMCExpr::VariantKind VKHi,
87+ unsigned SecondOpcode, SMLoc IDLoc, MCStreamer &Out);
88+
8289 // Helper to emit pseudo instruction "lla" used in PC-rel addressing.
8390 void emitLoadLocalAddress (MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
8491
92+ // Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing.
93+ void emitLoadAddress (MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
94+
8595 // / Helper for processing MC instructions that have been successfully matched
8696 // / by MatchAndEmitInstruction. Modifications to the emitted instructions,
8797 // / like the expansion of pseudo instructions (e.g., "li"), can be performed
@@ -505,10 +515,12 @@ struct RISCVOperand : public MCParsedAsmOperand {
505515 bool IsConstantImm = evaluateConstantImm (getImm (), Imm, VK);
506516 if (!IsConstantImm) {
507517 IsValid = RISCVAsmParser::classifySymbolRef (getImm (), VK, Imm);
508- return IsValid && VK == RISCVMCExpr::VK_RISCV_PCREL_HI;
518+ return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
519+ VK == RISCVMCExpr::VK_RISCV_GOT_HI);
509520 } else {
510521 return isUInt<20 >(Imm) && (VK == RISCVMCExpr::VK_RISCV_None ||
511- VK == RISCVMCExpr::VK_RISCV_PCREL_HI);
522+ VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
523+ VK == RISCVMCExpr::VK_RISCV_GOT_HI);
512524 }
513525 }
514526
@@ -861,8 +873,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
861873 case Match_InvalidUImm20AUIPC:
862874 return generateImmOutOfRangeError (
863875 Operands, ErrorInfo, 0 , (1 << 20 ) - 1 ,
864- " operand must be a symbol with %pcrel_hi() modifier or an integer in "
865- " the range" );
876+ " operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier "
877+ " or an integer in the range" );
866878 case Match_InvalidSImm21Lsb0JAL:
867879 return generateImmOutOfRangeError (
868880 Operands, ErrorInfo, -(1 << 20 ), (1 << 20 ) - 2 ,
@@ -1408,42 +1420,82 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
14081420 }
14091421}
14101422
1411- void RISCVAsmParser::emitLoadLocalAddress (MCInst &Inst, SMLoc IDLoc ,
1412- MCStreamer &Out) {
1413- // The local load address pseudo-instruction "lla" is used in PC-relative
1414- // addressing of symbols:
1415- // lla rdest, symbol
1416- // expands to
1417- // TmpLabel: AUIPC rdest, %pcrel_hi (symbol)
1418- // ADDI rdest , %pcrel_lo(TmpLabel)
1423+ void RISCVAsmParser::emitAuipcInstPair (MCOperand DestReg, MCOperand TmpReg ,
1424+ const MCExpr *Symbol,
1425+ RISCVMCExpr::VariantKind VKHi,
1426+ unsigned SecondOpcode, SMLoc IDLoc,
1427+ MCStreamer &Out) {
1428+ // A pair of instructions for PC-relative addressing; expands to
1429+ // TmpLabel: AUIPC TmpReg, VKHi (symbol)
1430+ // OP DestReg, TmpReg , %pcrel_lo(TmpLabel)
14191431 MCContext &Ctx = getContext ();
14201432
14211433 MCSymbol *TmpLabel = Ctx.createTempSymbol (
14221434 " pcrel_hi" , /* AlwaysAddSuffix */ true , /* CanBeUnnamed */ false );
14231435 Out.EmitLabel (TmpLabel);
14241436
1425- MCOperand DestReg = Inst.getOperand (0 );
1426- const RISCVMCExpr *Symbol = RISCVMCExpr::create (
1427- Inst.getOperand (1 ).getExpr (), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
1428-
1437+ const RISCVMCExpr *SymbolHi = RISCVMCExpr::create (Symbol, VKHi, Ctx);
14291438 emitToStreamer (
1430- Out, MCInstBuilder (RISCV::AUIPC).addOperand (DestReg ).addExpr (Symbol ));
1439+ Out, MCInstBuilder (RISCV::AUIPC).addOperand (TmpReg ).addExpr (SymbolHi ));
14311440
14321441 const MCExpr *RefToLinkTmpLabel =
14331442 RISCVMCExpr::create (MCSymbolRefExpr::create (TmpLabel, Ctx),
14341443 RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx);
14351444
1436- emitToStreamer (Out, MCInstBuilder (RISCV::ADDI)
1437- .addOperand (DestReg)
1445+ emitToStreamer (Out, MCInstBuilder (SecondOpcode)
14381446 .addOperand (DestReg)
1447+ .addOperand (TmpReg)
14391448 .addExpr (RefToLinkTmpLabel));
14401449}
14411450
1451+ void RISCVAsmParser::emitLoadLocalAddress (MCInst &Inst, SMLoc IDLoc,
1452+ MCStreamer &Out) {
1453+ // The load local address pseudo-instruction "lla" is used in PC-relative
1454+ // addressing of local symbols:
1455+ // lla rdest, symbol
1456+ // expands to
1457+ // TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1458+ // ADDI rdest, rdest, %pcrel_lo(TmpLabel)
1459+ MCOperand DestReg = Inst.getOperand (0 );
1460+ const MCExpr *Symbol = Inst.getOperand (1 ).getExpr ();
1461+ emitAuipcInstPair (DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI,
1462+ RISCV::ADDI, IDLoc, Out);
1463+ }
1464+
1465+ void RISCVAsmParser::emitLoadAddress (MCInst &Inst, SMLoc IDLoc,
1466+ MCStreamer &Out) {
1467+ // The load address pseudo-instruction "la" is used in PC-relative and
1468+ // GOT-indirect addressing of global symbols:
1469+ // la rdest, symbol
1470+ // expands to either (for non-PIC)
1471+ // TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1472+ // ADDI rdest, rdest, %pcrel_lo(TmpLabel)
1473+ // or (for PIC)
1474+ // TmpLabel: AUIPC rdest, %got_pcrel_hi(symbol)
1475+ // Lx rdest, %pcrel_lo(TmpLabel)(rdest)
1476+ MCOperand DestReg = Inst.getOperand (0 );
1477+ const MCExpr *Symbol = Inst.getOperand (1 ).getExpr ();
1478+ unsigned SecondOpcode;
1479+ RISCVMCExpr::VariantKind VKHi;
1480+ // FIXME: Should check .option (no)pic when implemented
1481+ if (getContext ().getObjectFileInfo ()->isPositionIndependent ()) {
1482+ SecondOpcode = isRV64 () ? RISCV::LD : RISCV::LW;
1483+ VKHi = RISCVMCExpr::VK_RISCV_GOT_HI;
1484+ } else {
1485+ SecondOpcode = RISCV::ADDI;
1486+ VKHi = RISCVMCExpr::VK_RISCV_PCREL_HI;
1487+ }
1488+ emitAuipcInstPair (DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out);
1489+ }
1490+
14421491bool RISCVAsmParser::processInstruction (MCInst &Inst, SMLoc IDLoc,
14431492 MCStreamer &Out) {
14441493 Inst.setLoc (IDLoc);
14451494
1446- if (Inst.getOpcode () == RISCV::PseudoLI) {
1495+ switch (Inst.getOpcode ()) {
1496+ default :
1497+ break ;
1498+ case RISCV::PseudoLI: {
14471499 unsigned Reg = Inst.getOperand (0 ).getReg ();
14481500 const MCOperand &Op1 = Inst.getOperand (1 );
14491501 if (Op1.isExpr ()) {
@@ -1463,9 +1515,13 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
14631515 Imm = SignExtend64<32 >(Imm);
14641516 emitLoadImm (Reg, Imm, Out);
14651517 return false ;
1466- } else if (Inst.getOpcode () == RISCV::PseudoLLA) {
1518+ }
1519+ case RISCV::PseudoLLA:
14671520 emitLoadLocalAddress (Inst, IDLoc, Out);
14681521 return false ;
1522+ case RISCV::PseudoLA:
1523+ emitLoadAddress (Inst, IDLoc, Out);
1524+ return false ;
14691525 }
14701526
14711527 emitToStreamer (Out, Inst);
0 commit comments