diff options
Diffstat (limited to 'lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp')
-rw-r--r-- | lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 393 |
1 files changed, 345 insertions, 48 deletions
diff --git a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 1d1112cc5124..0172c6298772 100644 --- a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -1,9 +1,8 @@ //===-- RISCVAsmParser.cpp - Parse RISCV assembly to MCInst instructions --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -11,6 +10,7 @@ #include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "MCTargetDesc/RISCVTargetStreamer.h" +#include "TargetInfo/RISCVTargetInfo.h" #include "Utils/RISCVBaseInfo.h" #include "Utils/RISCVMatInt.h" #include "llvm/ADT/STLExtras.h" @@ -21,6 +21,7 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" @@ -47,6 +48,7 @@ class RISCVAsmParser : public MCTargetAsmParser { SMLoc getLoc() const { return getParser().getTok().getLoc(); } bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); } + bool isRV32E() const { return getSTI().hasFeature(RISCV::FeatureRV32E); } RISCVTargetStreamer &getTargetStreamer() { MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); @@ -79,14 +81,42 @@ class RISCVAsmParser : public MCTargetAsmParser { // synthesize the desired immedate value into the destination register. void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out); + // Helper to emit a combination of AUIPC and SecondOpcode. Used to implement + // helpers such as emitLoadLocalAddress and emitLoadAddress. + void emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg, + const MCExpr *Symbol, RISCVMCExpr::VariantKind VKHi, + unsigned SecondOpcode, SMLoc IDLoc, MCStreamer &Out); + // Helper to emit pseudo instruction "lla" used in PC-rel addressing. void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); + // Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing. + void emitLoadAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); + + // Helper to emit pseudo instruction "la.tls.ie" used in initial-exec TLS + // addressing. + void emitLoadTLSIEAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); + + // Helper to emit pseudo instruction "la.tls.gd" used in global-dynamic TLS + // addressing. + void emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); + + // Helper to emit pseudo load/store instruction with a symbol. + void emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, + MCStreamer &Out, bool HasTmpReg); + + // Checks that a PseudoAddTPRel is using x4/tp in its second input operand. + // Enforcing this using a restricted register class for the second input + // operand of PseudoAddTPRel results in a poor diagnostic due to the fact + // 'add' is an overloaded mnemonic. + bool checkPseudoAddTPRel(MCInst &Inst, OperandVector &Operands); + /// Helper for processing MC instructions that have been successfully matched /// by MatchAndEmitInstruction. Modifications to the emitted instructions, /// like the expansion of pseudo instructions (e.g., "li"), can be performed /// in this method. - bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); + bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, + MCStreamer &Out); // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER @@ -99,6 +129,7 @@ class RISCVAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); OperandMatchResultTy parseBareSymbol(OperandVector &Operands); + OperandMatchResultTy parseCallSymbol(OperandVector &Operands); OperandMatchResultTy parseJALOffset(OperandVector &Operands); bool parseOperand(OperandVector &Operands, StringRef Mnemonic); @@ -269,6 +300,27 @@ public: VK == RISCVMCExpr::VK_RISCV_None; } + bool isCallSymbol() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + // Must be of 'immediate' type but not a constant. + if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) + return false; + return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) && + (VK == RISCVMCExpr::VK_RISCV_CALL || + VK == RISCVMCExpr::VK_RISCV_CALL_PLT); + } + + bool isTPRelAddSymbol() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + // Must be of 'immediate' type but not a constant. + if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) + return false; + return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) && + VK == RISCVMCExpr::VK_RISCV_TPREL_ADD; + } + bool isCSRSystemRegister() const { return isSystemRegister(); } /// Return true if the operand is a valid for the fence instruction e.g. @@ -463,7 +515,8 @@ public: IsValid = isInt<12>(Imm); return IsValid && ((IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None) || VK == RISCVMCExpr::VK_RISCV_LO || - VK == RISCVMCExpr::VK_RISCV_PCREL_LO); + VK == RISCVMCExpr::VK_RISCV_PCREL_LO || + VK == RISCVMCExpr::VK_RISCV_TPREL_LO); } bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } @@ -489,10 +542,12 @@ public: bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); if (!IsConstantImm) { IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); - return IsValid && VK == RISCVMCExpr::VK_RISCV_HI; + return IsValid && (VK == RISCVMCExpr::VK_RISCV_HI || + VK == RISCVMCExpr::VK_RISCV_TPREL_HI); } else { return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || - VK == RISCVMCExpr::VK_RISCV_HI); + VK == RISCVMCExpr::VK_RISCV_HI || + VK == RISCVMCExpr::VK_RISCV_TPREL_HI); } } @@ -505,10 +560,16 @@ public: bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); if (!IsConstantImm) { IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); - return IsValid && VK == RISCVMCExpr::VK_RISCV_PCREL_HI; + return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI); } else { return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || - VK == RISCVMCExpr::VK_RISCV_PCREL_HI); + VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI); } } @@ -753,7 +814,7 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, default: break; case Match_Success: - return processInstruction(Inst, IDLoc, Out); + return processInstruction(Inst, IDLoc, Operands, Out); case Match_MissingFeature: return Error(IDLoc, "instruction use requires an option to be enabled"); case Match_MnemonicFail: @@ -844,8 +905,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidSImm12: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1, - "operand must be a symbol with %lo/%pcrel_lo modifier or an integer in " - "the range"); + "operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an " + "integer in the range"); case Match_InvalidSImm12Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 11), (1 << 11) - 2, @@ -856,13 +917,15 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidUImm20LUI: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 20) - 1, - "operand must be a symbol with %hi() " - "modifier or an integer in the range"); + "operand must be a symbol with " + "%hi/%tprel_hi modifier or an integer in " + "the range"); case Match_InvalidUImm20AUIPC: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 20) - 1, - "operand must be a symbol with %pcrel_hi() modifier or an integer in " - "the range"); + "operand must be a symbol with a " + "%pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or " + "an integer in the range"); case Match_InvalidSImm21Lsb0JAL: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, @@ -888,11 +951,33 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a bare symbol name"); } + case Match_InvalidCallSymbol: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be a bare symbol name"); + } + case Match_InvalidTPRelAddSymbol: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be a symbol with %tprel_add modifier"); + } } llvm_unreachable("Unknown match type detected!"); } +// Attempts to match Name as a register (either using the default name or +// alternative ABI names), setting RegNo to the matching register. Upon +// failure, returns true and sets RegNo to 0. If IsRV32E then registers +// x16-x31 will be rejected. +static bool matchRegisterNameHelper(bool IsRV32E, unsigned &RegNo, + StringRef Name) { + RegNo = MatchRegisterName(Name); + if (RegNo == 0) + RegNo = MatchRegisterAltName(Name); + if (IsRV32E && RegNo >= RISCV::X16 && RegNo <= RISCV::X31) + RegNo = 0; + return RegNo == 0; +} + bool RISCVAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { const AsmToken &Tok = getParser().getTok(); @@ -901,42 +986,45 @@ bool RISCVAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, RegNo = 0; StringRef Name = getLexer().getTok().getIdentifier(); - if (!MatchRegisterName(Name) || !MatchRegisterAltName(Name)) { - getParser().Lex(); // Eat identifier token. - return false; - } + if (matchRegisterNameHelper(isRV32E(), RegNo, Name)) + return Error(StartLoc, "invalid register name"); - return Error(StartLoc, "invalid register name"); + getParser().Lex(); // Eat identifier token. + return false; } OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands, bool AllowParens) { SMLoc FirstS = getLoc(); bool HadParens = false; - AsmToken Buf[2]; + AsmToken LParen; - // If this a parenthesised register name is allowed, parse it atomically + // If this is an LParen and a parenthesised register name is allowed, parse it + // atomically. if (AllowParens && getLexer().is(AsmToken::LParen)) { + AsmToken Buf[2]; size_t ReadCount = getLexer().peekTokens(Buf); if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { HadParens = true; + LParen = getParser().getTok(); getParser().Lex(); // Eat '(' } } switch (getLexer().getKind()) { default: + if (HadParens) + getLexer().UnLex(LParen); return MatchOperand_NoMatch; case AsmToken::Identifier: StringRef Name = getLexer().getTok().getIdentifier(); - unsigned RegNo = MatchRegisterName(Name); + unsigned RegNo; + matchRegisterNameHelper(isRV32E(), RegNo, Name); + if (RegNo == 0) { - RegNo = MatchRegisterAltName(Name); - if (RegNo == 0) { - if (HadParens) - getLexer().UnLex(Buf[0]); - return MatchOperand_NoMatch; - } + if (HadParens) + getLexer().UnLex(LParen); + return MatchOperand_NoMatch; } if (HadParens) Operands.push_back(RISCVOperand::createToken("(", FirstS, isRV64())); @@ -965,6 +1053,8 @@ RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { case AsmToken::LParen: case AsmToken::Minus: case AsmToken::Plus: + case AsmToken::Exclaim: + case AsmToken::Tilde: case AsmToken::Integer: case AsmToken::String: { if (getParser().parseExpression(Res)) @@ -1029,8 +1119,11 @@ OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { 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: @@ -1094,11 +1187,54 @@ OperandMatchResultTy RISCVAsmParser::parseBareSymbol(OperandVector &Operands) { return MatchOperand_NoMatch; StringRef Identifier; + AsmToken Tok = getLexer().getTok(); + + if (getParser().parseIdentifier(Identifier)) + return MatchOperand_ParseFail; + + if (Identifier.consume_back("@plt")) { + Error(getLoc(), "'@plt' operand not valid for instruction"); + return MatchOperand_ParseFail; + } + + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + + if (Sym->isVariable()) { + const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); + if (!isa<MCSymbolRefExpr>(V)) { + getLexer().UnLex(Tok); // Put back if it's not a bare symbol. + return MatchOperand_NoMatch; + } + Res = V; + } else + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); + return MatchOperand_Success; +} + +OperandMatchResultTy RISCVAsmParser::parseCallSymbol(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; + + if (getLexer().getKind() != AsmToken::Identifier) + return MatchOperand_NoMatch; + + // Avoid parsing the register in `call rd, foo` as a call symbol. + if (getLexer().peekTok().getKind() != AsmToken::EndOfStatement) + return MatchOperand_NoMatch; + + StringRef Identifier; if (getParser().parseIdentifier(Identifier)) return MatchOperand_ParseFail; + RISCVMCExpr::VariantKind Kind = RISCVMCExpr::VK_RISCV_CALL; + if (Identifier.consume_back("@plt")) + Kind = RISCVMCExpr::VK_RISCV_CALL_PLT; + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + Res = RISCVMCExpr::create(Res, Kind, getContext()); Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } @@ -1408,42 +1544,144 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value, } } -void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, - MCStreamer &Out) { - // The local load address pseudo-instruction "lla" is used in PC-relative - // addressing of symbols: - // lla rdest, symbol - // expands to - // TmpLabel: AUIPC rdest, %pcrel_hi(symbol) - // ADDI rdest, %pcrel_lo(TmpLabel) +void RISCVAsmParser::emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg, + const MCExpr *Symbol, + RISCVMCExpr::VariantKind VKHi, + unsigned SecondOpcode, SMLoc IDLoc, + MCStreamer &Out) { + // A pair of instructions for PC-relative addressing; expands to + // TmpLabel: AUIPC TmpReg, VKHi(symbol) + // OP DestReg, TmpReg, %pcrel_lo(TmpLabel) MCContext &Ctx = getContext(); MCSymbol *TmpLabel = Ctx.createTempSymbol( "pcrel_hi", /* AlwaysAddSuffix */ true, /* CanBeUnnamed */ false); Out.EmitLabel(TmpLabel); - MCOperand DestReg = Inst.getOperand(0); - const RISCVMCExpr *Symbol = RISCVMCExpr::create( - Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx); - + const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx); emitToStreamer( - Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol)); + Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolHi)); const MCExpr *RefToLinkTmpLabel = RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx), RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx); - emitToStreamer(Out, MCInstBuilder(RISCV::ADDI) - .addOperand(DestReg) + emitToStreamer(Out, MCInstBuilder(SecondOpcode) .addOperand(DestReg) + .addOperand(TmpReg) .addExpr(RefToLinkTmpLabel)); } +void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out) { + // The load local address pseudo-instruction "lla" is used in PC-relative + // addressing of local symbols: + // lla rdest, symbol + // expands to + // TmpLabel: AUIPC rdest, %pcrel_hi(symbol) + // ADDI rdest, rdest, %pcrel_lo(TmpLabel) + MCOperand DestReg = Inst.getOperand(0); + const MCExpr *Symbol = Inst.getOperand(1).getExpr(); + emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI, + RISCV::ADDI, IDLoc, Out); +} + +void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out) { + // The load address pseudo-instruction "la" is used in PC-relative and + // GOT-indirect addressing of global symbols: + // la rdest, symbol + // expands to either (for non-PIC) + // TmpLabel: AUIPC rdest, %pcrel_hi(symbol) + // ADDI rdest, rdest, %pcrel_lo(TmpLabel) + // or (for PIC) + // TmpLabel: AUIPC rdest, %got_pcrel_hi(symbol) + // Lx rdest, %pcrel_lo(TmpLabel)(rdest) + MCOperand DestReg = Inst.getOperand(0); + const MCExpr *Symbol = Inst.getOperand(1).getExpr(); + unsigned SecondOpcode; + RISCVMCExpr::VariantKind VKHi; + // FIXME: Should check .option (no)pic when implemented + if (getContext().getObjectFileInfo()->isPositionIndependent()) { + SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW; + VKHi = RISCVMCExpr::VK_RISCV_GOT_HI; + } else { + SecondOpcode = RISCV::ADDI; + VKHi = RISCVMCExpr::VK_RISCV_PCREL_HI; + } + emitAuipcInstPair(DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out); +} + +void RISCVAsmParser::emitLoadTLSIEAddress(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out) { + // The load TLS IE address pseudo-instruction "la.tls.ie" is used in + // initial-exec TLS model addressing of global symbols: + // la.tls.ie rdest, symbol + // expands to + // TmpLabel: AUIPC rdest, %tls_ie_pcrel_hi(symbol) + // Lx rdest, %pcrel_lo(TmpLabel)(rdest) + MCOperand DestReg = Inst.getOperand(0); + const MCExpr *Symbol = Inst.getOperand(1).getExpr(); + unsigned SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW; + emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_TLS_GOT_HI, + SecondOpcode, IDLoc, Out); +} + +void RISCVAsmParser::emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out) { + // The load TLS GD address pseudo-instruction "la.tls.gd" is used in + // global-dynamic TLS model addressing of global symbols: + // la.tls.gd rdest, symbol + // expands to + // TmpLabel: AUIPC rdest, %tls_gd_pcrel_hi(symbol) + // ADDI rdest, rdest, %pcrel_lo(TmpLabel) + MCOperand DestReg = Inst.getOperand(0); + const MCExpr *Symbol = Inst.getOperand(1).getExpr(); + emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_TLS_GD_HI, + RISCV::ADDI, IDLoc, Out); +} + +void RISCVAsmParser::emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode, + SMLoc IDLoc, MCStreamer &Out, + bool HasTmpReg) { + // The load/store pseudo-instruction does a pc-relative load with + // a symbol. + // + // The expansion looks like this + // + // TmpLabel: AUIPC tmp, %pcrel_hi(symbol) + // [S|L]X rd, %pcrel_lo(TmpLabel)(tmp) + MCOperand DestReg = Inst.getOperand(0); + unsigned SymbolOpIdx = HasTmpReg ? 2 : 1; + unsigned TmpRegOpIdx = HasTmpReg ? 1 : 0; + MCOperand TmpReg = Inst.getOperand(TmpRegOpIdx); + const MCExpr *Symbol = Inst.getOperand(SymbolOpIdx).getExpr(); + emitAuipcInstPair(DestReg, TmpReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI, + Opcode, IDLoc, Out); +} + +bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst, + OperandVector &Operands) { + assert(Inst.getOpcode() == RISCV::PseudoAddTPRel && "Invalid instruction"); + assert(Inst.getOperand(2).isReg() && "Unexpected second operand kind"); + if (Inst.getOperand(2).getReg() != RISCV::X4) { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[3]).getStartLoc(); + return Error(ErrorLoc, "the second input operand must be tp/x4 when using " + "%tprel_add modifier"); + } + + return false; +} + bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + OperandVector &Operands, MCStreamer &Out) { Inst.setLoc(IDLoc); - if (Inst.getOpcode() == RISCV::PseudoLI) { + switch (Inst.getOpcode()) { + default: + break; + case RISCV::PseudoLI: { unsigned Reg = Inst.getOperand(0).getReg(); const MCOperand &Op1 = Inst.getOperand(1); if (Op1.isExpr()) { @@ -1463,9 +1701,68 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, Imm = SignExtend64<32>(Imm); emitLoadImm(Reg, Imm, Out); return false; - } else if (Inst.getOpcode() == RISCV::PseudoLLA) { + } + case RISCV::PseudoLLA: emitLoadLocalAddress(Inst, IDLoc, Out); return false; + case RISCV::PseudoLA: + emitLoadAddress(Inst, IDLoc, Out); + return false; + case RISCV::PseudoLA_TLS_IE: + emitLoadTLSIEAddress(Inst, IDLoc, Out); + return false; + case RISCV::PseudoLA_TLS_GD: + emitLoadTLSGDAddress(Inst, IDLoc, Out); + return false; + case RISCV::PseudoLB: + emitLoadStoreSymbol(Inst, RISCV::LB, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLBU: + emitLoadStoreSymbol(Inst, RISCV::LBU, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLH: + emitLoadStoreSymbol(Inst, RISCV::LH, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLHU: + emitLoadStoreSymbol(Inst, RISCV::LHU, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLW: + emitLoadStoreSymbol(Inst, RISCV::LW, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLWU: + emitLoadStoreSymbol(Inst, RISCV::LWU, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoLD: + emitLoadStoreSymbol(Inst, RISCV::LD, IDLoc, Out, /*HasTmpReg=*/false); + return false; + case RISCV::PseudoFLW: + emitLoadStoreSymbol(Inst, RISCV::FLW, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoFLD: + emitLoadStoreSymbol(Inst, RISCV::FLD, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoSB: + emitLoadStoreSymbol(Inst, RISCV::SB, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoSH: + emitLoadStoreSymbol(Inst, RISCV::SH, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoSW: + emitLoadStoreSymbol(Inst, RISCV::SW, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoSD: + emitLoadStoreSymbol(Inst, RISCV::SD, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoFSW: + emitLoadStoreSymbol(Inst, RISCV::FSW, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoFSD: + emitLoadStoreSymbol(Inst, RISCV::FSD, IDLoc, Out, /*HasTmpReg=*/true); + return false; + case RISCV::PseudoAddTPRel: + if (checkPseudoAddTPRel(Inst, Operands)) + return true; + break; } emitToStreamer(Out, Inst); |