diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
| commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
| tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Target/RISCV | |
| parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) | |
Notes
Diffstat (limited to 'lib/Target/RISCV')
60 files changed, 3418 insertions, 765 deletions
diff --git a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 1d1112cc51249..0172c6298772c 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); diff --git a/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index eafa09d56315d..36200c03f7032 100644 --- a/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -1,9 +1,8 @@ //===-- RISCVDisassembler.cpp - Disassembler for RISCV --------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -12,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "TargetInfo/RISCVTargetInfo.h" #include "Utils/RISCVBaseInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -70,7 +70,13 @@ static const unsigned GPRDecoderTable[] = { static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const void *Decoder) { - if (RegNo > sizeof(GPRDecoderTable)) + const FeatureBitset &FeatureBits = + static_cast<const MCDisassembler *>(Decoder) + ->getSubtargetInfo() + .getFeatureBits(); + bool IsRV32E = FeatureBits[RISCV::FeatureRV32E]; + + if (RegNo > array_lengthof(GPRDecoderTable) || (IsRV32E && RegNo > 15)) return MCDisassembler::Fail; // We must define our own mapping from RegNo to register identifier. @@ -95,7 +101,7 @@ static const unsigned FPR32DecoderTable[] = { static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const void *Decoder) { - if (RegNo > sizeof(FPR32DecoderTable)) + if (RegNo > array_lengthof(FPR32DecoderTable)) return MCDisassembler::Fail; // We must define our own mapping from RegNo to register identifier. @@ -131,7 +137,7 @@ static const unsigned FPR64DecoderTable[] = { static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const void *Decoder) { - if (RegNo > sizeof(FPR64DecoderTable)) + if (RegNo > array_lengthof(FPR64DecoderTable)) return MCDisassembler::Fail; // We must define our own mapping from RegNo to register identifier. diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 7672fea5d95ba..ee5f760ebcb0e 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -1,9 +1,8 @@ //===-- RISCVAsmBackend.cpp - RISCV Assembler Backend ---------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -17,6 +16,7 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -33,6 +33,10 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, switch ((unsigned)Fixup.getKind()) { default: break; + case RISCV::fixup_riscv_got_hi20: + case RISCV::fixup_riscv_tls_got_hi20: + case RISCV::fixup_riscv_tls_gd_hi20: + return true; case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_s: // For pcrel_lo12, force a relocation if the target of the corresponding @@ -48,6 +52,11 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, default: llvm_unreachable("Unexpected fixup kind for pcrel_lo12"); break; + case RISCV::fixup_riscv_got_hi20: + case RISCV::fixup_riscv_tls_got_hi20: + case RISCV::fixup_riscv_tls_gd_hi20: + ShouldForce = true; + break; case RISCV::fixup_riscv_pcrel_hi20: ShouldForce = T->getValue()->findAssociatedFragment() != Fixup.getValue()->findAssociatedFragment(); @@ -153,16 +162,12 @@ bool RISCVAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const { return false; // The canonical nop on RISC-V is addi x0, x0, 0. - uint64_t Nop32Count = Count / 4; - for (uint64_t i = Nop32Count; i != 0; --i) + for (; Count >= 4; Count -= 4) OS.write("\x13\0\0\0", 4); // The canonical nop on RVC is c.nop. - if (HasStdExtC) { - uint64_t Nop16Count = (Count - Nop32Count * 4) / 2; - for (uint64_t i = Nop16Count; i != 0; --i) - OS.write("\x01\0", 2); - } + if (Count && HasStdExtC) + OS.write("\x01\0", 2); return true; } @@ -173,6 +178,10 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); + case RISCV::fixup_riscv_got_hi20: + case RISCV::fixup_riscv_tls_got_hi20: + case RISCV::fixup_riscv_tls_gd_hi20: + llvm_unreachable("Relocation should be unconditionally forced\n"); case FK_Data_1: case FK_Data_2: case FK_Data_4: @@ -180,12 +189,15 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, return Value; case RISCV::fixup_riscv_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_i: + case RISCV::fixup_riscv_tprel_lo12_i: return Value & 0xfff; case RISCV::fixup_riscv_lo12_s: case RISCV::fixup_riscv_pcrel_lo12_s: + case RISCV::fixup_riscv_tprel_lo12_s: return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); case RISCV::fixup_riscv_hi20: case RISCV::fixup_riscv_pcrel_hi20: + case RISCV::fixup_riscv_tprel_hi20: // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. return ((Value + 0x800) >> 12) & 0xfffff; case RISCV::fixup_riscv_jal: { @@ -223,7 +235,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); return Value; } - case RISCV::fixup_riscv_call: { + case RISCV::fixup_riscv_call: + case RISCV::fixup_riscv_call_plt: { // Jalr will add UpperImm with the sign-extended 12-bit LowerImm, // we need to add 0x800ULL before extract upper bits to reflect the // effect of the sign extension. @@ -287,6 +300,60 @@ void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, } } +// Linker relaxation may change code size. We have to insert Nops +// for .align directive when linker relaxation enabled. So then Linker +// could satisfy alignment by removing Nops. +// The function return the total Nops Size we need to insert. +bool RISCVAsmBackend::shouldInsertExtraNopBytesForCodeAlign( + const MCAlignFragment &AF, unsigned &Size) { + // Calculate Nops Size only when linker relaxation enabled. + if (!STI.getFeatureBits()[RISCV::FeatureRelax]) + return false; + + bool HasStdExtC = STI.getFeatureBits()[RISCV::FeatureStdExtC]; + unsigned MinNopLen = HasStdExtC ? 2 : 4; + + if (AF.getAlignment() <= MinNopLen) { + return false; + } else { + Size = AF.getAlignment() - MinNopLen; + return true; + } +} + +// We need to insert R_RISCV_ALIGN relocation type to indicate the +// position of Nops and the total bytes of the Nops have been inserted +// when linker relaxation enabled. +// The function insert fixup_riscv_align fixup which eventually will +// transfer to R_RISCV_ALIGN relocation type. +bool RISCVAsmBackend::shouldInsertFixupForCodeAlign(MCAssembler &Asm, + const MCAsmLayout &Layout, + MCAlignFragment &AF) { + // Insert the fixup only when linker relaxation enabled. + if (!STI.getFeatureBits()[RISCV::FeatureRelax]) + return false; + + // Calculate total Nops we need to insert. If there are none to insert + // then simply return. + unsigned Count; + if (!shouldInsertExtraNopBytesForCodeAlign(AF, Count) || (Count == 0)) + return false; + + MCContext &Ctx = Asm.getContext(); + const MCExpr *Dummy = MCConstantExpr::create(0, Ctx); + // Create fixup_riscv_align fixup. + MCFixup Fixup = + MCFixup::create(0, Dummy, MCFixupKind(RISCV::fixup_riscv_align), SMLoc()); + + uint64_t FixedValue = 0; + MCValue NopBytes = MCValue::get(Count); + + Asm.getWriter().recordRelocation(Asm, Layout, &AF, Fixup, NopBytes, + FixedValue); + + return true; +} + std::unique_ptr<MCObjectTargetWriter> RISCVAsmBackend::createObjectTargetWriter() const { return createRISCVELFObjectWriter(OSABI, Is64Bit); @@ -298,5 +365,5 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T, const MCTargetOptions &Options) { const Triple &TT = STI.getTargetTriple(); uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); - return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit()); + return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options); } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h index b98e45f4053fd..254249c87dc88 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -1,9 +1,8 @@ //===-- RISCVAsmBackend.h - RISCV Assembler Backend -----------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -12,6 +11,7 @@ #include "MCTargetDesc/RISCVFixupKinds.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "Utils/RISCVBaseInfo.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -26,21 +26,45 @@ class RISCVAsmBackend : public MCAsmBackend { uint8_t OSABI; bool Is64Bit; bool ForceRelocs = false; + const MCTargetOptions &TargetOptions; + RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; public: - RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit) - : MCAsmBackend(support::little), STI(STI), OSABI(OSABI), - Is64Bit(Is64Bit) {} + RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit, + const MCTargetOptions &Options) + : MCAsmBackend(support::little), STI(STI), OSABI(OSABI), Is64Bit(Is64Bit), + TargetOptions(Options) { + TargetABI = RISCVABI::computeTargetABI( + STI.getTargetTriple(), STI.getFeatureBits(), Options.getABIName()); + RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits()); + } ~RISCVAsmBackend() override {} void setForceRelocs() { ForceRelocs = true; } + // Returns true if relocations will be forced for shouldForceRelocation by + // default. This will be true if relaxation is enabled or had previously + // been enabled. + bool willForceRelocations() const { + return ForceRelocs || STI.getFeatureBits()[RISCV::FeatureRelax]; + } + // Generate diff expression relocations if the relax feature is enabled or had // previously been enabled, otherwise it is safe for the assembler to // calculate these internally. bool requiresDiffExpressionRelocations() const override { - return STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs; + return willForceRelocations(); } + + // Return Size with extra Nop Bytes for alignment directive in code section. + bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF, + unsigned &Size) override; + + // Insert target specific fixup type for alignment directive in code section. + bool shouldInsertFixupForCodeAlign(MCAssembler &Asm, + const MCAsmLayout &Layout, + MCAlignFragment &AF) override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef<char> Data, uint64_t Value, bool IsResolved, @@ -80,12 +104,21 @@ public: { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_tprel_hi20", 12, 20, 0 }, + { "fixup_riscv_tprel_lo12_i", 20, 12, 0 }, + { "fixup_riscv_tprel_lo12_s", 0, 32, 0 }, + { "fixup_riscv_tprel_add", 0, 0, 0 }, + { "fixup_riscv_tls_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_tls_gd_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_rvc_branch", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel }, - { "fixup_riscv_relax", 0, 0, 0 } + { "fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_relax", 0, 0, 0 }, + { "fixup_riscv_align", 0, 0, 0 } }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -107,6 +140,9 @@ public: bool writeNopData(raw_ostream &OS, uint64_t Count) const override; + + const MCTargetOptions &getTargetOptions() const { return TargetOptions; } + RISCVABI::ABI getTargetABI() const { return TargetABI; } }; } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 9b88614aa6938..3ccbc86d2619a 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -1,9 +1,8 @@ //===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -49,7 +48,42 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, const MCFixup &Fixup, bool IsPCRel) const { // Determine the type of the relocation - switch ((unsigned)Fixup.getKind()) { + unsigned Kind = Fixup.getKind(); + if (IsPCRel) { + switch (Kind) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + case FK_PCRel_4: + return ELF::R_RISCV_32_PCREL; + case RISCV::fixup_riscv_pcrel_hi20: + return ELF::R_RISCV_PCREL_HI20; + case RISCV::fixup_riscv_pcrel_lo12_i: + return ELF::R_RISCV_PCREL_LO12_I; + case RISCV::fixup_riscv_pcrel_lo12_s: + return ELF::R_RISCV_PCREL_LO12_S; + case RISCV::fixup_riscv_got_hi20: + return ELF::R_RISCV_GOT_HI20; + case RISCV::fixup_riscv_tls_got_hi20: + return ELF::R_RISCV_TLS_GOT_HI20; + case RISCV::fixup_riscv_tls_gd_hi20: + return ELF::R_RISCV_TLS_GD_HI20; + case RISCV::fixup_riscv_jal: + return ELF::R_RISCV_JAL; + case RISCV::fixup_riscv_branch: + return ELF::R_RISCV_BRANCH; + case RISCV::fixup_riscv_rvc_jump: + return ELF::R_RISCV_RVC_JUMP; + case RISCV::fixup_riscv_rvc_branch: + return ELF::R_RISCV_RVC_BRANCH; + case RISCV::fixup_riscv_call: + return ELF::R_RISCV_CALL; + case RISCV::fixup_riscv_call_plt: + return ELF::R_RISCV_CALL_PLT; + } + } + + switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case FK_Data_4: @@ -78,24 +112,18 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, return ELF::R_RISCV_LO12_I; case RISCV::fixup_riscv_lo12_s: return ELF::R_RISCV_LO12_S; - case RISCV::fixup_riscv_pcrel_hi20: - return ELF::R_RISCV_PCREL_HI20; - case RISCV::fixup_riscv_pcrel_lo12_i: - return ELF::R_RISCV_PCREL_LO12_I; - case RISCV::fixup_riscv_pcrel_lo12_s: - return ELF::R_RISCV_PCREL_LO12_S; - case RISCV::fixup_riscv_jal: - return ELF::R_RISCV_JAL; - case RISCV::fixup_riscv_branch: - return ELF::R_RISCV_BRANCH; - case RISCV::fixup_riscv_rvc_jump: - return ELF::R_RISCV_RVC_JUMP; - case RISCV::fixup_riscv_rvc_branch: - return ELF::R_RISCV_RVC_BRANCH; - case RISCV::fixup_riscv_call: - return ELF::R_RISCV_CALL; + case RISCV::fixup_riscv_tprel_hi20: + return ELF::R_RISCV_TPREL_HI20; + case RISCV::fixup_riscv_tprel_lo12_i: + return ELF::R_RISCV_TPREL_LO12_I; + case RISCV::fixup_riscv_tprel_lo12_s: + return ELF::R_RISCV_TPREL_LO12_S; + case RISCV::fixup_riscv_tprel_add: + return ELF::R_RISCV_TPREL_ADD; case RISCV::fixup_riscv_relax: return ELF::R_RISCV_RELAX; + case RISCV::fixup_riscv_align: + return ELF::R_RISCV_ALIGN; } } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp index a6ba1e41e9644..40fa195f37909 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -1,9 +1,8 @@ //===-- RISCVELFStreamer.cpp - RISCV ELF Target Streamer Methods ----------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -12,7 +11,9 @@ //===----------------------------------------------------------------------===// #include "RISCVELFStreamer.h" +#include "MCTargetDesc/RISCVAsmBackend.h" #include "RISCVMCTargetDesc.h" +#include "Utils/RISCVBaseInfo.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -23,14 +24,35 @@ RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) : RISCVTargetStreamer(S) { MCAssembler &MCA = getStreamer().getAssembler(); - const FeatureBitset &Features = STI.getFeatureBits(); + auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend()); + RISCVABI::ABI ABI = MAB.getTargetABI(); + assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI"); unsigned EFlags = MCA.getELFHeaderEFlags(); if (Features[RISCV::FeatureStdExtC]) EFlags |= ELF::EF_RISCV_RVC; + switch (ABI) { + case RISCVABI::ABI_ILP32: + case RISCVABI::ABI_LP64: + break; + case RISCVABI::ABI_ILP32F: + case RISCVABI::ABI_LP64F: + EFlags |= ELF::EF_RISCV_FLOAT_ABI_SINGLE; + break; + case RISCVABI::ABI_ILP32D: + case RISCVABI::ABI_LP64D: + EFlags |= ELF::EF_RISCV_FLOAT_ABI_DOUBLE; + break; + case RISCVABI::ABI_ILP32E: + EFlags |= ELF::EF_RISCV_RVE; + break; + case RISCVABI::ABI_Unknown: + llvm_unreachable("Improperly initialised target ABI"); + } + MCA.setELFHeaderEFlags(EFlags); } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h index 1f36bbc438824..138df786eaf3f 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -1,9 +1,8 @@ //===-- RISCVELFStreamer.h - RISCV ELF Target Streamer ---------*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h index 6a1224be774e4..6c7933340608b 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -1,9 +1,8 @@ //===-- RISCVFixupKinds.h - RISCV Specific Fixup Entries --------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -35,6 +34,27 @@ enum Fixups { // fixup_riscv_pcrel_lo12_s - 12-bit fixup corresponding to pcrel_lo(foo) for // the S-type store instructions fixup_riscv_pcrel_lo12_s, + // fixup_riscv_got_hi20 - 20-bit fixup corresponding to got_pcrel_hi(foo) for + // instructions like auipc + fixup_riscv_got_hi20, + // fixup_riscv_tprel_hi20 - 20-bit fixup corresponding to tprel_hi(foo) for + // instructions like lui + fixup_riscv_tprel_hi20, + // fixup_riscv_tprel_lo12_i - 12-bit fixup corresponding to tprel_lo(foo) for + // instructions like addi + fixup_riscv_tprel_lo12_i, + // fixup_riscv_tprel_lo12_s - 12-bit fixup corresponding to tprel_lo(foo) for + // the S-type store instructions + fixup_riscv_tprel_lo12_s, + // fixup_riscv_tprel_add - A fixup corresponding to %tprel_add(foo) for the + // add_tls instruction. Used to provide a hint to the linker. + fixup_riscv_tprel_add, + // fixup_riscv_tls_got_hi20 - 20-bit fixup corresponding to + // tls_ie_pcrel_hi(foo) for instructions like auipc + fixup_riscv_tls_got_hi20, + // fixup_riscv_tls_gd_hi20 - 20-bit fixup corresponding to + // tls_gd_pcrel_hi(foo) for instructions like auipc + fixup_riscv_tls_gd_hi20, // fixup_riscv_jal - 20-bit fixup for symbol references in the jal // instruction fixup_riscv_jal, @@ -50,9 +70,17 @@ enum Fixups { // fixup_riscv_call - A fixup representing a call attached to the auipc // instruction in a pair composed of adjacent auipc+jalr instructions. fixup_riscv_call, + // fixup_riscv_call_plt - A fixup representing a procedure linkage table call + // attached to the auipc instruction in a pair composed of adjacent auipc+jalr + // instructions. + fixup_riscv_call_plt, // fixup_riscv_relax - Used to generate an R_RISCV_RELAX relocation type, // which indicates the linker may relax the instruction pair. fixup_riscv_relax, + // fixup_riscv_align - Used to generate an R_RISCV_ALIGN relocation type, + // which indicates the linker should fixup the alignment after linker + // relaxation. + fixup_riscv_align, // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, diff --git a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp index 979c8f4e2fa7a..fe37b70811d84 100644 --- a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -1,9 +1,8 @@ //===-- RISCVInstPrinter.cpp - Convert RISCV MCInst to asm syntax ---------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h b/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h index 0f9bed184996a..5ca1d3fa20fe7 100644 --- a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h @@ -1,9 +1,8 @@ //===-- RISCVInstPrinter.h - Convert RISCV MCInst to asm syntax ---*- C++ -*--// // -// 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,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_TARGET_RISCV_INSTPRINTER_RISCVINSTPRINTER_H -#define LLVM_LIB_TARGET_RISCV_INSTPRINTER_RISCVINSTPRINTER_H +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVINSTPRINTER_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVINSTPRINTER_H #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/MC/MCInstPrinter.h" diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp index 780dae410cd0d..9836296928833 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp @@ -1,9 +1,8 @@ //===-- RISCVMCAsmInfo.cpp - RISCV Asm properties -------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -22,6 +21,7 @@ RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) { CommentString = "#"; AlignmentIsInBytes = false; SupportsDebugInformation = true; + ExceptionsType = ExceptionHandling::DwarfCFI; Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h index 901a1eba8af25..043fdb7c08c0a 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h @@ -1,9 +1,8 @@ //===-- RISCVMCAsmInfo.h - RISCV Asm Info ----------------------*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index c5a4ffc0e360c..0fc775f63ed45 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -1,9 +1,8 @@ //===-- RISCVMCCodeEmitter.cpp - Convert RISCV code to machine code -------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -57,6 +56,10 @@ public: SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; + void expandAddTPRel(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, @@ -85,28 +88,34 @@ MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII, return new RISCVMCCodeEmitter(Ctx, MCII); } -// Expand PseudoCALL and PseudoTAIL to AUIPC and JALR with relocation types. -// We expand PseudoCALL and PseudoTAIL while encoding, meaning AUIPC and JALR -// won't go through RISCV MC to MC compressed instruction transformation. This -// is acceptable because AUIPC has no 16-bit form and C_JALR have no immediate -// operand field. We let linker relaxation deal with it. When linker -// relaxation enabled, AUIPC and JALR have chance relax to JAL. If C extension -// is enabled, JAL has chance relax to C_JAL. +// Expand PseudoCALL(Reg) and PseudoTAIL to AUIPC and JALR with relocation +// types. We expand PseudoCALL(Reg) and PseudoTAIL while encoding, meaning AUIPC +// and JALR won't go through RISCV MC to MC compressed instruction +// transformation. This is acceptable because AUIPC has no 16-bit form and +// C_JALR have no immediate operand field. We let linker relaxation deal with +// it. When linker relaxation enabled, AUIPC and JALR have chance relax to JAL. +// If C extension is enabled, JAL has chance relax to C_JAL. void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { MCInst TmpInst; - MCOperand Func = MI.getOperand(0); - unsigned Ra = (MI.getOpcode() == RISCV::PseudoTAIL) ? RISCV::X6 : RISCV::X1; + MCOperand Func; + unsigned Ra; + if (MI.getOpcode() == RISCV::PseudoTAIL) { + Func = MI.getOperand(0); + Ra = RISCV::X6; + } else if (MI.getOpcode() == RISCV::PseudoCALLReg) { + Func = MI.getOperand(1); + Ra = MI.getOperand(0).getReg(); + } else { + Func = MI.getOperand(0); + Ra = RISCV::X1; + } uint32_t Binary; assert(Func.isExpr() && "Expected expression"); - const MCExpr *Expr = Func.getExpr(); - - // Create function call expression CallExpr for AUIPC. - const MCExpr *CallExpr = - RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL, Ctx); + const MCExpr *CallExpr = Func.getExpr(); // Emit AUIPC Ra, Func with R_RISCV_CALL relocation type. TmpInst = MCInstBuilder(RISCV::AUIPC) @@ -119,12 +128,50 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS, // Emit JALR X0, X6, 0 TmpInst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Ra).addImm(0); else - // Emit JALR X1, X1, 0 + // Emit JALR Ra, Ra, 0 TmpInst = MCInstBuilder(RISCV::JALR).addReg(Ra).addReg(Ra).addImm(0); Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); support::endian::write(OS, Binary, support::little); } +// Expand PseudoAddTPRel to a simple ADD with the correct relocation. +void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + MCOperand DestReg = MI.getOperand(0); + MCOperand SrcReg = MI.getOperand(1); + MCOperand TPReg = MI.getOperand(2); + assert(TPReg.isReg() && TPReg.getReg() == RISCV::X4 && + "Expected thread pointer as second input to TP-relative add"); + + MCOperand SrcSymbol = MI.getOperand(3); + assert(SrcSymbol.isExpr() && + "Expected expression as third input to TP-relative add"); + + const RISCVMCExpr *Expr = dyn_cast<RISCVMCExpr>(SrcSymbol.getExpr()); + assert(Expr && Expr->getKind() == RISCVMCExpr::VK_RISCV_TPREL_ADD && + "Expected tprel_add relocation on TP-relative symbol"); + + // Emit the correct tprel_add relocation for the symbol. + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(RISCV::fixup_riscv_tprel_add), MI.getLoc())); + + // Emit fixup_riscv_relax for tprel_add where the relax feature is enabled. + if (STI.getFeatureBits()[RISCV::FeatureRelax]) { + const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx); + Fixups.push_back(MCFixup::create( + 0, Dummy, MCFixupKind(RISCV::fixup_riscv_relax), MI.getLoc())); + } + + // Emit a normal ADD instruction with the given operands. + MCInst TmpInst = MCInstBuilder(RISCV::ADD) + .addOperand(DestReg) + .addOperand(SrcReg) + .addOperand(TPReg); + uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); +} + void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -132,13 +179,20 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, // Get byte count of instruction. unsigned Size = Desc.getSize(); - if (MI.getOpcode() == RISCV::PseudoCALL || + if (MI.getOpcode() == RISCV::PseudoCALLReg || + MI.getOpcode() == RISCV::PseudoCALL || MI.getOpcode() == RISCV::PseudoTAIL) { expandFunctionCall(MI, OS, Fixups, STI); MCNumEmitted += 2; return; } + if (MI.getOpcode() == RISCV::PseudoAddTPRel) { + expandAddTPRel(MI, OS, Fixups, STI); + MCNumEmitted += 1; + return; + } + switch (Size) { default: llvm_unreachable("Unhandled encodeInstruction length!"); @@ -205,6 +259,7 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, const MCExpr *Expr = MO.getExpr(); MCExpr::ExprKind Kind = Expr->getKind(); RISCV::Fixups FixupKind = RISCV::fixup_riscv_invalid; + bool RelaxCandidate = false; if (Kind == MCExpr::Target) { const RISCVMCExpr *RVExpr = cast<RISCVMCExpr>(Expr); @@ -212,6 +267,13 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, case RISCVMCExpr::VK_RISCV_None: case RISCVMCExpr::VK_RISCV_Invalid: llvm_unreachable("Unhandled fixup kind!"); + case RISCVMCExpr::VK_RISCV_TPREL_ADD: + // tprel_add is only used to indicate that a relocation should be emitted + // for an add instruction used in TP-relative addressing. It should not be + // expanded as if representing an actual instruction operand and so to + // encounter it here is an error. + llvm_unreachable( + "VK_RISCV_TPREL_ADD should not represent an instruction operand"); case RISCVMCExpr::VK_RISCV_LO: if (MIFrm == RISCVII::InstFormatI) FixupKind = RISCV::fixup_riscv_lo12_i; @@ -219,9 +281,11 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, FixupKind = RISCV::fixup_riscv_lo12_s; else llvm_unreachable("VK_RISCV_LO used with unexpected instruction format"); + RelaxCandidate = true; break; case RISCVMCExpr::VK_RISCV_HI: FixupKind = RISCV::fixup_riscv_hi20; + RelaxCandidate = true; break; case RISCVMCExpr::VK_RISCV_PCREL_LO: if (MIFrm == RISCVII::InstFormatI) @@ -231,12 +295,42 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, else llvm_unreachable( "VK_RISCV_PCREL_LO used with unexpected instruction format"); + RelaxCandidate = true; break; case RISCVMCExpr::VK_RISCV_PCREL_HI: FixupKind = RISCV::fixup_riscv_pcrel_hi20; + RelaxCandidate = true; + break; + case RISCVMCExpr::VK_RISCV_GOT_HI: + FixupKind = RISCV::fixup_riscv_got_hi20; + break; + case RISCVMCExpr::VK_RISCV_TPREL_LO: + if (MIFrm == RISCVII::InstFormatI) + FixupKind = RISCV::fixup_riscv_tprel_lo12_i; + else if (MIFrm == RISCVII::InstFormatS) + FixupKind = RISCV::fixup_riscv_tprel_lo12_s; + else + llvm_unreachable( + "VK_RISCV_TPREL_LO used with unexpected instruction format"); + RelaxCandidate = true; + break; + case RISCVMCExpr::VK_RISCV_TPREL_HI: + FixupKind = RISCV::fixup_riscv_tprel_hi20; + RelaxCandidate = true; + break; + case RISCVMCExpr::VK_RISCV_TLS_GOT_HI: + FixupKind = RISCV::fixup_riscv_tls_got_hi20; + break; + case RISCVMCExpr::VK_RISCV_TLS_GD_HI: + FixupKind = RISCV::fixup_riscv_tls_gd_hi20; break; case RISCVMCExpr::VK_RISCV_CALL: FixupKind = RISCV::fixup_riscv_call; + RelaxCandidate = true; + break; + case RISCVMCExpr::VK_RISCV_CALL_PLT: + FixupKind = RISCV::fixup_riscv_call_plt; + RelaxCandidate = true; break; } } else if (Kind == MCExpr::SymbolRef && @@ -258,13 +352,15 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); ++MCNumFixups; - if (EnableRelax) { - if (FixupKind == RISCV::fixup_riscv_call) { - Fixups.push_back( - MCFixup::create(0, Expr, MCFixupKind(RISCV::fixup_riscv_relax), - MI.getLoc())); - ++MCNumFixups; - } + // Ensure an R_RISCV_RELAX relocation will be emitted if linker relaxation is + // enabled and the current fixup will result in a relocation that may be + // relaxed. + if (EnableRelax && RelaxCandidate) { + const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx); + Fixups.push_back( + MCFixup::create(0, Dummy, MCFixupKind(RISCV::fixup_riscv_relax), + MI.getLoc())); + ++MCNumFixups; } return 0; diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index 53648a5922c85..ae25ec8181710 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -1,9 +1,8 @@ //===-- RISCVMCExpr.cpp - RISCV specific MC expression classes ------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -12,9 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "RISCV.h" #include "RISCVMCExpr.h" +#include "MCTargetDesc/RISCVAsmBackend.h" +#include "RISCV.h" #include "RISCVFixupKinds.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" @@ -32,11 +34,15 @@ const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind, } void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { - bool HasVariant = - ((getKind() != VK_RISCV_None) && (getKind() != VK_RISCV_CALL)); + VariantKind Kind = getKind(); + bool HasVariant = ((Kind != VK_RISCV_None) && (Kind != VK_RISCV_CALL) && + (Kind != VK_RISCV_CALL_PLT)); + if (HasVariant) OS << '%' << getVariantKindName(getKind()) << '('; Expr->print(OS, MAI); + if (Kind == VK_RISCV_CALL_PLT) + OS << "@plt"; if (HasVariant) OS << ')'; } @@ -50,19 +56,30 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup() const { if (!AUIPCSRE) return nullptr; - const auto *DF = - dyn_cast_or_null<MCDataFragment>(AUIPCSRE->findAssociatedFragment()); + const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); + const auto *DF = dyn_cast_or_null<MCDataFragment>(AUIPCSymbol->getFragment()); + if (!DF) return nullptr; - const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); + uint64_t Offset = AUIPCSymbol->getOffset(); + if (DF->getContents().size() == Offset) { + DF = dyn_cast_or_null<MCDataFragment>(DF->getNextNode()); + if (!DF) + return nullptr; + Offset = 0; + } + for (const MCFixup &F : DF->getFixups()) { - if (F.getOffset() != AUIPCSymbol->getOffset()) + if (F.getOffset() != Offset) continue; switch ((unsigned)F.getKind()) { default: continue; + case RISCV::fixup_riscv_got_hi20: + case RISCV::fixup_riscv_tls_got_hi20: + case RISCV::fixup_riscv_tls_gd_hi20: case RISCV::fixup_riscv_pcrel_hi20: return &F; } @@ -79,6 +96,16 @@ bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, // (<real target> + <offset from this fixup to the auipc fixup>). The Fixup // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct. + + // Don't try to evaluate if the fixup will be forced as a relocation (e.g. + // as linker relaxation is enabled). If we evaluated pcrel_lo in this case, + // the modified fixup will be converted into a relocation that no longer + // points to the pcrel_hi as the linker requires. + auto &RAB = + static_cast<RISCVAsmBackend &>(Layout->getAssembler().getBackend()); + if (RAB.willForceRelocations()) + return false; + MCValue AUIPCLoc; if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout)) return false; @@ -137,6 +164,12 @@ bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, case VK_RISCV_HI: case VK_RISCV_PCREL_LO: case VK_RISCV_PCREL_HI: + case VK_RISCV_GOT_HI: + case VK_RISCV_TPREL_LO: + case VK_RISCV_TPREL_HI: + case VK_RISCV_TPREL_ADD: + case VK_RISCV_TLS_GOT_HI: + case VK_RISCV_TLS_GD_HI: return false; } } @@ -154,6 +187,12 @@ RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { .Case("hi", VK_RISCV_HI) .Case("pcrel_lo", VK_RISCV_PCREL_LO) .Case("pcrel_hi", VK_RISCV_PCREL_HI) + .Case("got_pcrel_hi", VK_RISCV_GOT_HI) + .Case("tprel_lo", VK_RISCV_TPREL_LO) + .Case("tprel_hi", VK_RISCV_TPREL_HI) + .Case("tprel_add", VK_RISCV_TPREL_ADD) + .Case("tls_ie_pcrel_hi", VK_RISCV_TLS_GOT_HI) + .Case("tls_gd_pcrel_hi", VK_RISCV_TLS_GD_HI) .Default(VK_RISCV_Invalid); } @@ -169,14 +208,71 @@ StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { return "pcrel_lo"; case VK_RISCV_PCREL_HI: return "pcrel_hi"; + case VK_RISCV_GOT_HI: + return "got_pcrel_hi"; + case VK_RISCV_TPREL_LO: + return "tprel_lo"; + case VK_RISCV_TPREL_HI: + return "tprel_hi"; + case VK_RISCV_TPREL_ADD: + return "tprel_add"; + case VK_RISCV_TLS_GOT_HI: + return "tls_ie_pcrel_hi"; + case VK_RISCV_TLS_GD_HI: + return "tls_gd_pcrel_hi"; } } +static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { + switch (Expr->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expression"); + break; + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); + fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); + fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: { + // We're known to be under a TLS fixup, so any symbol should be + // modified. There should be only one. + const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr); + cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm); + break; + } +} + +void RISCVMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { + switch (getKind()) { + default: + return; + case VK_RISCV_TPREL_HI: + case VK_RISCV_TLS_GOT_HI: + case VK_RISCV_TLS_GD_HI: + break; + } + + fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); +} + bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { MCValue Value; if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || - Kind == VK_RISCV_CALL) + Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI || + Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD || + Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI || + Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h index 4eafcc08b51ff..b5a292dc1b1a6 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -1,9 +1,8 @@ //===-- RISCVMCExpr.h - RISCV specific MC expression classes ----*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -29,7 +28,14 @@ public: VK_RISCV_HI, VK_RISCV_PCREL_LO, VK_RISCV_PCREL_HI, + VK_RISCV_GOT_HI, + VK_RISCV_TPREL_LO, + VK_RISCV_TPREL_HI, + VK_RISCV_TPREL_ADD, + VK_RISCV_TLS_GOT_HI, + VK_RISCV_TLS_GD_HI, VK_RISCV_CALL, + VK_RISCV_CALL_PLT, VK_RISCV_Invalid }; @@ -53,11 +59,11 @@ public: const MCExpr *getSubExpr() const { return Expr; } - /// Get the MCExpr of the VK_RISCV_PCREL_HI Fixup that the - /// VK_RISCV_PCREL_LO points to. + /// Get the corresponding PC-relative HI fixup that a VK_RISCV_PCREL_LO + /// points to. /// /// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a - /// VK_RISCV_PCREL_HI. + /// known PC-relative HI fixup. const MCFixup *getPCRelHiFixup() const; void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; @@ -68,8 +74,7 @@ public: return getSubExpr()->findAssociatedFragment(); } - // There are no TLS RISCVMCExprs at the moment. - void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override; bool evaluateAsConstant(int64_t &Res) const; diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp index 133f3cd3d39ae..bc45262ab2de3 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -1,9 +1,8 @@ //===-- RISCVMCTargetDesc.cpp - RISCV Target Descriptions -----------------===// // -// 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 // //===----------------------------------------------------------------------===// /// @@ -12,10 +11,11 @@ //===----------------------------------------------------------------------===// #include "RISCVMCTargetDesc.h" -#include "InstPrinter/RISCVInstPrinter.h" #include "RISCVELFStreamer.h" +#include "RISCVInstPrinter.h" #include "RISCVMCAsmInfo.h" #include "RISCVTargetStreamer.h" +#include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" @@ -50,7 +50,13 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) { static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI, const Triple &TT) { - return new RISCVMCAsmInfo(TT); + MCAsmInfo *MAI = new RISCVMCAsmInfo(TT); + + unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0); + MAI->addInitialFrameState(Inst); + + return MAI; } static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT, diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h index 0228253c08cb2..b30997533ddfa 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h @@ -1,9 +1,8 @@ //===-- RISCVMCTargetDesc.h - RISCV Target Descriptions ---------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -33,9 +32,6 @@ class Triple; class raw_ostream; class raw_pwrite_stream; -Target &getTheRISCV32Target(); -Target &getTheRISCV64Target(); - MCCodeEmitter *createRISCVMCCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo &MRI, MCContext &Ctx); diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp index 8d5ef3dbd17f9..913e1f744192c 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -1,9 +1,8 @@ //===-- RISCVTargetStreamer.cpp - RISCV Target Streamer Methods -----------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h index 74ec9e303933d..1becc134b2a23 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -1,9 +1,8 @@ //===-- RISCVTargetStreamer.h - RISCV Target Streamer ----------*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/Target/RISCV/RISCV.h b/lib/Target/RISCV/RISCV.h index b25aee46200da..834a1d1711435 100644 --- a/lib/Target/RISCV/RISCV.h +++ b/lib/Target/RISCV/RISCV.h @@ -1,9 +1,8 @@ //===-- RISCV.h - Top-level interface for RISCV -----------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/RISCV.td b/lib/Target/RISCV/RISCV.td index 0e86e2bc5e98c..e19b70b8e709b 100644 --- a/lib/Target/RISCV/RISCV.td +++ b/lib/Target/RISCV/RISCV.td @@ -1,9 +1,8 @@ //===-- RISCV.td - Describe the RISCV Target Machine -------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -55,23 +54,29 @@ def IsRV32 : Predicate<"!Subtarget->is64Bit()">, def RV64 : HwMode<"+64bit">; def RV32 : HwMode<"-64bit">; +def FeatureRV32E + : SubtargetFeature<"e", "IsRV32E", "true", + "Implements RV32E (provides 16 rather than 32 GPRs)">; +def IsRV32E : Predicate<"Subtarget->isRV32E()">, + AssemblerPredicate<"FeatureRV32E">; + def FeatureRelax : SubtargetFeature<"relax", "EnableLinkerRelax", "true", "Enable Linker relaxation.">; //===----------------------------------------------------------------------===// -// Registers, calling conventions, instruction descriptions. +// Named operands for CSR instructions. //===----------------------------------------------------------------------===// -include "RISCVRegisterInfo.td" -include "RISCVCallingConv.td" -include "RISCVInstrInfo.td" +include "RISCVSystemOperands.td" //===----------------------------------------------------------------------===// -// Named operands for CSR instructions. +// Registers, calling conventions, instruction descriptions. //===----------------------------------------------------------------------===// -include "RISCVSystemOperands.td" +include "RISCVRegisterInfo.td" +include "RISCVCallingConv.td" +include "RISCVInstrInfo.td" //===----------------------------------------------------------------------===// // RISC-V processors supported. diff --git a/lib/Target/RISCV/RISCVAsmPrinter.cpp b/lib/Target/RISCV/RISCVAsmPrinter.cpp index bdf8e5d840b30..57631dcb5115c 100644 --- a/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -1,9 +1,8 @@ //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -13,9 +12,10 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" -#include "InstPrinter/RISCVInstPrinter.h" +#include "MCTargetDesc/RISCVInstPrinter.h" #include "MCTargetDesc/RISCVMCExpr.h" #include "RISCVTargetMachine.h" +#include "TargetInfo/RISCVTargetInfo.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -43,11 +43,9 @@ public: void EmitInstruction(const MachineInstr *MI) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) override; + const char *ExtraCode, raw_ostream &OS) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) override; + const char *ExtraCode, raw_ostream &OS) override; void EmitToStreamer(MCStreamer &S, const MCInst &Inst); bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, @@ -84,39 +82,50 @@ void RISCVAsmPrinter::EmitInstruction(const MachineInstr *MI) { } bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) { - if (AsmVariant != 0) - report_fatal_error("There are no defined alternate asm variants"); - // First try the generic code, which knows about modifiers like 'c' and 'n'. - if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS)) + if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) return false; - if (!ExtraCode) { - const MachineOperand &MO = MI->getOperand(OpNo); - switch (MO.getType()) { - case MachineOperand::MO_Immediate: - OS << MO.getImm(); - return false; - case MachineOperand::MO_Register: - OS << RISCVInstPrinter::getRegisterName(MO.getReg()); - return false; + const MachineOperand &MO = MI->getOperand(OpNo); + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) + return true; // Unknown modifier. + + switch (ExtraCode[0]) { default: + return true; // Unknown modifier. + case 'z': // Print zero register if zero, regular printing otherwise. + if (MO.isImm() && MO.getImm() == 0) { + OS << RISCVInstPrinter::getRegisterName(RISCV::X0); + return false; + } break; + case 'i': // Literal 'i' if operand is not a register. + if (!MO.isReg()) + OS << 'i'; + return false; } } + switch (MO.getType()) { + case MachineOperand::MO_Immediate: + OS << MO.getImm(); + return false; + case MachineOperand::MO_Register: + OS << RISCVInstPrinter::getRegisterName(MO.getReg()); + return false; + default: + break; + } + return true; } bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, - unsigned OpNo, unsigned AsmVariant, + unsigned OpNo, const char *ExtraCode, raw_ostream &OS) { - if (AsmVariant != 0) - report_fatal_error("There are no defined alternate asm variants"); - if (!ExtraCode) { const MachineOperand &MO = MI->getOperand(OpNo); // For now, we only support register memory operands in registers and @@ -128,7 +137,7 @@ bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } - return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS); + return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); } // Force static initialization. diff --git a/lib/Target/RISCV/RISCVCallingConv.td b/lib/Target/RISCV/RISCVCallingConv.td index ef146258c3834..db13e6e8becaa 100644 --- a/lib/Target/RISCV/RISCVCallingConv.td +++ b/lib/Target/RISCV/RISCVCallingConv.td @@ -1,9 +1,8 @@ //===-- RISCVCallingConv.td - Calling Conventions RISCV ----*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -14,7 +13,16 @@ // The RISC-V calling convention is handled with custom code in // RISCVISelLowering.cpp (CC_RISCV). -def CSR : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>; +def CSR_ILP32_LP64 + : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>; + +def CSR_ILP32F_LP64F + : CalleeSavedRegs<(add CSR_ILP32_LP64, + F8_32, F9_32, (sequence "F%u_32", 18, 27))>; + +def CSR_ILP32D_LP64D + : CalleeSavedRegs<(add CSR_ILP32_LP64, + F8_64, F9_64, (sequence "F%u_64", 18, 27))>; // Needed for implementation of RISCVRegisterInfo::getNoPreservedMask() def CSR_NoRegs : CalleeSavedRegs<(add)>; diff --git a/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index 35c185aa5edd3..1c5171a7b7a46 100644 --- a/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -1,9 +1,8 @@ //===-- RISCVExpandPseudoInsts.cpp - Expand pseudo 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 // //===----------------------------------------------------------------------===// // @@ -55,6 +54,22 @@ private: bool expandAtomicCmpXchg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked, int Width, MachineBasicBlock::iterator &NextMBBI); + bool expandAuipcInstPair(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI, + unsigned FlagsHi, unsigned SecondOpcode); + bool expandLoadLocalAddress(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddress(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadTLSIEAddress(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadTLSGDAddress(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); }; char RISCVExpandPseudo::ID = 0; @@ -87,6 +102,9 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB, case RISCV::PseudoAtomicLoadNand32: return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32, NextMBBI); + case RISCV::PseudoAtomicLoadNand64: + return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64, + NextMBBI); case RISCV::PseudoMaskedAtomicSwap32: return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32, NextMBBI); @@ -111,8 +129,18 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB, NextMBBI); case RISCV::PseudoCmpXchg32: return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI); + case RISCV::PseudoCmpXchg64: + return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI); case RISCV::PseudoMaskedCmpXchg32: return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI); + case RISCV::PseudoLLA: + return expandLoadLocalAddress(MBB, MBBI, NextMBBI); + case RISCV::PseudoLA: + return expandLoadAddress(MBB, MBBI, NextMBBI); + case RISCV::PseudoLA_TLS_IE: + return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI); + case RISCV::PseudoLA_TLS_GD: + return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI); } return false; @@ -152,12 +180,61 @@ static unsigned getSCForRMW32(AtomicOrdering Ordering) { } } +static unsigned getLRForRMW64(AtomicOrdering Ordering) { + switch (Ordering) { + default: + llvm_unreachable("Unexpected AtomicOrdering"); + case AtomicOrdering::Monotonic: + return RISCV::LR_D; + case AtomicOrdering::Acquire: + return RISCV::LR_D_AQ; + case AtomicOrdering::Release: + return RISCV::LR_D; + case AtomicOrdering::AcquireRelease: + return RISCV::LR_D_AQ; + case AtomicOrdering::SequentiallyConsistent: + return RISCV::LR_D_AQ_RL; + } +} + +static unsigned getSCForRMW64(AtomicOrdering Ordering) { + switch (Ordering) { + default: + llvm_unreachable("Unexpected AtomicOrdering"); + case AtomicOrdering::Monotonic: + return RISCV::SC_D; + case AtomicOrdering::Acquire: + return RISCV::SC_D; + case AtomicOrdering::Release: + return RISCV::SC_D_RL; + case AtomicOrdering::AcquireRelease: + return RISCV::SC_D_RL; + case AtomicOrdering::SequentiallyConsistent: + return RISCV::SC_D_AQ_RL; + } +} + +static unsigned getLRForRMW(AtomicOrdering Ordering, int Width) { + if (Width == 32) + return getLRForRMW32(Ordering); + if (Width == 64) + return getLRForRMW64(Ordering); + llvm_unreachable("Unexpected LR width\n"); +} + +static unsigned getSCForRMW(AtomicOrdering Ordering, int Width) { + if (Width == 32) + return getSCForRMW32(Ordering); + if (Width == 64) + return getSCForRMW64(Ordering); + llvm_unreachable("Unexpected SC width\n"); +} + static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI, DebugLoc DL, MachineBasicBlock *ThisMBB, MachineBasicBlock *LoopMBB, MachineBasicBlock *DoneMBB, AtomicRMWInst::BinOp BinOp, int Width) { - assert(Width == 32 && "RV64 atomic expansion currently unsupported"); unsigned DestReg = MI.getOperand(0).getReg(); unsigned ScratchReg = MI.getOperand(1).getReg(); unsigned AddrReg = MI.getOperand(2).getReg(); @@ -166,11 +243,11 @@ static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI, static_cast<AtomicOrdering>(MI.getOperand(4).getImm()); // .loop: - // lr.w dest, (addr) + // lr.[w|d] dest, (addr) // binop scratch, dest, val - // sc.w scratch, scratch, (addr) + // sc.[w|d] scratch, scratch, (addr) // bnez scratch, loop - BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg) + BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) .addReg(AddrReg); switch (BinOp) { default: @@ -184,7 +261,7 @@ static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI, .addImm(-1); break; } - BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg) + BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) .addReg(AddrReg) .addReg(ScratchReg); BuildMI(LoopMBB, DL, TII->get(RISCV::BNE)) @@ -219,7 +296,7 @@ static void doMaskedAtomicBinOpExpansion( const RISCVInstrInfo *TII, MachineInstr &MI, DebugLoc DL, MachineBasicBlock *ThisMBB, MachineBasicBlock *LoopMBB, MachineBasicBlock *DoneMBB, AtomicRMWInst::BinOp BinOp, int Width) { - assert(Width == 32 && "RV64 atomic expansion currently unsupported"); + assert(Width == 32 && "Should never need to expand masked 64-bit operations"); unsigned DestReg = MI.getOperand(0).getReg(); unsigned ScratchReg = MI.getOperand(1).getReg(); unsigned AddrReg = MI.getOperand(2).getReg(); @@ -333,7 +410,7 @@ bool RISCVExpandPseudo::expandAtomicMinMaxOp( MachineBasicBlock::iterator &NextMBBI) { assert(IsMasked == true && "Should only need to expand masked atomic max/min"); - assert(Width == 32 && "RV64 atomic expansion currently unsupported"); + assert(Width == 32 && "Should never need to expand masked 64-bit operations"); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); @@ -451,7 +528,6 @@ bool RISCVExpandPseudo::expandAtomicMinMaxOp( bool RISCVExpandPseudo::expandAtomicCmpXchg( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked, int Width, MachineBasicBlock::iterator &NextMBBI) { - assert(Width == 32 && "RV64 atomic expansion currently unsupported"); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); MachineFunction *MF = MBB.getParent(); @@ -483,18 +559,18 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg( if (!IsMasked) { // .loophead: - // lr.w dest, (addr) + // lr.[w|d] dest, (addr) // bne dest, cmpval, done - BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg) + BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) .addReg(AddrReg); BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE)) .addReg(DestReg) .addReg(CmpValReg) .addMBB(DoneMBB); // .looptail: - // sc.w scratch, newval, (addr) + // sc.[w|d] scratch, newval, (addr) // bnez scratch, loophead - BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg) + BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) .addReg(AddrReg) .addReg(NewValReg); BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE)) @@ -507,7 +583,7 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg( // and scratch, dest, mask // bne scratch, cmpval, done unsigned MaskReg = MI.getOperand(5).getReg(); - BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg) + BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) .addReg(AddrReg); BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg) .addReg(DestReg) @@ -525,7 +601,7 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg( // bnez scratch, loophead insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg, MaskReg, ScratchReg); - BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg) + BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) .addReg(AddrReg) .addReg(ScratchReg); BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE)) @@ -545,6 +621,90 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg( return true; } +bool RISCVExpandPseudo::expandAuipcInstPair( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, + unsigned SecondOpcode) { + MachineFunction *MF = MBB.getParent(); + MachineInstr &MI = *MBBI; + DebugLoc DL = MI.getDebugLoc(); + + unsigned DestReg = MI.getOperand(0).getReg(); + const MachineOperand &Symbol = MI.getOperand(1); + + MachineBasicBlock *NewMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); + + // Tell AsmPrinter that we unconditionally want the symbol of this label to be + // emitted. + NewMBB->setLabelMustBeEmitted(); + + MF->insert(++MBB.getIterator(), NewMBB); + + BuildMI(NewMBB, DL, TII->get(RISCV::AUIPC), DestReg) + .addDisp(Symbol, 0, FlagsHi); + BuildMI(NewMBB, DL, TII->get(SecondOpcode), DestReg) + .addReg(DestReg) + .addMBB(NewMBB, RISCVII::MO_PCREL_LO); + + // Move all the rest of the instructions to NewMBB. + NewMBB->splice(NewMBB->end(), &MBB, std::next(MBBI), MBB.end()); + // Update machine-CFG edges. + NewMBB->transferSuccessorsAndUpdatePHIs(&MBB); + // Make the original basic block fall-through to the new. + MBB.addSuccessor(NewMBB); + + // Make sure live-ins are correctly attached to this new basic block. + LivePhysRegs LiveRegs; + computeAndAddLiveIns(LiveRegs, *NewMBB); + + NextMBBI = MBB.end(); + MI.eraseFromParent(); + return true; +} + +bool RISCVExpandPseudo::expandLoadLocalAddress( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_PCREL_HI, + RISCV::ADDI); +} + +bool RISCVExpandPseudo::expandLoadAddress( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + MachineFunction *MF = MBB.getParent(); + + unsigned SecondOpcode; + unsigned FlagsHi; + if (MF->getTarget().isPositionIndependent()) { + const auto &STI = MF->getSubtarget<RISCVSubtarget>(); + SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW; + FlagsHi = RISCVII::MO_GOT_HI; + } else { + SecondOpcode = RISCV::ADDI; + FlagsHi = RISCVII::MO_PCREL_HI; + } + return expandAuipcInstPair(MBB, MBBI, NextMBBI, FlagsHi, SecondOpcode); +} + +bool RISCVExpandPseudo::expandLoadTLSIEAddress( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + MachineFunction *MF = MBB.getParent(); + + const auto &STI = MF->getSubtarget<RISCVSubtarget>(); + unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW; + return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_TLS_GOT_HI, + SecondOpcode); +} + +bool RISCVExpandPseudo::expandLoadTLSGDAddress( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_TLS_GD_HI, + RISCV::ADDI); +} + } // end of anonymous namespace INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo", diff --git a/lib/Target/RISCV/RISCVFrameLowering.cpp b/lib/Target/RISCV/RISCVFrameLowering.cpp index 74417899c8da8..32c3b9684d2c3 100644 --- a/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -1,9 +1,8 @@ //===-- RISCVFrameLowering.cpp - RISCV Frame Information ------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -19,6 +18,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/MCDwarf.h" using namespace llvm; @@ -97,6 +97,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); + const RISCVRegisterInfo *RI = STI.getRegisterInfo(); + const RISCVInstrInfo *TII = STI.getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); unsigned FPReg = getFPReg(STI); @@ -120,6 +122,12 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, // Allocate space on the stack if necessary. adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); + // Emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + // The frame pointer is callee-saved, and code has been generated for us to // save it to the stack. We need to skip over the storing of callee-saved // registers as the frame pointer must be modified after it has been saved @@ -129,10 +137,28 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); std::advance(MBBI, CSI.size()); + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + for (const auto &Entry : CSI) { + int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); + unsigned Reg = Entry.getReg(); + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( + nullptr, RI->getDwarfRegNum(Reg, true), Offset)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + // Generate new FP. - if (hasFP(MF)) + if (hasFP(MF)) { adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); + + // Emit ".cfi_def_cfa $fp, 0" + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( + nullptr, RI->getDwarfRegNum(FPReg, true), 0)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } } void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, @@ -142,6 +168,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); DebugLoc DL = MBBI->getDebugLoc(); + const RISCVInstrInfo *TII = STI.getInstrInfo(); unsigned FPReg = getFPReg(STI); unsigned SPReg = getSPReg(STI); @@ -151,19 +178,58 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); uint64_t StackSize = MFI.getStackSize(); + uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); // Restore the stack pointer using the value of the frame pointer. Only // necessary if the stack pointer was modified, meaning the stack size is // unknown. if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { assert(hasFP(MF) && "frame pointer should not have been eliminated"); - adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, - -StackSize + RVFI->getVarArgsSaveSize(), + adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, MachineInstr::FrameDestroy); } + if (hasFP(MF)) { + // To find the instruction restoring FP from stack. + for (auto &I = LastFrameDestroy; I != MBBI; ++I) { + if (I->mayLoad() && I->getOperand(0).isReg()) { + unsigned DestReg = I->getOperand(0).getReg(); + if (DestReg == FPReg) { + // If there is frame pointer, after restoring $fp registers, we + // need adjust CFA to ($sp - FPOffset). + // Emit ".cfi_def_cfa $sp, -FPOffset" + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( + nullptr, RI->getDwarfRegNum(SPReg, true), -FPOffset)); + BuildMI(MBB, std::next(I), DL, + TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + break; + } + } + } + } + + // Add CFI directives for callee-saved registers. + const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); + // Iterate over list of callee-saved registers and emit .cfi_restore + // directives. + for (const auto &Entry : CSI) { + unsigned Reg = Entry.getReg(); + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore( + nullptr, RI->getDwarfRegNum(Reg, true))); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + // Deallocate stack adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); + + // After restoring $sp, we need to adjust CFA to $(sp + 0) + // Emit ".cfi_def_cfa_offset 0" + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, diff --git a/lib/Target/RISCV/RISCVFrameLowering.h b/lib/Target/RISCV/RISCVFrameLowering.h index ca653c2b9f17c..0e045c3ff8538 100644 --- a/lib/Target/RISCV/RISCVFrameLowering.h +++ b/lib/Target/RISCV/RISCVFrameLowering.h @@ -1,9 +1,8 @@ //===-- RISCVFrameLowering.h - Define frame lowering for RISCV -*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index aa80365feb830..d0a3af375a6d6 100644 --- a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -1,9 +1,8 @@ //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -156,7 +155,15 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { return; } } + break; } + case RISCVISD::READ_CYCLE_WIDE: + assert(!Subtarget->is64Bit() && "READ_CYCLE_WIDE is only used on riscv32"); + + ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ReadCycleWide, DL, MVT::i32, + MVT::i32, MVT::Other, + Node->getOperand(0))); + return; } // Select the default instruction. diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp index 508dcbd009edf..ce7b85911ab65 100644 --- a/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1,9 +1,8 @@ //===-- RISCVISelLowering.cpp - RISCV DAG Lowering Implementation --------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -18,6 +17,8 @@ #include "RISCVRegisterInfo.h" #include "RISCVSubtarget.h" #include "RISCVTargetMachine.h" +#include "Utils/RISCVMatInt.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -43,6 +44,24 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, const RISCVSubtarget &STI) : TargetLowering(TM), Subtarget(STI) { + if (Subtarget.isRV32E()) + report_fatal_error("Codegen not yet implemented for RV32E"); + + RISCVABI::ABI ABI = Subtarget.getTargetABI(); + assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI"); + + switch (ABI) { + default: + report_fatal_error("Don't know how to lower this ABI"); + case RISCVABI::ABI_ILP32: + case RISCVABI::ABI_ILP32F: + case RISCVABI::ABI_ILP32D: + case RISCVABI::ABI_LP64: + case RISCVABI::ABI_LP64F: + case RISCVABI::ABI_LP64D: + break; + } + MVT XLenVT = Subtarget.getXLenVT(); // Set up the register classes. @@ -81,10 +100,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); if (Subtarget.is64Bit()) { - setTargetDAGCombine(ISD::SHL); - setTargetDAGCombine(ISD::SRL); - setTargetDAGCombine(ISD::SRA); - setTargetDAGCombine(ISD::ANY_EXTEND); + setOperationAction(ISD::SHL, MVT::i32, Custom); + setOperationAction(ISD::SRA, MVT::i32, Custom); + setOperationAction(ISD::SRL, MVT::i32, Custom); } if (!Subtarget.hasStdExtM()) { @@ -97,14 +115,20 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::UREM, XLenVT, Expand); } + if (Subtarget.is64Bit() && Subtarget.hasStdExtM()) { + setOperationAction(ISD::SDIV, MVT::i32, Custom); + setOperationAction(ISD::UDIV, MVT::i32, Custom); + setOperationAction(ISD::UREM, MVT::i32, Custom); + } + setOperationAction(ISD::SDIVREM, XLenVT, Expand); setOperationAction(ISD::UDIVREM, XLenVT, Expand); setOperationAction(ISD::SMUL_LOHI, XLenVT, Expand); setOperationAction(ISD::UMUL_LOHI, XLenVT, Expand); - setOperationAction(ISD::SHL_PARTS, XLenVT, Expand); - setOperationAction(ISD::SRL_PARTS, XLenVT, Expand); - setOperationAction(ISD::SRA_PARTS, XLenVT, Expand); + setOperationAction(ISD::SHL_PARTS, XLenVT, Custom); + setOperationAction(ISD::SRL_PARTS, XLenVT, Custom); + setOperationAction(ISD::SRA_PARTS, XLenVT, Custom); setOperationAction(ISD::ROTL, XLenVT, Expand); setOperationAction(ISD::ROTR, XLenVT, Expand); @@ -114,9 +138,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTPOP, XLenVT, Expand); ISD::CondCode FPCCToExtend[] = { - ISD::SETOGT, ISD::SETOGE, ISD::SETONE, ISD::SETO, ISD::SETUEQ, - ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE, ISD::SETUNE, - ISD::SETGT, ISD::SETGE, ISD::SETNE}; + ISD::SETOGT, ISD::SETOGE, ISD::SETONE, ISD::SETUEQ, ISD::SETUGT, + ISD::SETUGE, ISD::SETULT, ISD::SETULE, ISD::SETUNE, ISD::SETGT, + ISD::SETGE, ISD::SETNE}; ISD::NodeType FPOpToExtend[] = { ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM}; @@ -133,6 +157,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(Op, MVT::f32, Expand); } + if (Subtarget.hasStdExtF() && Subtarget.is64Bit()) + setOperationAction(ISD::BITCAST, MVT::i32, Custom); + if (Subtarget.hasStdExtD()) { setOperationAction(ISD::FMINNUM, MVT::f64, Legal); setOperationAction(ISD::FMAXNUM, MVT::f64, Legal); @@ -151,6 +178,13 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::BlockAddress, XLenVT, Custom); setOperationAction(ISD::ConstantPool, XLenVT, Custom); + setOperationAction(ISD::GlobalTLSAddress, XLenVT, Custom); + + // TODO: On M-mode only targets, the cycle[h] CSR may not be present. + // Unfortunately this can't be determined just from the ISA naming string. + setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, + Subtarget.is64Bit() ? Legal : Custom); + if (Subtarget.hasStdExtA()) { setMaxAtomicSizeInBitsSupported(Subtarget.getXLen()); setMinCmpXchgSizeInBits(32); @@ -276,6 +310,11 @@ bool RISCVTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const { return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64; } +bool RISCVTargetLowering::hasBitPreservingFPLogic(EVT VT) const { + return (VT == MVT::f32 && Subtarget.hasStdExtF()) || + (VT == MVT::f64 && Subtarget.hasStdExtD()); +} + // Changes the condition code and swaps operands if necessary, so the SetCC // operation matches one of the comparisons supported directly in the RISC-V // ISA. @@ -326,6 +365,8 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerBlockAddress(Op, DAG); case ISD::ConstantPool: return lowerConstantPool(Op, DAG); + case ISD::GlobalTLSAddress: + return lowerGlobalTLSAddress(Op, DAG); case ISD::SELECT: return lowerSELECT(Op, DAG); case ISD::VASTART: @@ -334,6 +375,81 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerFRAMEADDR(Op, DAG); case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); + case ISD::SHL_PARTS: + return lowerShiftLeftParts(Op, DAG); + case ISD::SRA_PARTS: + return lowerShiftRightParts(Op, DAG, true); + case ISD::SRL_PARTS: + return lowerShiftRightParts(Op, DAG, false); + case ISD::BITCAST: { + assert(Subtarget.is64Bit() && Subtarget.hasStdExtF() && + "Unexpected custom legalisation"); + SDLoc DL(Op); + SDValue Op0 = Op.getOperand(0); + if (Op.getValueType() != MVT::f32 || Op0.getValueType() != MVT::i32) + return SDValue(); + SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); + SDValue FPConv = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, NewOp0); + return FPConv; + } + } +} + +static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); +} + +static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), + Flags); +} + +static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(), + N->getOffset(), Flags); +} + +template <class NodeTy> +SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, + bool IsLocal) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + + if (isPositionIndependent()) { + SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); + if (IsLocal) + // Use PC-relative addressing to access the symbol. This generates the + // pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym)) + // %pcrel_lo(auipc)). + return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0); + + // Use PC-relative addressing to access the GOT for this symbol, then load + // the address from the GOT. This generates the pattern (PseudoLA sym), + // which expands to (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))). + return SDValue(DAG.getMachineNode(RISCV::PseudoLA, DL, Ty, Addr), 0); + } + + switch (getTargetMachine().getCodeModel()) { + default: + report_fatal_error("Unsupported code model for lowering"); + case CodeModel::Small: { + // Generate a sequence for accessing addresses within the first 2 GiB of + // address space. This generates the pattern (addi (lui %hi(sym)) %lo(sym)). + SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_HI); + SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_LO); + SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); + return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0); + } + case CodeModel::Medium: { + // Generate a sequence for accessing addresses within any 2GiB range within + // the address space. This generates the pattern (PseudoLLA sym), which + // expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)). + SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); + return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0); + } } } @@ -342,67 +458,145 @@ SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op, SDLoc DL(Op); EVT Ty = Op.getValueType(); GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); - const GlobalValue *GV = N->getGlobal(); int64_t Offset = N->getOffset(); MVT XLenVT = Subtarget.getXLenVT(); - if (isPositionIndependent()) - report_fatal_error("Unable to lowerGlobalAddress"); + const GlobalValue *GV = N->getGlobal(); + bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV); + SDValue Addr = getAddr(N, DAG, IsLocal); + // In order to maximise the opportunity for common subexpression elimination, // emit a separate ADD node for the global address offset instead of folding // it in the global address node. Later peephole optimisations may choose to // fold it back in when profitable. - SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_HI); - SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_LO); - SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0); - SDValue MNLo = - SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0); if (Offset != 0) - return DAG.getNode(ISD::ADD, DL, Ty, MNLo, + return DAG.getNode(ISD::ADD, DL, Ty, Addr, DAG.getConstant(Offset, DL, XLenVT)); - return MNLo; + return Addr; } SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { - SDLoc DL(Op); - EVT Ty = Op.getValueType(); BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); - const BlockAddress *BA = N->getBlockAddress(); - int64_t Offset = N->getOffset(); - if (isPositionIndependent()) - report_fatal_error("Unable to lowerBlockAddress"); - - SDValue BAHi = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_HI); - SDValue BALo = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_LO); - SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, BAHi), 0); - SDValue MNLo = - SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, BALo), 0); - return MNLo; + return getAddr(N, DAG); } SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op, SelectionDAG &DAG) const { + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + + return getAddr(N, DAG); +} + +SDValue RISCVTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG, + bool UseGOT) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + const GlobalValue *GV = N->getGlobal(); + MVT XLenVT = Subtarget.getXLenVT(); + + if (UseGOT) { + // Use PC-relative addressing to access the GOT for this TLS symbol, then + // load the address from the GOT and add the thread pointer. This generates + // the pattern (PseudoLA_TLS_IE sym), which expands to + // (ld (auipc %tls_ie_pcrel_hi(sym)) %pcrel_lo(auipc)). + SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); + SDValue Load = + SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLS_IE, DL, Ty, Addr), 0); + + // Add the thread pointer. + SDValue TPReg = DAG.getRegister(RISCV::X4, XLenVT); + return DAG.getNode(ISD::ADD, DL, Ty, Load, TPReg); + } + + // Generate a sequence for accessing the address relative to the thread + // pointer, with the appropriate adjustment for the thread pointer offset. + // This generates the pattern + // (add (add_tprel (lui %tprel_hi(sym)) tp %tprel_add(sym)) %tprel_lo(sym)) + SDValue AddrHi = + DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_HI); + SDValue AddrAdd = + DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_ADD); + SDValue AddrLo = + DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_LO); + + SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); + SDValue TPReg = DAG.getRegister(RISCV::X4, XLenVT); + SDValue MNAdd = SDValue( + DAG.getMachineNode(RISCV::PseudoAddTPRel, DL, Ty, MNHi, TPReg, AddrAdd), + 0); + return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNAdd, AddrLo), 0); +} + +SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); + const GlobalValue *GV = N->getGlobal(); + + // Use a PC-relative addressing mode to access the global dynamic GOT address. + // This generates the pattern (PseudoLA_TLS_GD sym), which expands to + // (addi (auipc %tls_gd_pcrel_hi(sym)) %pcrel_lo(auipc)). + SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); + SDValue Load = + SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLS_GD, DL, Ty, Addr), 0); + + // Prepare argument list to generate call. + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Load; + Entry.Ty = CallTy; + Args.push_back(Entry); + + // Setup call to __tls_get_addr. + TargetLowering::CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(DL) + .setChain(DAG.getEntryNode()) + .setLibCallee(CallingConv::C, CallTy, + DAG.getExternalSymbol("__tls_get_addr", Ty), + std::move(Args)); + + return LowerCallTo(CLI).first; +} + +SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { SDLoc DL(Op); EVT Ty = Op.getValueType(); - ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); - const Constant *CPA = N->getConstVal(); + GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); int64_t Offset = N->getOffset(); - unsigned Alignment = N->getAlignment(); + MVT XLenVT = Subtarget.getXLenVT(); - if (!isPositionIndependent()) { - SDValue CPAHi = - DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_HI); - SDValue CPALo = - DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_LO); - SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, CPAHi), 0); - SDValue MNLo = - SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, CPALo), 0); - return MNLo; - } else { - report_fatal_error("Unable to lowerConstantPool"); + // Non-PIC TLS lowering should always use the LocalExec model. + TLSModel::Model Model = isPositionIndependent() + ? getTargetMachine().getTLSModel(N->getGlobal()) + : TLSModel::LocalExec; + + SDValue Addr; + switch (Model) { + case TLSModel::LocalExec: + Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/false); + break; + case TLSModel::InitialExec: + Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/true); + break; + case TLSModel::LocalDynamic: + case TLSModel::GeneralDynamic: + Addr = getDynamicTLSAddr(N, DAG); + break; } + + // In order to maximise the opportunity for common subexpression elimination, + // emit a separate ADD node for the global address offset instead of folding + // it in the global address node. Later peephole optimisations may choose to + // fold it back in when profitable. + if (Offset != 0) + return DAG.getNode(ISD::ADD, DL, Ty, Addr, + DAG.getConstant(Offset, DL, XLenVT)); + return Addr; } SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const { @@ -513,29 +707,184 @@ SDValue RISCVTargetLowering::lowerRETURNADDR(SDValue Op, return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, XLenVT); } -// Return true if the given node is a shift with a non-constant shift amount. -static bool isVariableShift(SDValue Val) { - switch (Val.getOpcode()) { +SDValue RISCVTargetLowering::lowerShiftLeftParts(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0); + SDValue Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + EVT VT = Lo.getValueType(); + + // if Shamt-XLEN < 0: // Shamt < XLEN + // Lo = Lo << Shamt + // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (XLEN-1 - Shamt)) + // else: + // Lo = 0 + // Hi = Lo << (Shamt-XLEN) + + SDValue Zero = DAG.getConstant(0, DL, VT); + SDValue One = DAG.getConstant(1, DL, VT); + SDValue MinusXLen = DAG.getConstant(-(int)Subtarget.getXLen(), DL, VT); + SDValue XLenMinus1 = DAG.getConstant(Subtarget.getXLen() - 1, DL, VT); + SDValue ShamtMinusXLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusXLen); + SDValue XLenMinus1Shamt = DAG.getNode(ISD::SUB, DL, VT, XLenMinus1, Shamt); + + SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); + SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); + SDValue ShiftRightLo = + DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, XLenMinus1Shamt); + SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); + SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); + SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusXLen); + + SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusXLen, Zero, ISD::SETLT); + + Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); + Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); + + SDValue Parts[2] = {Lo, Hi}; + return DAG.getMergeValues(Parts, DL); +} + +SDValue RISCVTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, + bool IsSRA) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0); + SDValue Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + EVT VT = Lo.getValueType(); + + // SRA expansion: + // if Shamt-XLEN < 0: // Shamt < XLEN + // Lo = (Lo >>u Shamt) | ((Hi << 1) << (XLEN-1 - Shamt)) + // Hi = Hi >>s Shamt + // else: + // Lo = Hi >>s (Shamt-XLEN); + // Hi = Hi >>s (XLEN-1) + // + // SRL expansion: + // if Shamt-XLEN < 0: // Shamt < XLEN + // Lo = (Lo >>u Shamt) | ((Hi << 1) << (XLEN-1 - Shamt)) + // Hi = Hi >>u Shamt + // else: + // Lo = Hi >>u (Shamt-XLEN); + // Hi = 0; + + unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; + + SDValue Zero = DAG.getConstant(0, DL, VT); + SDValue One = DAG.getConstant(1, DL, VT); + SDValue MinusXLen = DAG.getConstant(-(int)Subtarget.getXLen(), DL, VT); + SDValue XLenMinus1 = DAG.getConstant(Subtarget.getXLen() - 1, DL, VT); + SDValue ShamtMinusXLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusXLen); + SDValue XLenMinus1Shamt = DAG.getNode(ISD::SUB, DL, VT, XLenMinus1, Shamt); + + SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); + SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); + SDValue ShiftLeftHi = + DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, XLenMinus1Shamt); + SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); + SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); + SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusXLen); + SDValue HiFalse = + IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, XLenMinus1) : Zero; + + SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusXLen, Zero, ISD::SETLT); + + Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); + Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); + + SDValue Parts[2] = {Lo, Hi}; + return DAG.getMergeValues(Parts, DL); +} + +// Returns the opcode of the target-specific SDNode that implements the 32-bit +// form of the given Opcode. +static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) { + switch (Opcode) { default: - return false; + llvm_unreachable("Unexpected opcode"); case ISD::SHL: + return RISCVISD::SLLW; case ISD::SRA: + return RISCVISD::SRAW; case ISD::SRL: - return Val.getOperand(1).getOpcode() != ISD::Constant; + return RISCVISD::SRLW; + case ISD::SDIV: + return RISCVISD::DIVW; + case ISD::UDIV: + return RISCVISD::DIVUW; + case ISD::UREM: + return RISCVISD::REMUW; } } -// Returns true if the given node is an sdiv, udiv, or urem with non-constant -// operands. -static bool isVariableSDivUDivURem(SDValue Val) { - switch (Val.getOpcode()) { +// Converts the given 32-bit operation to a target-specific SelectionDAG node. +// Because i32 isn't a legal type for RV64, these operations would otherwise +// be promoted to i64, making it difficult to select the SLLW/DIVUW/.../*W +// later one because the fact the operation was originally of type i32 is +// lost. +static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG) { + SDLoc DL(N); + RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode()); + SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); + SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); + SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); + // ReplaceNodeResults requires we maintain the same type for the return value. + return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes); +} + +void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const { + SDLoc DL(N); + switch (N->getOpcode()) { default: - return false; + llvm_unreachable("Don't know how to custom type legalize this operation!"); + case ISD::READCYCLECOUNTER: { + assert(!Subtarget.is64Bit() && + "READCYCLECOUNTER only has custom type legalization on riscv32"); + + SDVTList VTs = DAG.getVTList(MVT::i32, MVT::i32, MVT::Other); + SDValue RCW = + DAG.getNode(RISCVISD::READ_CYCLE_WIDE, DL, VTs, N->getOperand(0)); + + Results.push_back(RCW); + Results.push_back(RCW.getValue(1)); + Results.push_back(RCW.getValue(2)); + break; + } + case ISD::SHL: + case ISD::SRA: + case ISD::SRL: + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + if (N->getOperand(1).getOpcode() == ISD::Constant) + return; + Results.push_back(customLegalizeToWOp(N, DAG)); + break; case ISD::SDIV: case ISD::UDIV: case ISD::UREM: - return Val.getOperand(0).getOpcode() != ISD::Constant && - Val.getOperand(1).getOpcode() != ISD::Constant; + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + Subtarget.hasStdExtM() && "Unexpected custom legalisation"); + if (N->getOperand(0).getOpcode() == ISD::Constant || + N->getOperand(1).getOpcode() == ISD::Constant) + return; + Results.push_back(customLegalizeToWOp(N, DAG)); + break; + case ISD::BITCAST: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + Subtarget.hasStdExtF() && "Unexpected custom legalisation"); + SDLoc DL(N); + SDValue Op0 = N->getOperand(0); + if (Op0.getValueType() != MVT::f32) + return; + SDValue FPConv = + DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Op0); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, FPConv)); + break; + } } } @@ -546,51 +895,225 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, switch (N->getOpcode()) { default: break; - case ISD::SHL: - case ISD::SRL: - case ISD::SRA: { - assert(Subtarget.getXLen() == 64 && "Combine should be 64-bit only"); - if (!DCI.isBeforeLegalize()) - break; - SDValue RHS = N->getOperand(1); - if (N->getValueType(0) != MVT::i32 || RHS->getOpcode() == ISD::Constant || - (RHS->getOpcode() == ISD::AssertZext && - cast<VTSDNode>(RHS->getOperand(1))->getVT().getSizeInBits() <= 5)) + case RISCVISD::SplitF64: { + SDValue Op0 = N->getOperand(0); + // If the input to SplitF64 is just BuildPairF64 then the operation is + // redundant. Instead, use BuildPairF64's operands directly. + if (Op0->getOpcode() == RISCVISD::BuildPairF64) + return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1)); + + SDLoc DL(N); + + // It's cheaper to materialise two 32-bit integers than to load a double + // from the constant pool and transfer it to integer registers through the + // stack. + if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op0)) { + APInt V = C->getValueAPF().bitcastToAPInt(); + SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32); + SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32); + return DCI.CombineTo(N, Lo, Hi); + } + + // This is a target-specific version of a DAGCombine performed in + // DAGCombiner::visitBITCAST. It performs the equivalent of: + // fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) + // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) + if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) || + !Op0.getNode()->hasOneUse()) break; + SDValue NewSplitF64 = + DAG.getNode(RISCVISD::SplitF64, DL, DAG.getVTList(MVT::i32, MVT::i32), + Op0.getOperand(0)); + SDValue Lo = NewSplitF64.getValue(0); + SDValue Hi = NewSplitF64.getValue(1); + APInt SignBit = APInt::getSignMask(32); + if (Op0.getOpcode() == ISD::FNEG) { + SDValue NewHi = DAG.getNode(ISD::XOR, DL, MVT::i32, Hi, + DAG.getConstant(SignBit, DL, MVT::i32)); + return DCI.CombineTo(N, Lo, NewHi); + } + assert(Op0.getOpcode() == ISD::FABS); + SDValue NewHi = DAG.getNode(ISD::AND, DL, MVT::i32, Hi, + DAG.getConstant(~SignBit, DL, MVT::i32)); + return DCI.CombineTo(N, Lo, NewHi); + } + case RISCVISD::SLLW: + case RISCVISD::SRAW: + case RISCVISD::SRLW: { + // Only the lower 32 bits of LHS and lower 5 bits of RHS are read. SDValue LHS = N->getOperand(0); - SDLoc DL(N); - SDValue NewRHS = - DAG.getNode(ISD::AssertZext, DL, RHS.getValueType(), RHS, - DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), 5))); - return DCI.CombineTo( - N, DAG.getNode(N->getOpcode(), DL, LHS.getValueType(), LHS, NewRHS)); + SDValue RHS = N->getOperand(1); + APInt LHSMask = APInt::getLowBitsSet(LHS.getValueSizeInBits(), 32); + APInt RHSMask = APInt::getLowBitsSet(RHS.getValueSizeInBits(), 5); + if ((SimplifyDemandedBits(N->getOperand(0), LHSMask, DCI)) || + (SimplifyDemandedBits(N->getOperand(1), RHSMask, DCI))) + return SDValue(); + break; } - case ISD::ANY_EXTEND: { - // If any-extending an i32 variable-length shift or sdiv/udiv/urem to i64, - // then instead sign-extend in order to increase the chance of being able - // to select the sllw/srlw/sraw/divw/divuw/remuw instructions. - SDValue Src = N->getOperand(0); - if (N->getValueType(0) != MVT::i64 || Src.getValueType() != MVT::i32) - break; - if (!isVariableShift(Src) && - !(Subtarget.hasStdExtM() && isVariableSDivUDivURem(Src))) - break; + case RISCVISD::FMV_X_ANYEXTW_RV64: { SDLoc DL(N); - return DCI.CombineTo(N, DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, Src)); - } - case RISCVISD::SplitF64: { - // If the input to SplitF64 is just BuildPairF64 then the operation is - // redundant. Instead, use BuildPairF64's operands directly. SDValue Op0 = N->getOperand(0); - if (Op0->getOpcode() != RISCVISD::BuildPairF64) + // If the input to FMV_X_ANYEXTW_RV64 is just FMV_W_X_RV64 then the + // conversion is unnecessary and can be replaced with an ANY_EXTEND + // of the FMV_W_X_RV64 operand. + if (Op0->getOpcode() == RISCVISD::FMV_W_X_RV64) { + SDValue AExtOp = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0.getOperand(0)); + return DCI.CombineTo(N, AExtOp); + } + + // This is a target-specific version of a DAGCombine performed in + // DAGCombiner::visitBITCAST. It performs the equivalent of: + // fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) + // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) + if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) || + !Op0.getNode()->hasOneUse()) break; - return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1)); + SDValue NewFMV = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, + Op0.getOperand(0)); + APInt SignBit = APInt::getSignMask(32).sext(64); + if (Op0.getOpcode() == ISD::FNEG) { + return DCI.CombineTo(N, + DAG.getNode(ISD::XOR, DL, MVT::i64, NewFMV, + DAG.getConstant(SignBit, DL, MVT::i64))); + } + assert(Op0.getOpcode() == ISD::FABS); + return DCI.CombineTo(N, + DAG.getNode(ISD::AND, DL, MVT::i64, NewFMV, + DAG.getConstant(~SignBit, DL, MVT::i64))); } } return SDValue(); } +bool RISCVTargetLowering::isDesirableToCommuteWithShift( + const SDNode *N, CombineLevel Level) const { + // The following folds are only desirable if `(OP _, c1 << c2)` can be + // materialised in fewer instructions than `(OP _, c1)`: + // + // (shl (add x, c1), c2) -> (add (shl x, c2), c1 << c2) + // (shl (or x, c1), c2) -> (or (shl x, c2), c1 << c2) + SDValue N0 = N->getOperand(0); + EVT Ty = N0.getValueType(); + if (Ty.isScalarInteger() && + (N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::OR)) { + auto *C1 = dyn_cast<ConstantSDNode>(N0->getOperand(1)); + auto *C2 = dyn_cast<ConstantSDNode>(N->getOperand(1)); + if (C1 && C2) { + APInt C1Int = C1->getAPIntValue(); + APInt ShiftedC1Int = C1Int << C2->getAPIntValue(); + + // We can materialise `c1 << c2` into an add immediate, so it's "free", + // and the combine should happen, to potentially allow further combines + // later. + if (isLegalAddImmediate(ShiftedC1Int.getSExtValue())) + return true; + + // We can materialise `c1` in an add immediate, so it's "free", and the + // combine should be prevented. + if (isLegalAddImmediate(C1Int.getSExtValue())) + return false; + + // Neither constant will fit into an immediate, so find materialisation + // costs. + int C1Cost = RISCVMatInt::getIntMatCost(C1Int, Ty.getSizeInBits(), + Subtarget.is64Bit()); + int ShiftedC1Cost = RISCVMatInt::getIntMatCost( + ShiftedC1Int, Ty.getSizeInBits(), Subtarget.is64Bit()); + + // Materialising `c1` is cheaper than materialising `c1 << c2`, so the + // combine should be prevented. + if (C1Cost < ShiftedC1Cost) + return false; + } + } + return true; +} + +unsigned RISCVTargetLowering::ComputeNumSignBitsForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + unsigned Depth) const { + switch (Op.getOpcode()) { + default: + break; + case RISCVISD::SLLW: + case RISCVISD::SRAW: + case RISCVISD::SRLW: + case RISCVISD::DIVW: + case RISCVISD::DIVUW: + case RISCVISD::REMUW: + // TODO: As the result is sign-extended, this is conservatively correct. A + // more precise answer could be calculated for SRAW depending on known + // bits in the shift amount. + return 33; + } + + return 1; +} + +MachineBasicBlock *emitReadCycleWidePseudo(MachineInstr &MI, + MachineBasicBlock *BB) { + assert(MI.getOpcode() == RISCV::ReadCycleWide && "Unexpected instruction"); + + // To read the 64-bit cycle CSR on a 32-bit target, we read the two halves. + // Should the count have wrapped while it was being read, we need to try + // again. + // ... + // read: + // rdcycleh x3 # load high word of cycle + // rdcycle x2 # load low word of cycle + // rdcycleh x4 # load high word of cycle + // bne x3, x4, read # check if high word reads match, otherwise try again + // ... + + MachineFunction &MF = *BB->getParent(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVM_BB); + MF.insert(It, LoopMBB); + + MachineBasicBlock *DoneMBB = MF.CreateMachineBasicBlock(LLVM_BB); + MF.insert(It, DoneMBB); + + // Transfer the remainder of BB and its successor edges to DoneMBB. + DoneMBB->splice(DoneMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + DoneMBB->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(LoopMBB); + + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + unsigned ReadAgainReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); + unsigned LoReg = MI.getOperand(0).getReg(); + unsigned HiReg = MI.getOperand(1).getReg(); + DebugLoc DL = MI.getDebugLoc(); + + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), HiReg) + .addImm(RISCVSysReg::lookupSysRegByName("CYCLEH")->Encoding) + .addReg(RISCV::X0); + BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), LoReg) + .addImm(RISCVSysReg::lookupSysRegByName("CYCLE")->Encoding) + .addReg(RISCV::X0); + BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), ReadAgainReg) + .addImm(RISCVSysReg::lookupSysRegByName("CYCLEH")->Encoding) + .addReg(RISCV::X0); + + BuildMI(LoopMBB, DL, TII->get(RISCV::BNE)) + .addReg(HiReg) + .addReg(ReadAgainReg) + .addMBB(LoopMBB); + + LoopMBB->addSuccessor(LoopMBB); + LoopMBB->addSuccessor(DoneMBB); + + MI.eraseFromParent(); + + return DoneMBB; +} + static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB) { assert(MI.getOpcode() == RISCV::SplitF64Pseudo && "Unexpected instruction"); @@ -655,24 +1178,21 @@ static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI, return BB; } -MachineBasicBlock * -RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, - MachineBasicBlock *BB) const { +static bool isSelectPseudo(MachineInstr &MI) { switch (MI.getOpcode()) { default: - llvm_unreachable("Unexpected instr type to insert"); + return false; case RISCV::Select_GPR_Using_CC_GPR: case RISCV::Select_FPR32_Using_CC_GPR: case RISCV::Select_FPR64_Using_CC_GPR: - break; - case RISCV::BuildPairF64Pseudo: - return emitBuildPairF64Pseudo(MI, BB); - case RISCV::SplitF64Pseudo: - return emitSplitF64Pseudo(MI, BB); + return true; } +} - // To "insert" a SELECT instruction, we actually have to insert the triangle - // control-flow pattern. The incoming instruction knows the destination vreg +static MachineBasicBlock *emitSelectPseudo(MachineInstr &MI, + MachineBasicBlock *BB) { + // To "insert" Select_* instructions, we actually have to insert the triangle + // control-flow pattern. The incoming instructions know the destination vreg // to set, the condition code register to branch on, the true/false values to // select between, and the condcode to use to select the appropriate branch. // @@ -682,6 +1202,54 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, // | IfFalseMBB // | / // TailMBB + // + // When we find a sequence of selects we attempt to optimize their emission + // by sharing the control flow. Currently we only handle cases where we have + // multiple selects with the exact same condition (same LHS, RHS and CC). + // The selects may be interleaved with other instructions if the other + // instructions meet some requirements we deem safe: + // - They are debug instructions. Otherwise, + // - They do not have side-effects, do not access memory and their inputs do + // not depend on the results of the select pseudo-instructions. + // The TrueV/FalseV operands of the selects cannot depend on the result of + // previous selects in the sequence. + // These conditions could be further relaxed. See the X86 target for a + // related approach and more information. + unsigned LHS = MI.getOperand(1).getReg(); + unsigned RHS = MI.getOperand(2).getReg(); + auto CC = static_cast<ISD::CondCode>(MI.getOperand(3).getImm()); + + SmallVector<MachineInstr *, 4> SelectDebugValues; + SmallSet<unsigned, 4> SelectDests; + SelectDests.insert(MI.getOperand(0).getReg()); + + MachineInstr *LastSelectPseudo = &MI; + + for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI); + SequenceMBBI != E; ++SequenceMBBI) { + if (SequenceMBBI->isDebugInstr()) + continue; + else if (isSelectPseudo(*SequenceMBBI)) { + if (SequenceMBBI->getOperand(1).getReg() != LHS || + SequenceMBBI->getOperand(2).getReg() != RHS || + SequenceMBBI->getOperand(3).getImm() != CC || + SelectDests.count(SequenceMBBI->getOperand(4).getReg()) || + SelectDests.count(SequenceMBBI->getOperand(5).getReg())) + break; + LastSelectPseudo = &*SequenceMBBI; + SequenceMBBI->collectDebugValues(SelectDebugValues); + SelectDests.insert(SequenceMBBI->getOperand(0).getReg()); + } else { + if (SequenceMBBI->hasUnmodeledSideEffects() || + SequenceMBBI->mayLoadOrStore()) + break; + if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) { + return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg()); + })) + break; + } + } + const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); DebugLoc DL = MI.getDebugLoc(); @@ -694,20 +1262,23 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, F->insert(I, IfFalseMBB); F->insert(I, TailMBB); - // Move all remaining instructions to TailMBB. - TailMBB->splice(TailMBB->begin(), HeadMBB, - std::next(MachineBasicBlock::iterator(MI)), HeadMBB->end()); + + // Transfer debug instructions associated with the selects to TailMBB. + for (MachineInstr *DebugInstr : SelectDebugValues) { + TailMBB->push_back(DebugInstr->removeFromParent()); + } + + // Move all instructions after the sequence to TailMBB. + TailMBB->splice(TailMBB->end(), HeadMBB, + std::next(LastSelectPseudo->getIterator()), HeadMBB->end()); // Update machine-CFG edges by transferring all successors of the current - // block to the new block which will contain the Phi node for the select. + // block to the new block which will contain the Phi nodes for the selects. TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB); // Set the successors for HeadMBB. HeadMBB->addSuccessor(IfFalseMBB); HeadMBB->addSuccessor(TailMBB); // Insert appropriate branch. - unsigned LHS = MI.getOperand(1).getReg(); - unsigned RHS = MI.getOperand(2).getReg(); - auto CC = static_cast<ISD::CondCode>(MI.getOperand(3).getImm()); unsigned Opcode = getBranchOpcodeForIntCondCode(CC); BuildMI(HeadMBB, DL, TII.get(Opcode)) @@ -718,18 +1289,50 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, // IfFalseMBB just falls through to TailMBB. IfFalseMBB->addSuccessor(TailMBB); - // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ] - BuildMI(*TailMBB, TailMBB->begin(), DL, TII.get(RISCV::PHI), - MI.getOperand(0).getReg()) - .addReg(MI.getOperand(4).getReg()) - .addMBB(HeadMBB) - .addReg(MI.getOperand(5).getReg()) - .addMBB(IfFalseMBB); + // Create PHIs for all of the select pseudo-instructions. + auto SelectMBBI = MI.getIterator(); + auto SelectEnd = std::next(LastSelectPseudo->getIterator()); + auto InsertionPoint = TailMBB->begin(); + while (SelectMBBI != SelectEnd) { + auto Next = std::next(SelectMBBI); + if (isSelectPseudo(*SelectMBBI)) { + // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ] + BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(), + TII.get(RISCV::PHI), SelectMBBI->getOperand(0).getReg()) + .addReg(SelectMBBI->getOperand(4).getReg()) + .addMBB(HeadMBB) + .addReg(SelectMBBI->getOperand(5).getReg()) + .addMBB(IfFalseMBB); + SelectMBBI->eraseFromParent(); + } + SelectMBBI = Next; + } - MI.eraseFromParent(); // The pseudo instruction is gone now. + F->getProperties().reset(MachineFunctionProperties::Property::NoPHIs); return TailMBB; } +MachineBasicBlock * +RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const { + switch (MI.getOpcode()) { + default: + llvm_unreachable("Unexpected instr type to insert"); + case RISCV::ReadCycleWide: + assert(!Subtarget.is64Bit() && + "ReadCycleWrite is only to be used on riscv32"); + return emitReadCycleWidePseudo(MI, BB); + case RISCV::Select_GPR_Using_CC_GPR: + case RISCV::Select_FPR32_Using_CC_GPR: + case RISCV::Select_FPR64_Using_CC_GPR: + return emitSelectPseudo(MI, BB); + case RISCV::BuildPairF64Pseudo: + return emitBuildPairF64Pseudo(MI, BB); + case RISCV::SplitF64Pseudo: + return emitSplitF64Pseudo(MI, BB); + } +} + // Calling Convention Implementation. // The expectations for frontend ABI lowering vary from target to target. // Ideally, an LLVM frontend would be able to avoid worrying about many ABI @@ -759,6 +1362,14 @@ static const MCPhysReg ArgGPRs[] = { RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17 }; +static const MCPhysReg ArgFPR32s[] = { + RISCV::F10_32, RISCV::F11_32, RISCV::F12_32, RISCV::F13_32, + RISCV::F14_32, RISCV::F15_32, RISCV::F16_32, RISCV::F17_32 +}; +static const MCPhysReg ArgFPR64s[] = { + RISCV::F10_64, RISCV::F11_64, RISCV::F12_64, RISCV::F13_64, + RISCV::F14_64, RISCV::F15_64, RISCV::F16_64, RISCV::F17_64 +}; // Pass a 2*XLEN argument that has been split into two XLEN values through // registers or the stack as necessary. @@ -799,22 +1410,59 @@ static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, } // Implements the RISC-V calling convention. Returns true upon failure. -static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT, - CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, - CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) { +static bool CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo, + MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, + bool IsRet, Type *OrigTy) { unsigned XLen = DL.getLargestLegalIntTypeSizeInBits(); assert(XLen == 32 || XLen == 64); MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64; - if (ValVT == MVT::f32) { - LocVT = MVT::i32; - LocInfo = CCValAssign::BCvt; - } // Any return value split in to more than two values can't be returned // directly. if (IsRet && ValNo > 1) return true; + // UseGPRForF32 if targeting one of the soft-float ABIs, if passing a + // variadic argument, or if no F32 argument registers are available. + bool UseGPRForF32 = true; + // UseGPRForF64 if targeting soft-float ABIs or an FLEN=32 ABI, if passing a + // variadic argument, or if no F64 argument registers are available. + bool UseGPRForF64 = true; + + switch (ABI) { + default: + llvm_unreachable("Unexpected ABI"); + case RISCVABI::ABI_ILP32: + case RISCVABI::ABI_LP64: + break; + case RISCVABI::ABI_ILP32F: + case RISCVABI::ABI_LP64F: + UseGPRForF32 = !IsFixed; + break; + case RISCVABI::ABI_ILP32D: + case RISCVABI::ABI_LP64D: + UseGPRForF32 = !IsFixed; + UseGPRForF64 = !IsFixed; + break; + } + + if (State.getFirstUnallocated(ArgFPR32s) == array_lengthof(ArgFPR32s)) + UseGPRForF32 = true; + if (State.getFirstUnallocated(ArgFPR64s) == array_lengthof(ArgFPR64s)) + UseGPRForF64 = true; + + // From this point on, rely on UseGPRForF32, UseGPRForF64 and similar local + // variables rather than directly checking against the target ABI. + + if (UseGPRForF32 && ValVT == MVT::f32) { + LocVT = XLenVT; + LocInfo = CCValAssign::BCvt; + } else if (UseGPRForF64 && XLen == 64 && ValVT == MVT::f64) { + LocVT = MVT::i64; + LocInfo = CCValAssign::BCvt; + } + // If this is a variadic argument, the RISC-V calling convention requires // that it is assigned an 'even' or 'aligned' register if it has 8-byte // alignment (RV32) or 16-byte alignment (RV64). An aligned register should @@ -838,8 +1486,9 @@ static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT, assert(PendingLocs.size() == PendingArgFlags.size() && "PendingLocs and PendingArgFlags out of sync"); - // Handle passing f64 on RV32D with a soft float ABI. - if (XLen == 32 && ValVT == MVT::f64) { + // Handle passing f64 on RV32D with a soft float ABI or when floating point + // registers are exhausted. + if (UseGPRForF64 && XLen == 32 && ValVT == MVT::f64) { assert(!ArgFlags.isSplit() && PendingLocs.empty() && "Can't lower f64 if it is split"); // Depending on available argument GPRS, f64 may be passed in a pair of @@ -888,7 +1537,13 @@ static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT, } // Allocate to a register if possible, or else a stack slot. - unsigned Reg = State.AllocateReg(ArgGPRs); + unsigned Reg; + if (ValVT == MVT::f32 && !UseGPRForF32) + Reg = State.AllocateReg(ArgFPR32s, ArgFPR64s); + else if (ValVT == MVT::f64 && !UseGPRForF64) + Reg = State.AllocateReg(ArgFPR64s, ArgFPR32s); + else + Reg = State.AllocateReg(ArgGPRs); unsigned StackOffset = Reg ? 0 : State.AllocateStack(XLen / 8, XLen / 8); // If we reach this point and PendingLocs is non-empty, we must be at the @@ -909,15 +1564,17 @@ static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT, return false; } - assert(LocVT == XLenVT && "Expected an XLenVT at this stage"); + assert((!UseGPRForF32 || !UseGPRForF64 || LocVT == XLenVT) && + "Expected an XLenVT at this stage"); if (Reg) { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } - if (ValVT == MVT::f32) { - LocVT = MVT::f32; + // When an f32 or f64 is passed on the stack, no bit-conversion is needed. + if (ValVT == MVT::f32 || ValVT == MVT::f64) { + LocVT = ValVT; LocInfo = CCValAssign::Full; } State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); @@ -940,7 +1597,8 @@ void RISCVTargetLowering::analyzeInputArgs( else if (Ins[i].isOrigArg()) ArgTy = FType->getParamType(Ins[i].getOrigArgIndex()); - if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full, + RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI(); + if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo, /*IsRet=*/true, IsRet, ArgTy)) { LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << EVT(ArgVT).getEVTString() << '\n'); @@ -960,7 +1618,8 @@ void RISCVTargetLowering::analyzeOutputArgs( ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr; - if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full, + RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI(); + if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) { LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << EVT(ArgVT).getEVTString() << "\n"); @@ -979,6 +1638,10 @@ static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, case CCValAssign::Full: break; case CCValAssign::BCvt: + if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) { + Val = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, Val); + break; + } Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); break; } @@ -993,8 +1656,24 @@ static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, MachineRegisterInfo &RegInfo = MF.getRegInfo(); EVT LocVT = VA.getLocVT(); SDValue Val; + const TargetRegisterClass *RC; + + switch (LocVT.getSimpleVT().SimpleTy) { + default: + llvm_unreachable("Unexpected register type"); + case MVT::i32: + case MVT::i64: + RC = &RISCV::GPRRegClass; + break; + case MVT::f32: + RC = &RISCV::FPR32RegClass; + break; + case MVT::f64: + RC = &RISCV::FPR64RegClass; + break; + } - unsigned VReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); + unsigned VReg = RegInfo.createVirtualRegister(RC); RegInfo.addLiveIn(VA.getLocReg(), VReg); Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); @@ -1014,6 +1693,10 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, case CCValAssign::Full: break; case CCValAssign::BCvt: + if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) { + Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Val); + break; + } Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); break; } @@ -1040,6 +1723,7 @@ static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, llvm_unreachable("Unexpected CCValAssign::LocInfo"); case CCValAssign::Full: case CCValAssign::Indirect: + case CCValAssign::BCvt: ExtType = ISD::NON_EXTLOAD; break; } @@ -1227,12 +1911,12 @@ SDValue RISCVTargetLowering::LowerFormalArguments( return Chain; } -/// IsEligibleForTailCallOptimization - Check whether the call is eligible +/// isEligibleForTailCallOptimization - Check whether the call is eligible /// for tail call optimization. /// Note: This is modelled after ARM's IsEligibleForTailCallOptimization. -bool RISCVTargetLowering::IsEligibleForTailCallOptimization( - CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, - const SmallVector<CCValAssign, 16> &ArgLocs) const { +bool RISCVTargetLowering::isEligibleForTailCallOptimization( + CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, + const SmallVector<CCValAssign, 16> &ArgLocs) const { auto &Callee = CLI.Callee; auto CalleeCC = CLI.CallConv; @@ -1335,8 +2019,7 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, // Check if it's really possible to do a tail call. if (IsTailCall) - IsTailCall = IsEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, - ArgLocs); + IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs); if (IsTailCall) ++NumTailCalls; @@ -1482,9 +2165,21 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) { - Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, 0); + const GlobalValue *GV = S->getGlobal(); + + unsigned OpFlags = RISCVII::MO_CALL; + if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) + OpFlags = RISCVII::MO_PLT; + + Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, 0); + unsigned OpFlags = RISCVII::MO_CALL; + + if (!getTargetMachine().shouldAssumeDSOLocal(*MF.getFunction().getParent(), + nullptr)) + OpFlags = RISCVII::MO_PLT; + + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); } // The first call operand is the chain and the second is the target address. @@ -1567,8 +2262,9 @@ bool RISCVTargetLowering::CanLowerReturn( for (unsigned i = 0, e = Outs.size(); i != e; ++i) { MVT VT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; - if (CC_RISCV(MF.getDataLayout(), i, VT, VT, CCValAssign::Full, ArgFlags, - CCInfo, /*IsFixed=*/true, /*IsRet=*/true, nullptr)) + RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI(); + if (CC_RISCV(MF.getDataLayout(), ABI, i, VT, VT, CCValAssign::Full, + ArgFlags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, nullptr)) return false; } return true; @@ -1679,6 +2375,24 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { return "RISCVISD::SplitF64"; case RISCVISD::TAIL: return "RISCVISD::TAIL"; + case RISCVISD::SLLW: + return "RISCVISD::SLLW"; + case RISCVISD::SRAW: + return "RISCVISD::SRAW"; + case RISCVISD::SRLW: + return "RISCVISD::SRLW"; + case RISCVISD::DIVW: + return "RISCVISD::DIVW"; + case RISCVISD::DIVUW: + return "RISCVISD::DIVUW"; + case RISCVISD::REMUW: + return "RISCVISD::REMUW"; + case RISCVISD::FMV_W_X_RV64: + return "RISCVISD::FMV_W_X_RV64"; + case RISCVISD::FMV_X_ANYEXTW_RV64: + return "RISCVISD::FMV_X_ANYEXTW_RV64"; + case RISCVISD::READ_CYCLE_WIDE: + return "RISCVISD::READ_CYCLE_WIDE"; } return nullptr; } @@ -1701,6 +2415,44 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } +void RISCVTargetLowering::LowerAsmOperandForConstraint( + SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, + SelectionDAG &DAG) const { + // Currently only support length 1 constraints. + if (Constraint.length() == 1) { + switch (Constraint[0]) { + case 'I': + // Validate & create a 12-bit signed immediate operand. + if (auto *C = dyn_cast<ConstantSDNode>(Op)) { + uint64_t CVal = C->getSExtValue(); + if (isInt<12>(CVal)) + Ops.push_back( + DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); + } + return; + case 'J': + // Validate & create an integer zero operand. + if (auto *C = dyn_cast<ConstantSDNode>(Op)) + if (C->getZExtValue() == 0) + Ops.push_back( + DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getXLenVT())); + return; + case 'K': + // Validate & create a 5-bit unsigned immediate operand. + if (auto *C = dyn_cast<ConstantSDNode>(Op)) { + uint64_t CVal = C->getZExtValue(); + if (isUInt<5>(CVal)) + Ops.push_back( + DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); + } + return; + default: + break; + } + } + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + Instruction *RISCVTargetLowering::emitLeadingFence(IRBuilder<> &Builder, Instruction *Inst, AtomicOrdering Ord) const { @@ -1721,6 +2473,12 @@ Instruction *RISCVTargetLowering::emitTrailingFence(IRBuilder<> &Builder, TargetLowering::AtomicExpansionKind RISCVTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { + // atomicrmw {fadd,fsub} must be expanded to use compare-exchange, as floating + // point operations can't be used in an lr/sc sequence without breaking the + // forward-progress guarantee. + if (AI->isFloatingPointOperation()) + return AtomicExpansionKind::CmpXChg; + unsigned Size = AI->getType()->getPrimitiveSizeInBits(); if (Size == 8 || Size == 16) return AtomicExpansionKind::MaskedIntrinsic; @@ -1728,37 +2486,74 @@ RISCVTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { } static Intrinsic::ID -getIntrinsicForMaskedAtomicRMWBinOp32(AtomicRMWInst::BinOp BinOp) { - switch (BinOp) { - default: - llvm_unreachable("Unexpected AtomicRMW BinOp"); - case AtomicRMWInst::Xchg: - return Intrinsic::riscv_masked_atomicrmw_xchg_i32; - case AtomicRMWInst::Add: - return Intrinsic::riscv_masked_atomicrmw_add_i32; - case AtomicRMWInst::Sub: - return Intrinsic::riscv_masked_atomicrmw_sub_i32; - case AtomicRMWInst::Nand: - return Intrinsic::riscv_masked_atomicrmw_nand_i32; - case AtomicRMWInst::Max: - return Intrinsic::riscv_masked_atomicrmw_max_i32; - case AtomicRMWInst::Min: - return Intrinsic::riscv_masked_atomicrmw_min_i32; - case AtomicRMWInst::UMax: - return Intrinsic::riscv_masked_atomicrmw_umax_i32; - case AtomicRMWInst::UMin: - return Intrinsic::riscv_masked_atomicrmw_umin_i32; +getIntrinsicForMaskedAtomicRMWBinOp(unsigned XLen, AtomicRMWInst::BinOp BinOp) { + if (XLen == 32) { + switch (BinOp) { + default: + llvm_unreachable("Unexpected AtomicRMW BinOp"); + case AtomicRMWInst::Xchg: + return Intrinsic::riscv_masked_atomicrmw_xchg_i32; + case AtomicRMWInst::Add: + return Intrinsic::riscv_masked_atomicrmw_add_i32; + case AtomicRMWInst::Sub: + return Intrinsic::riscv_masked_atomicrmw_sub_i32; + case AtomicRMWInst::Nand: + return Intrinsic::riscv_masked_atomicrmw_nand_i32; + case AtomicRMWInst::Max: + return Intrinsic::riscv_masked_atomicrmw_max_i32; + case AtomicRMWInst::Min: + return Intrinsic::riscv_masked_atomicrmw_min_i32; + case AtomicRMWInst::UMax: + return Intrinsic::riscv_masked_atomicrmw_umax_i32; + case AtomicRMWInst::UMin: + return Intrinsic::riscv_masked_atomicrmw_umin_i32; + } } + + if (XLen == 64) { + switch (BinOp) { + default: + llvm_unreachable("Unexpected AtomicRMW BinOp"); + case AtomicRMWInst::Xchg: + return Intrinsic::riscv_masked_atomicrmw_xchg_i64; + case AtomicRMWInst::Add: + return Intrinsic::riscv_masked_atomicrmw_add_i64; + case AtomicRMWInst::Sub: + return Intrinsic::riscv_masked_atomicrmw_sub_i64; + case AtomicRMWInst::Nand: + return Intrinsic::riscv_masked_atomicrmw_nand_i64; + case AtomicRMWInst::Max: + return Intrinsic::riscv_masked_atomicrmw_max_i64; + case AtomicRMWInst::Min: + return Intrinsic::riscv_masked_atomicrmw_min_i64; + case AtomicRMWInst::UMax: + return Intrinsic::riscv_masked_atomicrmw_umax_i64; + case AtomicRMWInst::UMin: + return Intrinsic::riscv_masked_atomicrmw_umin_i64; + } + } + + llvm_unreachable("Unexpected XLen\n"); } Value *RISCVTargetLowering::emitMaskedAtomicRMWIntrinsic( IRBuilder<> &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const { - Value *Ordering = Builder.getInt32(static_cast<uint32_t>(AI->getOrdering())); + unsigned XLen = Subtarget.getXLen(); + Value *Ordering = + Builder.getIntN(XLen, static_cast<uint64_t>(AI->getOrdering())); Type *Tys[] = {AlignedAddr->getType()}; Function *LrwOpScwLoop = Intrinsic::getDeclaration( AI->getModule(), - getIntrinsicForMaskedAtomicRMWBinOp32(AI->getOperation()), Tys); + getIntrinsicForMaskedAtomicRMWBinOp(XLen, AI->getOperation()), Tys); + + if (XLen == 64) { + Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty()); + Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); + ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty()); + } + + Value *Result; // Must pass the shift amount needed to sign extend the loaded value prior // to performing a signed comparison for min/max. ShiftAmt is the number of @@ -1770,13 +2565,18 @@ Value *RISCVTargetLowering::emitMaskedAtomicRMWIntrinsic( const DataLayout &DL = AI->getModule()->getDataLayout(); unsigned ValWidth = DL.getTypeStoreSizeInBits(AI->getValOperand()->getType()); - Value *SextShamt = Builder.CreateSub( - Builder.getInt32(Subtarget.getXLen() - ValWidth), ShiftAmt); - return Builder.CreateCall(LrwOpScwLoop, - {AlignedAddr, Incr, Mask, SextShamt, Ordering}); + Value *SextShamt = + Builder.CreateSub(Builder.getIntN(XLen, XLen - ValWidth), ShiftAmt); + Result = Builder.CreateCall(LrwOpScwLoop, + {AlignedAddr, Incr, Mask, SextShamt, Ordering}); + } else { + Result = + Builder.CreateCall(LrwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); } - return Builder.CreateCall(LrwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); + if (XLen == 64) + Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); + return Result; } TargetLowering::AtomicExpansionKind @@ -1791,10 +2591,31 @@ RISCVTargetLowering::shouldExpandAtomicCmpXchgInIR( Value *RISCVTargetLowering::emitMaskedAtomicCmpXchgIntrinsic( IRBuilder<> &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const { - Value *Ordering = Builder.getInt32(static_cast<uint32_t>(Ord)); + unsigned XLen = Subtarget.getXLen(); + Value *Ordering = Builder.getIntN(XLen, static_cast<uint64_t>(Ord)); + Intrinsic::ID CmpXchgIntrID = Intrinsic::riscv_masked_cmpxchg_i32; + if (XLen == 64) { + CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty()); + NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty()); + Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); + CmpXchgIntrID = Intrinsic::riscv_masked_cmpxchg_i64; + } Type *Tys[] = {AlignedAddr->getType()}; - Function *MaskedCmpXchg = Intrinsic::getDeclaration( - CI->getModule(), Intrinsic::riscv_masked_cmpxchg_i32, Tys); - return Builder.CreateCall(MaskedCmpXchg, - {AlignedAddr, CmpVal, NewVal, Mask, Ordering}); + Function *MaskedCmpXchg = + Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys); + Value *Result = Builder.CreateCall( + MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering}); + if (XLen == 64) + Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); + return Result; +} + +unsigned RISCVTargetLowering::getExceptionPointerRegister( + const Constant *PersonalityFn) const { + return RISCV::X10; +} + +unsigned RISCVTargetLowering::getExceptionSelectorRegister( + const Constant *PersonalityFn) const { + return RISCV::X11; } diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h index 6970900bb0622..17db03bbb69e3 100644 --- a/lib/Target/RISCV/RISCVISelLowering.h +++ b/lib/Target/RISCV/RISCVISelLowering.h @@ -1,9 +1,8 @@ //===-- RISCVISelLowering.h - RISCV DAG Lowering Interface ------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -32,7 +31,27 @@ enum NodeType : unsigned { SELECT_CC, BuildPairF64, SplitF64, - TAIL + TAIL, + // RV64I shifts, directly matching the semantics of the named RISC-V + // instructions. + SLLW, + SRAW, + SRLW, + // 32-bit operations from RV64M that can't be simply matched with a pattern + // at instruction selection time. + DIVW, + DIVUW, + REMUW, + // FPR32<->GPR transfer operations for RV64. Needed as an i32<->f32 bitcast + // is not legal on RV64. FMV_W_X_RV64 matches the semantics of the FMV.W.X. + // FMV_X_ANYEXTW_RV64 is similar to FMV.X.W but has an any-extended result. + // This is a more convenient semantic for producing dagcombines that remove + // unnecessary GPR->FPR->GPR moves. + FMV_W_X_RV64, + FMV_X_ANYEXTW_RV64, + // READ_CYCLE_WIDE - A read of the 64-bit cycle CSR on a 32-bit target + // (returns (Lo, Hi)). It takes a chain operand. + READ_CYCLE_WIDE }; } @@ -56,11 +75,20 @@ public: bool isZExtFree(SDValue Val, EVT VT2) const override; bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override; + bool hasBitPreservingFPLogic(EVT VT) const override; + // Provide custom lowering hooks for some operations. SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const override; SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + unsigned ComputeNumSignBitsForTargetNode(SDValue Op, + const APInt &DemandedElts, + const SelectionDAG &DAG, + unsigned Depth) const override; + // This method returns the name of a target specific DAG node. const char *getTargetNodeName(unsigned Opcode) const override; @@ -68,6 +96,10 @@ public: getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; + void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const override; + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const override; @@ -75,6 +107,10 @@ public: EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override; + bool convertSetCCLogicToBitwiseLogic(EVT VT) const override { + return VT.isScalarInteger(); + } + bool shouldInsertFencesForAtomic(const Instruction *I) const override { return isa<LoadInst>(I) || isa<StoreInst>(I); } @@ -83,6 +119,28 @@ public: Instruction *emitTrailingFence(IRBuilder<> &Builder, Instruction *Inst, AtomicOrdering Ord) const override; + ISD::NodeType getExtendForAtomicOps() const override { + return ISD::SIGN_EXTEND; + } + + bool shouldExpandShift(SelectionDAG &DAG, SDNode *N) const override { + if (DAG.getMachineFunction().getFunction().hasMinSize()) + return false; + return true; + } + bool isDesirableToCommuteWithShift(const SDNode *N, + CombineLevel Level) const override; + + /// If a physical register, this returns the register that receives the + /// exception address on entry to an EH pad. + unsigned + getExceptionPointerRegister(const Constant *PersonalityFn) const override; + + /// If a physical register, this returns the register that receives the + /// exception typeid on entry to a landing pad. + unsigned + getExceptionSelectorRegister(const Constant *PersonalityFn) const override; + private: void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins, @@ -110,17 +168,29 @@ private: Type *Ty) const override { return true; } + + template <class NodeTy> + SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const; + + SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, + bool UseGOT) const; + SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const; + + bool shouldConsiderGEPOffsetSplit() const override { return true; } SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; - bool IsEligibleForTailCallOptimization(CCState &CCInfo, - CallLoweringInfo &CLI, MachineFunction &MF, - const SmallVector<CCValAssign, 16> &ArgLocs) const; + bool isEligibleForTailCallOptimization( + CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, + const SmallVector<CCValAssign, 16> &ArgLocs) const; TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const override; diff --git a/lib/Target/RISCV/RISCVInstrFormats.td b/lib/Target/RISCV/RISCVInstrFormats.td index ebd676a6056ef..7229ebfe1db09 100644 --- a/lib/Target/RISCV/RISCVInstrFormats.td +++ b/lib/Target/RISCV/RISCVInstrFormats.td @@ -1,9 +1,8 @@ //===-- RISCVInstrFormats.td - RISCV Instruction Formats ---*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -109,6 +108,35 @@ class Pseudo<dag outs, dag ins, list<dag> pattern, string opcodestr = "", string let isCodeGenOnly = 1; } +// Pseudo load instructions. +class PseudoLoad<string opcodestr, RegisterClass rdty = GPR> + : Pseudo<(outs rdty:$rd), (ins bare_symbol:$addr), [], opcodestr, "$rd, $addr"> { + let hasSideEffects = 0; + let mayLoad = 1; + let mayStore = 0; + let isCodeGenOnly = 0; + let isAsmParserOnly = 1; +} + +class PseudoFloatLoad<string opcodestr, RegisterClass rdty = GPR> + : Pseudo<(outs rdty:$rd, GPR:$tmp), (ins bare_symbol:$addr), [], opcodestr, "$rd, $addr, $tmp"> { + let hasSideEffects = 0; + let mayLoad = 1; + let mayStore = 0; + let isCodeGenOnly = 0; + let isAsmParserOnly = 1; +} + +// Pseudo store instructions. +class PseudoStore<string opcodestr, RegisterClass rsty = GPR> + : Pseudo<(outs rsty:$rs, GPR:$tmp), (ins bare_symbol:$addr), [], opcodestr, "$rs, $addr, $tmp"> { + let hasSideEffects = 0; + let mayLoad = 0; + let mayStore = 1; + let isCodeGenOnly = 0; + let isAsmParserOnly = 1; +} + // Instruction formats are listed in the order they appear in the RISC-V // instruction set manual (R, I, S, B, U, J) with sub-formats (e.g. RVInstR4, // RVInstRAtomic) sorted alphabetically. diff --git a/lib/Target/RISCV/RISCVInstrFormatsC.td b/lib/Target/RISCV/RISCVInstrFormatsC.td index bda8bbb558eb6..690bec5181e2a 100644 --- a/lib/Target/RISCV/RISCVInstrFormatsC.td +++ b/lib/Target/RISCV/RISCVInstrFormatsC.td @@ -1,9 +1,8 @@ //===-- RISCVInstrFormatsC.td - RISCV C Instruction Formats --*- tablegen -*-=// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/RISCVInstrInfo.cpp b/lib/Target/RISCV/RISCVInstrInfo.cpp index 76c74368ca111..99c8d2ef73de5 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1,9 +1,8 @@ //===-- RISCVInstrInfo.cpp - RISCV Instruction Information ------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -291,9 +290,9 @@ unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB, return 0; // Remove the branch. - I->eraseFromParent(); if (BytesRemoved) *BytesRemoved += getInstSizeInBytes(*I); + I->eraseFromParent(); I = MBB.end(); @@ -304,9 +303,9 @@ unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB, return 1; // Remove the branch. - I->eraseFromParent(); if (BytesRemoved) *BytesRemoved += getInstSizeInBytes(*I); + I->eraseFromParent(); return 2; } @@ -383,8 +382,8 @@ unsigned RISCVInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, .addMBB(&DestBB, RISCVII::MO_LO); RS->enterBasicBlockEnd(MBB); - unsigned Scav = RS->scavengeRegisterBackwards( - RISCV::GPRRegClass, MachineBasicBlock::iterator(LuiMI), false, 0); + unsigned Scav = RS->scavengeRegisterBackwards(RISCV::GPRRegClass, + LuiMI.getIterator(), false, 0); MRI.replaceRegWith(ScratchReg, Scav); MRI.clearVirtRegs(); RS->setRegUsed(Scav); @@ -437,10 +436,16 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { case TargetOpcode::KILL: case TargetOpcode::DBG_VALUE: return 0; + case RISCV::PseudoCALLReg: case RISCV::PseudoCALL: case RISCV::PseudoTAIL: + case RISCV::PseudoLLA: + case RISCV::PseudoLA: + case RISCV::PseudoLA_TLS_IE: + case RISCV::PseudoLA_TLS_GD: return 8; - case TargetOpcode::INLINEASM: { + case TargetOpcode::INLINEASM: + case TargetOpcode::INLINEASM_BR: { const MachineFunction &MF = *MI.getParent()->getParent(); const auto &TM = static_cast<const RISCVTargetMachine &>(MF.getTarget()); return getInlineAsmLength(MI.getOperand(0).getSymbolName(), @@ -448,3 +453,16 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { } } } + +bool RISCVInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const { + const unsigned Opcode = MI.getOpcode(); + switch(Opcode) { + default: + break; + case RISCV::ADDI: + case RISCV::ORI: + case RISCV::XORI: + return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0); + } + return MI.isAsCheapAsAMove(); +} diff --git a/lib/Target/RISCV/RISCVInstrInfo.h b/lib/Target/RISCV/RISCVInstrInfo.h index 1d3279c3d31e7..ff098e660d191 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.h +++ b/lib/Target/RISCV/RISCVInstrInfo.h @@ -1,9 +1,8 @@ //===-- RISCVInstrInfo.h - RISCV Instruction Information --------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -79,6 +78,8 @@ public: bool isBranchOffsetInRange(unsigned BranchOpc, int64_t BrOffset) const override; + + bool isAsCheapAsAMove(const MachineInstr &MI) const override; }; } #endif diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td index d7cc13d4fabd7..69bde15f12187 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.td +++ b/lib/Target/RISCV/RISCVInstrInfo.td @@ -1,9 +1,8 @@ //===-- RISCVInstrInfo.td - Target Description for RISCV ---*- tablegen -*-===// // -// 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,42 +10,48 @@ // //===----------------------------------------------------------------------===// -include "RISCVInstrFormats.td" - //===----------------------------------------------------------------------===// // RISC-V specific DAG Nodes. //===----------------------------------------------------------------------===// -def SDT_RISCVCall : SDTypeProfile<0, -1, [SDTCisVT<0, XLenVT>]>; -def SDT_RISCVCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, - SDTCisVT<1, i32>]>; -def SDT_RISCVCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, - SDTCisVT<1, i32>]>; -def SDT_RISCVSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, - SDTCisSameAs<0, 4>, - SDTCisSameAs<4, 5>]>; +// Target-independent type requirements, but with target-specific formats. +def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; +def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; + +// Target-dependent type requirements. +def SDT_RISCVCall : SDTypeProfile<0, -1, [SDTCisVT<0, XLenVT>]>; +def SDT_RISCVSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, + SDTCisSameAs<0, 4>, + SDTCisSameAs<4, 5>]>; +// Target-independent nodes, but with target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; -def Call : SDNode<"RISCVISD::CALL", SDT_RISCVCall, - [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, - SDNPVariadic]>; -def CallSeqStart : SDNode<"ISD::CALLSEQ_START", SDT_RISCVCallSeqStart, - [SDNPHasChain, SDNPOutGlue]>; -def CallSeqEnd : SDNode<"ISD::CALLSEQ_END", SDT_RISCVCallSeqEnd, - [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; -def RetFlag : SDNode<"RISCVISD::RET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; -def URetFlag : SDNode<"RISCVISD::URET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInGlue]>; -def SRetFlag : SDNode<"RISCVISD::SRET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInGlue]>; -def MRetFlag : SDNode<"RISCVISD::MRET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInGlue]>; -def SelectCC : SDNode<"RISCVISD::SELECT_CC", SDT_RISCVSelectCC, - [SDNPInGlue]>; -def Tail : SDNode<"RISCVISD::TAIL", SDT_RISCVCall, - [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, - SDNPVariadic]>; +// Target-dependent nodes. +def riscv_call : SDNode<"RISCVISD::CALL", SDT_RISCVCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def riscv_ret_flag : SDNode<"RISCVISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def riscv_uret_flag : SDNode<"RISCVISD::URET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue]>; +def riscv_sret_flag : SDNode<"RISCVISD::SRET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue]>; +def riscv_mret_flag : SDNode<"RISCVISD::MRET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue]>; +def riscv_selectcc : SDNode<"RISCVISD::SELECT_CC", SDT_RISCVSelectCC, + [SDNPInGlue]>; +def riscv_tail : SDNode<"RISCVISD::TAIL", SDT_RISCVCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def riscv_sllw : SDNode<"RISCVISD::SLLW", SDTIntShiftOp>; +def riscv_sraw : SDNode<"RISCVISD::SRAW", SDTIntShiftOp>; +def riscv_srlw : SDNode<"RISCVISD::SRLW", SDTIntShiftOp>; //===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. @@ -185,6 +190,30 @@ def bare_symbol : Operand<XLenVT> { let ParserMatchClass = BareSymbol; } +def CallSymbol : AsmOperandClass { + let Name = "CallSymbol"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidCallSymbol"; + let ParserMethod = "parseCallSymbol"; +} + +// A bare symbol used in call/tail only. +def call_symbol : Operand<XLenVT> { + let ParserMatchClass = CallSymbol; +} + +def TPRelAddSymbol : AsmOperandClass { + let Name = "TPRelAddSymbol"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidTPRelAddSymbol"; + let ParserMethod = "parseOperandWithModifier"; +} + +// A bare symbol with the %tprel_add variant. +def tprel_add_symbol : Operand<XLenVT> { + let ParserMatchClass = TPRelAddSymbol; +} + def CSRSystemRegister : AsmOperandClass { let Name = "CSRSystemRegister"; let ParserMethod = "parseCSRSystemRegister"; @@ -234,6 +263,12 @@ def HI20 : SDNodeXForm<imm, [{ }]>; //===----------------------------------------------------------------------===// +// Instruction Formats +//===----------------------------------------------------------------------===// + +include "RISCVInstrFormats.td" + +//===----------------------------------------------------------------------===// // Instruction Class Templates //===----------------------------------------------------------------------===// @@ -307,7 +342,8 @@ class Priv<string opcodestr, bits<7> funct7> // Instructions //===----------------------------------------------------------------------===// -let hasSideEffects = 0, isReMaterializable = 1, mayLoad = 0, mayStore = 0 in { +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { +let isReMaterializable = 1, isAsCheapAsAMove = 1 in def LUI : RVInstU<OPC_LUI, (outs GPR:$rd), (ins uimm20_lui:$imm20), "lui", "$rd, $imm20">; @@ -321,7 +357,7 @@ def JAL : RVInstJ<OPC_JAL, (outs GPR:$rd), (ins simm21_lsb0_jal:$imm20), let isCall = 1 in def JALR : RVInstI<0b000, OPC_JALR, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), - "jalr", "$rd, $rs1, $imm12">; + "jalr", "$rd, ${imm12}(${rs1})">; } // hasSideEffects = 0, mayLoad = 0, mayStore = 0 def BEQ : BranchCC_rri<0b000, "beq">; @@ -343,13 +379,17 @@ def SW : Store_rri<0b010, "sw">; // ADDI isn't always rematerializable, but isReMaterializable will be used as // a hint which is verified in isReallyTriviallyReMaterializable. -let isReMaterializable = 1 in +let isReMaterializable = 1, isAsCheapAsAMove = 1 in def ADDI : ALU_ri<0b000, "addi">; def SLTI : ALU_ri<0b010, "slti">; def SLTIU : ALU_ri<0b011, "sltiu">; + +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { def XORI : ALU_ri<0b100, "xori">; def ORI : ALU_ri<0b110, "ori">; +} + def ANDI : ALU_ri<0b111, "andi">; def SLLI : Shift_ri<0, 0b001, "slli">; @@ -485,12 +525,6 @@ def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs), // Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) //===----------------------------------------------------------------------===// -// TODO la -// TODO lb lh lw -// TODO RV64I: ld -// TODO sb sh sw -// TODO RV64I: sd - def : InstAlias<"nop", (ADDI X0, X0, 0)>; // Note that the size is 32 because up to 8 32-bit instructions are needed to @@ -502,6 +536,22 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 32, def PseudoLI : Pseudo<(outs GPR:$rd), (ins ixlenimm_li:$imm), [], "li", "$rd, $imm">; +def PseudoLB : PseudoLoad<"lb">; +def PseudoLBU : PseudoLoad<"lbu">; +def PseudoLH : PseudoLoad<"lh">; +def PseudoLHU : PseudoLoad<"lhu">; +def PseudoLW : PseudoLoad<"lw">; + +def PseudoSB : PseudoStore<"sb">; +def PseudoSH : PseudoStore<"sh">; +def PseudoSW : PseudoStore<"sw">; + +let Predicates = [IsRV64] in { +def PseudoLWU : PseudoLoad<"lwu">; +def PseudoLD : PseudoLoad<"ld">; +def PseudoSD : PseudoStore<"sd">; +} // Predicates = [IsRV64] + def : InstAlias<"mv $rd, $rs", (ADDI GPR:$rd, GPR:$rs, 0)>; def : InstAlias<"not $rd, $rs", (XORI GPR:$rd, GPR:$rs, -1)>; def : InstAlias<"neg $rd, $rs", (SUB GPR:$rd, X0, GPR:$rs)>; @@ -547,27 +597,36 @@ def : InstAlias<"bgtu $rs, $rt, $offset", def : InstAlias<"bleu $rs, $rt, $offset", (BGEU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; -// "ret" has more weight since "ret" and "jr" alias the same "jalr" instruction. -def : InstAlias<"j $offset", (JAL X0, simm21_lsb0_jal:$offset)>; -def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0_jal:$offset)>; -def : InstAlias<"jr $rs", (JALR X0, GPR:$rs, 0)>; -def : InstAlias<"jalr $rs", (JALR X1, GPR:$rs, 0)>; -def : InstAlias<"ret", (JALR X0, X1, 0), 2>; +def : InstAlias<"j $offset", (JAL X0, simm21_lsb0_jal:$offset)>; +def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0_jal:$offset)>; + +// Non-zero offset aliases of "jalr" are the lowest weight, followed by the +// two-register form, then the one-register forms and finally "ret". +def : InstAlias<"jr $rs", (JALR X0, GPR:$rs, 0), 3>; +def : InstAlias<"jr ${offset}(${rs})", (JALR X0, GPR:$rs, simm12:$offset)>; +def : InstAlias<"jalr $rs", (JALR X1, GPR:$rs, 0), 3>; +def : InstAlias<"jalr ${offset}(${rs})", (JALR X1, GPR:$rs, simm12:$offset)>; +def : InstAlias<"jalr $rd, $rs", (JALR GPR:$rd, GPR:$rs, 0), 2>; +def : InstAlias<"ret", (JALR X0, X1, 0), 4>; + +// Non-canonical forms for jump targets also accepted by the assembler. +def : InstAlias<"jr $rs, $offset", (JALR X0, GPR:$rs, simm12:$offset), 0>; +def : InstAlias<"jalr $rs, $offset", (JALR X1, GPR:$rs, simm12:$offset), 0>; +def : InstAlias<"jalr $rd, $rs, $offset", (JALR GPR:$rd, GPR:$rs, simm12:$offset), 0>; + // TODO call // TODO tail def : InstAlias<"fence", (FENCE 0xF, 0xF)>; // 0xF == iorw -// CSR Addresses: 0xC00 == cycle, 0xC01 == time, 0xC02 == instret -// 0xC80 == cycleh, 0xC81 == timeh, 0xC82 == instreth -def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, 0xC02, X0)>; -def : InstAlias<"rdcycle $rd", (CSRRS GPR:$rd, 0xC00, X0)>; -def : InstAlias<"rdtime $rd", (CSRRS GPR:$rd, 0xC01, X0)>; +def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, INSTRET.Encoding, X0)>; +def : InstAlias<"rdcycle $rd", (CSRRS GPR:$rd, CYCLE.Encoding, X0)>; +def : InstAlias<"rdtime $rd", (CSRRS GPR:$rd, TIME.Encoding, X0)>; let Predicates = [IsRV32] in { -def : InstAlias<"rdinstreth $rd", (CSRRS GPR:$rd, 0xC82, X0)>; -def : InstAlias<"rdcycleh $rd", (CSRRS GPR:$rd, 0xC80, X0)>; -def : InstAlias<"rdtimeh $rd", (CSRRS GPR:$rd, 0xC81, X0)>; +def : InstAlias<"rdinstreth $rd", (CSRRS GPR:$rd, INSTRETH.Encoding, X0)>; +def : InstAlias<"rdcycleh $rd", (CSRRS GPR:$rd, CYCLEH.Encoding, X0)>; +def : InstAlias<"rdtimeh $rd", (CSRRS GPR:$rd, TIMEH.Encoding, X0)>; } // Predicates = [IsRV32] def : InstAlias<"csrr $rd, $csr", (CSRRS GPR:$rd, csr_sysreg:$csr, X0)>; @@ -593,6 +652,24 @@ def : InstAlias<"sfence.vma", (SFENCE_VMA X0, X0)>; def : InstAlias<"sfence.vma $rs", (SFENCE_VMA GPR:$rs, X0)>; let EmitPriority = 0 in { +def : InstAlias<"lb $rd, (${rs1})", + (LB GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"lh $rd, (${rs1})", + (LH GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"lw $rd, (${rs1})", + (LW GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"lbu $rd, (${rs1})", + (LBU GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"lhu $rd, (${rs1})", + (LHU GPR:$rd, GPR:$rs1, 0)>; + +def : InstAlias<"sb $rs2, (${rs1})", + (SB GPR:$rs2, GPR:$rs1, 0)>; +def : InstAlias<"sh $rs2, (${rs1})", + (SH GPR:$rs2, GPR:$rs1, 0)>; +def : InstAlias<"sw $rs2, (${rs1})", + (SW GPR:$rs2, GPR:$rs1, 0)>; + def : InstAlias<"add $rd, $rs1, $imm12", (ADDI GPR:$rd, GPR:$rs1, simm12:$imm12)>; def : InstAlias<"and $rd, $rs1, $imm12", @@ -608,6 +685,13 @@ def : InstAlias<"srl $rd, $rs1, $shamt", def : InstAlias<"sra $rd, $rs1, $shamt", (SRAI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>; let Predicates = [IsRV64] in { +def : InstAlias<"lwu $rd, (${rs1})", + (LWU GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"ld $rd, (${rs1})", + (LD GPR:$rd, GPR:$rs1, 0)>; +def : InstAlias<"sd $rs2, (${rs1})", + (SD GPR:$rs2, GPR:$rs1, 0)>; + def : InstAlias<"addw $rd, $rs1, $imm12", (ADDIW GPR:$rd, GPR:$rs1, simm12:$imm12)>; def : InstAlias<"sllw $rd, $rs1, $shamt", @@ -663,21 +747,9 @@ def sexti32 : PatFrags<(ops node:$src), def assertzexti32 : PatFrag<(ops node:$src), (assertzext node:$src), [{ return cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i32; }]>; -def assertzexti5 : PatFrag<(ops node:$src), (assertzext node:$src), [{ - return cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits() <= 5; -}]>; def zexti32 : PatFrags<(ops node:$src), [(and node:$src, 0xffffffff), (assertzexti32 node:$src)]>; -// Defines a legal mask for (assertzexti5 (and src, mask)) to be combinable -// with a shiftw operation. The mask mustn't modify the lower 5 bits or the -// upper 32 bits. -def shiftwamt_mask : ImmLeaf<XLenVT, [{ - return countTrailingOnes<uint64_t>(Imm) >= 5 && isUInt<32>(Imm); -}]>; -def shiftwamt : PatFrags<(ops node:$src), - [(assertzexti5 (and node:$src, shiftwamt_mask)), - (assertzexti5 node:$src)]>; /// Immediates @@ -714,6 +786,15 @@ def : PatGprGpr<shiftop<shl>, SLL>; def : PatGprGpr<shiftop<srl>, SRL>; def : PatGprGpr<shiftop<sra>, SRA>; +// This is a special case of the ADD instruction used to facilitate the use of a +// fourth operand to emit a relocation on a symbol relating to this instruction. +// The relocation does not affect any bits of the instruction itself but is used +// as a hint to the linker. +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in +def PseudoAddTPRel : Pseudo<(outs GPR:$rd), + (ins GPR:$rs1, GPR:$rs2, tprel_add_symbol:$src), [], + "add", "$rd, $rs1, $rs2, $src">; + /// FrameIndex calculations def : Pat<(add (i32 AddrFI:$Rs), simm12:$imm12), @@ -732,8 +813,12 @@ def : PatGprSimm12<setult, SLTIU>; // handled by a RISC-V instruction. def : Pat<(seteq GPR:$rs1, 0), (SLTIU GPR:$rs1, 1)>; def : Pat<(seteq GPR:$rs1, GPR:$rs2), (SLTIU (XOR GPR:$rs1, GPR:$rs2), 1)>; +def : Pat<(seteq GPR:$rs1, simm12:$imm12), + (SLTIU (XORI GPR:$rs1, simm12:$imm12), 1)>; def : Pat<(setne GPR:$rs1, 0), (SLTU X0, GPR:$rs1)>; def : Pat<(setne GPR:$rs1, GPR:$rs2), (SLTU X0, (XOR GPR:$rs1, GPR:$rs2))>; +def : Pat<(setne GPR:$rs1, simm12:$imm12), + (SLTU X0, (XORI GPR:$rs1, simm12:$imm12))>; def : Pat<(setugt GPR:$rs1, GPR:$rs2), (SLTU GPR:$rs2, GPR:$rs1)>; def : Pat<(setuge GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs1, GPR:$rs2), 1)>; def : Pat<(setule GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs2, GPR:$rs1), 1)>; @@ -746,7 +831,7 @@ class SelectCC_rrirr<RegisterClass valty, RegisterClass cmpty> : Pseudo<(outs valty:$dst), (ins cmpty:$lhs, cmpty:$rhs, ixlenimm:$imm, valty:$truev, valty:$falsev), - [(set valty:$dst, (SelectCC cmpty:$lhs, cmpty:$rhs, + [(set valty:$dst, (riscv_selectcc cmpty:$lhs, cmpty:$rhs, (XLenVT imm:$imm), valty:$truev, valty:$falsev))]>; def Select_GPR_Using_CC_GPR : SelectCC_rrirr<GPR, GPR>; @@ -794,6 +879,17 @@ def : Pat<(brind GPR:$rs1), (PseudoBRIND GPR:$rs1, 0)>; def : Pat<(brind (add GPR:$rs1, simm12:$imm12)), (PseudoBRIND GPR:$rs1, simm12:$imm12)>; +// PsuedoCALLReg is a generic pseudo instruction for calls which will eventually +// expand to auipc and jalr while encoding, with any given register used as the +// destination. +// Define AsmString to print "call" when compile with -S flag. +// Define isCodeGenOnly = 0 to support parsing assembly "call" instruction. +let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, hasSideEffects = 0, + mayStore = 0, mayLoad = 0 in +def PseudoCALLReg : Pseudo<(outs GPR:$rd), (ins call_symbol:$func), []> { + let AsmString = "call\t$rd, $func"; +} + // PseudoCALL is a pseudo instruction which will eventually expand to auipc // and jalr while encoding. This is desirable, as an auipc+jalr pair with // R_RISCV_CALL and R_RISCV_RELAX relocations can be be relaxed by the linker @@ -801,23 +897,24 @@ def : Pat<(brind (add GPR:$rs1, simm12:$imm12)), // Define AsmString to print "call" when compile with -S flag. // Define isCodeGenOnly = 0 to support parsing assembly "call" instruction. let isCall = 1, Defs = [X1], isCodeGenOnly = 0 in -def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func), - [(Call tglobaladdr:$func)]> { +def PseudoCALL : Pseudo<(outs), (ins call_symbol:$func), []> { let AsmString = "call\t$func"; } -def : Pat<(Call texternalsym:$func), (PseudoCALL texternalsym:$func)>; +def : Pat<(riscv_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>; +def : Pat<(riscv_call texternalsym:$func), (PseudoCALL texternalsym:$func)>; -def : Pat<(URetFlag), (URET X0, X0)>; -def : Pat<(SRetFlag), (SRET X0, X0)>; -def : Pat<(MRetFlag), (MRET X0, X0)>; +def : Pat<(riscv_uret_flag), (URET X0, X0)>; +def : Pat<(riscv_sret_flag), (SRET X0, X0)>; +def : Pat<(riscv_mret_flag), (MRET X0, X0)>; let isCall = 1, Defs = [X1] in -def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rs1), [(Call GPR:$rs1)]>, +def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rs1), + [(riscv_call GPR:$rs1)]>, PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; let isBarrier = 1, isReturn = 1, isTerminator = 1 in -def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>, +def PseudoRET : Pseudo<(outs), (ins), [(riscv_ret_flag)]>, PseudoInstExpansion<(JALR X0, X1, 0)>; // PseudoTAIL is a pseudo instruction similar to PseudoCALL and will eventually @@ -825,17 +922,18 @@ def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>, // Define AsmString to print "tail" when compile with -S flag. let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2], isCodeGenOnly = 0 in -def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst), []> { +def PseudoTAIL : Pseudo<(outs), (ins call_symbol:$dst), []> { let AsmString = "tail\t$dst"; } let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2] in -def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1), [(Tail GPRTC:$rs1)]>, +def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1), + [(riscv_tail GPRTC:$rs1)]>, PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>; -def : Pat<(Tail (iPTR tglobaladdr:$dst)), +def : Pat<(riscv_tail (iPTR tglobaladdr:$dst)), (PseudoTAIL texternalsym:$dst)>; -def : Pat<(Tail (iPTR texternalsym:$dst)), +def : Pat<(riscv_tail (iPTR texternalsym:$dst)), (PseudoTAIL texternalsym:$dst)>; let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0, @@ -843,6 +941,21 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0, def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], "lla", "$dst, $src">; +let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0, + isAsmParserOnly = 1 in +def PseudoLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], + "la", "$dst, $src">; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0, + isAsmParserOnly = 1 in +def PseudoLA_TLS_IE : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], + "la.tls.ie", "$dst, $src">; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0, + isAsmParserOnly = 1 in +def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], + "la.tls.gd", "$dst, $src">; + /// Loads multiclass LdPat<PatFrag LoadOp, RVInst Inst> { @@ -906,9 +1019,9 @@ def : Pat<(atomic_fence (XLenVT 7), (imm)), (FENCE 0b11, 0b11)>; // Pessimistically assume the stack pointer will be clobbered let Defs = [X2], Uses = [X2] in { def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), - [(CallSeqStart timm:$amt1, timm:$amt2)]>; + [(callseq_start timm:$amt1, timm:$amt2)]>; def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), - [(CallSeqEnd timm:$amt1, timm:$amt2)]>; + [(callseq_end timm:$amt1, timm:$amt2)]>; } // Defs = [X2], Uses = [X2] /// RV64 patterns @@ -935,28 +1048,9 @@ def : Pat<(sext_inreg (shl GPR:$rs1, uimm5:$shamt), i32), def : Pat<(sra (sext_inreg GPR:$rs1, i32), uimm5:$shamt), (SRAIW GPR:$rs1, uimm5:$shamt)>; -// For variable-length shifts, we rely on assertzexti5 being inserted during -// lowering (see RISCVTargetLowering::PerformDAGCombine). This enables us to -// guarantee that selecting a 32-bit variable shift is legal (as the variable -// shift is known to be <= 32). We must also be careful not to create -// semantically incorrect patterns. For instance, selecting SRLW for -// (srl (zexti32 GPR:$rs1), (shiftwamt GPR:$rs2)), -// is not guaranteed to be safe, as we don't know whether the upper 32-bits of -// the result are used or not (in the case where rs2=0, this is a -// sign-extension operation). - -def : Pat<(sext_inreg (shl GPR:$rs1, (shiftwamt GPR:$rs2)), i32), - (SLLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(zexti32 (shl GPR:$rs1, (shiftwamt GPR:$rs2))), - (SRLI (SLLI (SLLW GPR:$rs1, GPR:$rs2), 32), 32)>; - -def : Pat<(sext_inreg (srl (zexti32 GPR:$rs1), (shiftwamt GPR:$rs2)), i32), - (SRLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(zexti32 (srl (zexti32 GPR:$rs1), (shiftwamt GPR:$rs2))), - (SRLI (SLLI (SRLW GPR:$rs1, GPR:$rs2), 32), 32)>; - -def : Pat<(sra (sexti32 GPR:$rs1), (shiftwamt GPR:$rs2)), - (SRAW GPR:$rs1, GPR:$rs2)>; +def : PatGprGpr<riscv_sllw, SLLW>; +def : PatGprGpr<riscv_srlw, SRLW>; +def : PatGprGpr<riscv_sraw, SRAW>; /// Loads @@ -971,6 +1065,16 @@ defm : StPat<truncstorei32, SW, GPR>; defm : StPat<store, SD, GPR>; } // Predicates = [IsRV64] +/// readcyclecounter +// On RV64, we can directly read the 64-bit "cycle" CSR. +let Predicates = [IsRV64] in +def : Pat<(readcyclecounter), (CSRRS CYCLE.Encoding, X0)>; +// On RV32, ReadCycleWide will be expanded to the suggested loop reading both +// halves of the 64-bit "cycle" CSR. +let Predicates = [IsRV32], usesCustomInserter = 1, hasSideEffects = 0, +mayLoad = 0, mayStore = 0, hasNoSchedulingInfo = 1 in +def ReadCycleWide : Pseudo<(outs GPR:$lo, GPR:$hi), (ins), [], "", "">; + //===----------------------------------------------------------------------===// // Standard extensions //===----------------------------------------------------------------------===// diff --git a/lib/Target/RISCV/RISCVInstrInfoA.td b/lib/Target/RISCV/RISCVInstrInfoA.td index 9cb1d2f0b627d..b768c9347b385 100644 --- a/lib/Target/RISCV/RISCVInstrInfoA.td +++ b/lib/Target/RISCV/RISCVInstrInfoA.td @@ -1,9 +1,8 @@ //===-- RISCVInstrInfoA.td - RISC-V 'A' instructions -------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -85,7 +84,7 @@ defm AMOMIN_D : AMO_rr_aq_rl<0b10000, 0b011, "amomin.d">; defm AMOMAX_D : AMO_rr_aq_rl<0b10100, 0b011, "amomax.d">; defm AMOMINU_D : AMO_rr_aq_rl<0b11000, 0b011, "amominu.d">; defm AMOMAXU_D : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">; -} // Predicates = [HasStedExtA, IsRV64] +} // Predicates = [HasStdExtA, IsRV64] //===----------------------------------------------------------------------===// // Pseudo-instructions and codegen patterns @@ -235,7 +234,7 @@ def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i32, class PseudoCmpXchg : Pseudo<(outs GPR:$res, GPR:$scratch), - (ins GPR:$addr, GPR:$cmpval, GPR:$newval, i32imm:$ordering), []> { + (ins GPR:$addr, GPR:$cmpval, GPR:$newval, ixlenimm:$ordering), []> { let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; let mayLoad = 1; let mayStore = 1; @@ -263,7 +262,7 @@ defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>; def PseudoMaskedCmpXchg32 : Pseudo<(outs GPR:$res, GPR:$scratch), (ins GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, - i32imm:$ordering), []> { + ixlenimm:$ordering), []> { let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; let mayLoad = 1; let mayStore = 1; @@ -276,3 +275,79 @@ def : Pat<(int_riscv_masked_cmpxchg_i32 GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, imm:$ordering)>; } // Predicates = [HasStdExtA] + +let Predicates = [HasStdExtA, IsRV64] in { + +/// 64-bit atomic loads and stores + +// Fences will be inserted for atomic load/stores according to the logic in +// RISCVTargetLowering::{emitLeadingFence,emitTrailingFence}. +defm : LdPat<atomic_load_64, LD>; +defm : AtomicStPat<atomic_store_64, SD, GPR>; + +defm : AMOPat<"atomic_swap_64", "AMOSWAP_D">; +defm : AMOPat<"atomic_load_add_64", "AMOADD_D">; +defm : AMOPat<"atomic_load_and_64", "AMOAND_D">; +defm : AMOPat<"atomic_load_or_64", "AMOOR_D">; +defm : AMOPat<"atomic_load_xor_64", "AMOXOR_D">; +defm : AMOPat<"atomic_load_max_64", "AMOMAX_D">; +defm : AMOPat<"atomic_load_min_64", "AMOMIN_D">; +defm : AMOPat<"atomic_load_umax_64", "AMOMAXU_D">; +defm : AMOPat<"atomic_load_umin_64", "AMOMINU_D">; + +/// 64-bit AMOs + +def : Pat<(atomic_load_sub_64_monotonic GPR:$addr, GPR:$incr), + (AMOADD_D GPR:$addr, (SUB X0, GPR:$incr))>; +def : Pat<(atomic_load_sub_64_acquire GPR:$addr, GPR:$incr), + (AMOADD_D_AQ GPR:$addr, (SUB X0, GPR:$incr))>; +def : Pat<(atomic_load_sub_64_release GPR:$addr, GPR:$incr), + (AMOADD_D_RL GPR:$addr, (SUB X0, GPR:$incr))>; +def : Pat<(atomic_load_sub_64_acq_rel GPR:$addr, GPR:$incr), + (AMOADD_D_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; +def : Pat<(atomic_load_sub_64_seq_cst GPR:$addr, GPR:$incr), + (AMOADD_D_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; + +/// 64-bit pseudo AMOs + +def PseudoAtomicLoadNand64 : PseudoAMO; +// Ordering constants must be kept in sync with the AtomicOrdering enum in +// AtomicOrdering.h. +def : Pat<(atomic_load_nand_64_monotonic GPR:$addr, GPR:$incr), + (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 2)>; +def : Pat<(atomic_load_nand_64_acquire GPR:$addr, GPR:$incr), + (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 4)>; +def : Pat<(atomic_load_nand_64_release GPR:$addr, GPR:$incr), + (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 5)>; +def : Pat<(atomic_load_nand_64_acq_rel GPR:$addr, GPR:$incr), + (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 6)>; +def : Pat<(atomic_load_nand_64_seq_cst GPR:$addr, GPR:$incr), + (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 7)>; + +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_xchg_i64, + PseudoMaskedAtomicSwap32>; +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_add_i64, + PseudoMaskedAtomicLoadAdd32>; +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_sub_i64, + PseudoMaskedAtomicLoadSub32>; +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_nand_i64, + PseudoMaskedAtomicLoadNand32>; +def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_max_i64, + PseudoMaskedAtomicLoadMax32>; +def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_min_i64, + PseudoMaskedAtomicLoadMin32>; +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i64, + PseudoMaskedAtomicLoadUMax32>; +def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i64, + PseudoMaskedAtomicLoadUMin32>; + +/// 64-bit compare and exchange + +def PseudoCmpXchg64 : PseudoCmpXchg; +defm : PseudoCmpXchgPat<"atomic_cmp_swap_64", PseudoCmpXchg64>; + +def : Pat<(int_riscv_masked_cmpxchg_i64 + GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, imm:$ordering), + (PseudoMaskedCmpXchg32 + GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, imm:$ordering)>; +} // Predicates = [HasStdExtA, IsRV64] diff --git a/lib/Target/RISCV/RISCVInstrInfoC.td b/lib/Target/RISCV/RISCVInstrInfoC.td index ad68b5a7dc976..94477341eea74 100644 --- a/lib/Target/RISCV/RISCVInstrInfoC.td +++ b/lib/Target/RISCV/RISCVInstrInfoC.td @@ -1,9 +1,8 @@ //===- RISCVInstrInfoC.td - Compressed RISCV instructions -*- tblgen-*-----===// // -// 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 // //===----------------------------------------------------------------------===// @@ -524,6 +523,56 @@ def C_UNIMP : RVInst16<(outs), (ins), "c.unimp", "", [], InstFormatOther> { } // Predicates = [HasStdExtC] //===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions +//===----------------------------------------------------------------------===// + +let EmitPriority = 0 in { +let Predicates = [HasStdExtC, HasStdExtD] in +def : InstAlias<"c.fld $rd, (${rs1})", (C_FLD FPR64C:$rd, GPRC:$rs1, 0)>; + +def : InstAlias<"c.lw $rd, (${rs1})", (C_LW GPRC:$rd, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in +def : InstAlias<"c.flw $rd, (${rs1})", (C_FLW FPR32C:$rd, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, IsRV64] in +def : InstAlias<"c.ld $rd, (${rs1})", (C_LD GPRC:$rd, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtD] in +def : InstAlias<"c.fsd $rs2, (${rs1})", (C_FSD FPR64C:$rs2, GPRC:$rs1, 0)>; + +def : InstAlias<"c.sw $rs2, (${rs1})", (C_SW GPRC:$rs2, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in +def : InstAlias<"c.fsw $rs2, (${rs1})", (C_FSW FPR32C:$rs2, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, IsRV64] in +def : InstAlias<"c.sd $rs2, (${rs1})", (C_SD GPRC:$rs2, GPRC:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtD] in +def : InstAlias<"c.fldsp $rd, (${rs1})", (C_FLDSP FPR64C:$rd, SP:$rs1, 0)>; + +def : InstAlias<"c.lwsp $rd, (${rs1})", (C_LWSP GPRC:$rd, SP:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in +def : InstAlias<"c.flwsp $rd, (${rs1})", (C_FLWSP FPR32C:$rd, SP:$rs1, 0)>; + +let Predicates = [HasStdExtC, IsRV64] in +def : InstAlias<"c.ldsp $rd, (${rs1})", (C_LDSP GPRC:$rd, SP:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtD] in +def : InstAlias<"c.fsdsp $rs2, (${rs1})", (C_FSDSP FPR64C:$rs2, SP:$rs1, 0)>; + +def : InstAlias<"c.swsp $rs2, (${rs1})", (C_SWSP GPRC:$rs2, SP:$rs1, 0)>; + +let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in +def : InstAlias<"c.fswsp $rs2, (${rs1})", (C_FSWSP FPR32C:$rs2, SP:$rs1, 0)>; + +let Predicates = [HasStdExtC, IsRV64] in +def : InstAlias<"c.sdsp $rs2, (${rs1})", (C_SDSP GPRC:$rs2, SP:$rs1, 0)>; +} + +//===----------------------------------------------------------------------===// // Compress Instruction tablegen backend. //===----------------------------------------------------------------------===// diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td index 9f1cd50de595d..fe38c4ff02d33 100644 --- a/lib/Target/RISCV/RISCVInstrInfoD.td +++ b/lib/Target/RISCV/RISCVInstrInfoD.td @@ -1,9 +1,8 @@ //===-- RISCVInstrInfoD.td - RISC-V 'D' instructions -------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -179,8 +178,8 @@ def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> { //===----------------------------------------------------------------------===// let Predicates = [HasStdExtD] in { -// TODO fld -// TODO fsd +def : InstAlias<"fld $rd, (${rs1})", (FLD FPR64:$rd, GPR:$rs1, 0), 0>; +def : InstAlias<"fsd $rs2, (${rs1})", (FSD FPR64:$rs2, GPR:$rs1, 0), 0>; def : InstAlias<"fmv.d $rd, $rs", (FSGNJ_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>; def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>; @@ -192,6 +191,9 @@ def : InstAlias<"fgt.d $rd, $rs, $rt", (FLT_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>; def : InstAlias<"fge.d $rd, $rs, $rt", (FLE_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>; + +def PseudoFLD : PseudoFloatLoad<"fld", FPR64>; +def PseudoFSD : PseudoStore<"fsd", FPR64>; } // Predicates = [HasStdExtD] //===----------------------------------------------------------------------===// @@ -268,6 +270,10 @@ def : PatFpr64Fpr64<setole, FLE_D>; // handled by a RISC-V instruction and aren't expanded in the SelectionDAG // Legalizer. +def : Pat<(seto FPR64:$rs1, FPR64:$rs2), + (AND (FEQ_D FPR64:$rs1, FPR64:$rs1), + (FEQ_D FPR64:$rs2, FPR64:$rs2))>; + def : Pat<(setuo FPR64:$rs1, FPR64:$rs2), (SLTIU (AND (FEQ_D FPR64:$rs1, FPR64:$rs1), (FEQ_D FPR64:$rs2, FPR64:$rs2)), @@ -308,3 +314,26 @@ def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_WU_D FPR64:$rs1, 0b001)>; def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_W GPR:$rs1)>; def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_WU GPR:$rs1)>; } // Predicates = [HasStdExtD, IsRV32] + +let Predicates = [HasStdExtD, IsRV64] in { +def : Pat<(bitconvert GPR:$rs1), (FMV_D_X GPR:$rs1)>; +def : Pat<(bitconvert FPR64:$rs1), (FMV_X_D FPR64:$rs1)>; + +// FP->[u]int32 is mostly handled by the FP->[u]int64 patterns. This is safe +// because fpto[u|s]i produce poison if the value can't fit into the target. +// We match the single case below because fcvt.wu.d sign-extends its result so +// is cheaper than fcvt.lu.d+sext.w. +def : Pat<(sext_inreg (zexti32 (fp_to_uint FPR64:$rs1)), i32), + (FCVT_WU_D $rs1, 0b001)>; + +// [u]int32->fp +def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_D_W $rs1)>; +def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_D_WU $rs1)>; + +def : Pat<(fp_to_sint FPR64:$rs1), (FCVT_L_D FPR64:$rs1, 0b001)>; +def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_LU_D FPR64:$rs1, 0b001)>; + +// [u]int64->fp. Match GCC and default to using dynamic rounding mode. +def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_L GPR:$rs1, 0b111)>; +def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_LU GPR:$rs1, 0b111)>; +} // Predicates = [HasStdExtD, IsRV64] diff --git a/lib/Target/RISCV/RISCVInstrInfoF.td b/lib/Target/RISCV/RISCVInstrInfoF.td index 03bdac45873d0..032642942f2b5 100644 --- a/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/lib/Target/RISCV/RISCVInstrInfoF.td @@ -1,9 +1,8 @@ //===-- RISCVInstrInfoF.td - RISC-V 'F' instructions -------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -13,6 +12,20 @@ //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// +// RISC-V specific DAG Nodes. +//===----------------------------------------------------------------------===// + +def SDT_RISCVFMV_W_X_RV64 + : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>; +def SDT_RISCVFMV_X_ANYEXTW_RV64 + : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>; + +def riscv_fmv_w_x_rv64 + : SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>; +def riscv_fmv_x_anyextw_rv64 + : SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>; + +//===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. //===----------------------------------------------------------------------===// @@ -193,8 +206,8 @@ def : FPUnaryOpDynFrmAlias<FCVT_S_LU, "fcvt.s.lu", FPR32, GPR>; //===----------------------------------------------------------------------===// let Predicates = [HasStdExtF] in { -// TODO flw -// TODO fsw +def : InstAlias<"flw $rd, (${rs1})", (FLW FPR32:$rd, GPR:$rs1, 0), 0>; +def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>; def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; @@ -209,28 +222,30 @@ def : InstAlias<"fge.s $rd, $rs, $rt", // The following csr instructions actually alias instructions from the base ISA. // However, it only makes sense to support them when the F extension is enabled. -// CSR Addresses: 0x003 == fcsr, 0x002 == frm, 0x001 == fflags // NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr". -def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, 0x003, X0), 2>; -def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, 0x003, GPR:$rs)>; -def : InstAlias<"fscsr $rs", (CSRRW X0, 0x003, GPR:$rs), 2>; +def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, FCSR.Encoding, X0), 2>; +def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, FCSR.Encoding, GPR:$rs)>; +def : InstAlias<"fscsr $rs", (CSRRW X0, FCSR.Encoding, GPR:$rs), 2>; -def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, 0x002, X0), 2>; -def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, 0x002, GPR:$rs)>; -def : InstAlias<"fsrm $rs", (CSRRW X0, 0x002, GPR:$rs), 2>; -def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, 0x002, uimm5:$imm)>; -def : InstAlias<"fsrmi $imm", (CSRRWI X0, 0x002, uimm5:$imm), 2>; +def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, FRM.Encoding, X0), 2>; +def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, FRM.Encoding, GPR:$rs)>; +def : InstAlias<"fsrm $rs", (CSRRW X0, FRM.Encoding, GPR:$rs), 2>; +def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, FRM.Encoding, uimm5:$imm)>; +def : InstAlias<"fsrmi $imm", (CSRRWI X0, FRM.Encoding, uimm5:$imm), 2>; -def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, 0x001, X0), 2>; -def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, 0x001, GPR:$rs)>; -def : InstAlias<"fsflags $rs", (CSRRW X0, 0x001, GPR:$rs), 2>; -def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, 0x001, uimm5:$imm)>; -def : InstAlias<"fsflagsi $imm", (CSRRWI X0, 0x001, uimm5:$imm), 2>; +def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, FFLAGS.Encoding, X0), 2>; +def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, FFLAGS.Encoding, GPR:$rs)>; +def : InstAlias<"fsflags $rs", (CSRRW X0, FFLAGS.Encoding, GPR:$rs), 2>; +def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, FFLAGS.Encoding, uimm5:$imm)>; +def : InstAlias<"fsflagsi $imm", (CSRRWI X0, FFLAGS.Encoding, uimm5:$imm), 2>; // fmv.w.x and fmv.x.w were previously known as fmv.s.x and fmv.x.s. Both // spellings should be supported by standard tools. def : MnemonicAlias<"fmv.s.x", "fmv.w.x">; def : MnemonicAlias<"fmv.x.s", "fmv.x.w">; + +def PseudoFLW : PseudoFloatLoad<"flw", FPR32>; +def PseudoFSW : PseudoStore<"fsw", FPR32>; } // Predicates = [HasStdExtF] //===----------------------------------------------------------------------===// @@ -308,6 +323,10 @@ def : PatFpr32Fpr32<setole, FLE_S>; // handled by a RISC-V instruction and aren't expanded in the SelectionDAG // Legalizer. +def : Pat<(seto FPR32:$rs1, FPR32:$rs2), + (AND (FEQ_S FPR32:$rs1, FPR32:$rs1), + (FEQ_S FPR32:$rs2, FPR32:$rs2))>; + def : Pat<(setuo FPR32:$rs1, FPR32:$rs2), (SLTIU (AND (FEQ_S FPR32:$rs1, FPR32:$rs1), (FEQ_S FPR32:$rs2, FPR32:$rs2)), @@ -334,3 +353,37 @@ def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>; def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>; def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>; } // Predicates = [HasStdExtF, IsRV32] + +let Predicates = [HasStdExtF, IsRV32] in { +// FP->[u]int. Round-to-zero must be used +def : Pat<(fp_to_sint FPR32:$rs1), (FCVT_W_S $rs1, 0b001)>; +def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>; + +// [u]int->fp. Match GCC and default to using dynamic rounding mode. +def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>; +def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>; +} // Predicates = [HasStdExtF, IsRV32] + +let Predicates = [HasStdExtF, IsRV64] in { +def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>; +def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>; +def : Pat<(sexti32 (riscv_fmv_x_anyextw_rv64 FPR32:$src)), + (FMV_X_W FPR32:$src)>; + +// FP->[u]int32 is mostly handled by the FP->[u]int64 patterns. This is safe +// because fpto[u|s]i produces poison if the value can't fit into the target. +// We match the single case below because fcvt.wu.s sign-extends its result so +// is cheaper than fcvt.lu.s+sext.w. +def : Pat<(sext_inreg (assertzexti32 (fp_to_uint FPR32:$rs1)), i32), + (FCVT_WU_S $rs1, 0b001)>; + +// FP->[u]int64 +def : Pat<(fp_to_sint FPR32:$rs1), (FCVT_L_S $rs1, 0b001)>; +def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_LU_S $rs1, 0b001)>; + +// [u]int->fp. Match GCC and default to using dynamic rounding mode. +def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_S_W $rs1, 0b111)>; +def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>; +def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_L $rs1, 0b111)>; +def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_LU $rs1, 0b111)>; +} // Predicates = [HasStdExtF, IsRV64] diff --git a/lib/Target/RISCV/RISCVInstrInfoM.td b/lib/Target/RISCV/RISCVInstrInfoM.td index 05dd3311ad54c..e75151ba99c77 100644 --- a/lib/Target/RISCV/RISCVInstrInfoM.td +++ b/lib/Target/RISCV/RISCVInstrInfoM.td @@ -1,9 +1,8 @@ //===-- RISCVInstrInfoM.td - RISC-V 'M' instructions -------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -13,6 +12,14 @@ //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// +// RISC-V specific DAG Nodes. +//===----------------------------------------------------------------------===// + +def riscv_divw : SDNode<"RISCVISD::DIVW", SDTIntBinOp>; +def riscv_divuw : SDNode<"RISCVISD::DIVUW", SDTIntBinOp>; +def riscv_remuw : SDNode<"RISCVISD::REMUW", SDTIntBinOp>; + +//===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// @@ -53,18 +60,19 @@ def : PatGprGpr<urem, REMU>; let Predicates = [HasStdExtM, IsRV64] in { def : Pat<(sext_inreg (mul GPR:$rs1, GPR:$rs2), i32), (MULW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sext_inreg (sdiv (sexti32 GPR:$rs1), - (sexti32 GPR:$rs2)), i32), - (DIVW GPR:$rs1, GPR:$rs2)>; -def : Pat<(zexti32 (sdiv (sexti32 GPR:$rs1), - (sexti32 GPR:$rs2))), - (SRLI (SLLI (DIVW GPR:$rs1, GPR:$rs2), 32), 32)>; -def : Pat<(sext_inreg (udiv (zexti32 GPR:$rs1), (zexti32 GPR:$rs2)), i32), - (DIVUW GPR:$rs1, GPR:$rs2)>; -// It's cheaper to perform a divuw and zero-extend the result than to -// zero-extend both inputs to a udiv. -def : Pat<(udiv (and GPR:$rs1, 0xffffffff), (and GPR:$rs2, 0xffffffff)), - (SRLI (SLLI (DIVUW GPR:$rs1, GPR:$rs2), 32), 32)>; + +def : PatGprGpr<riscv_divw, DIVW>; +def : PatGprGpr<riscv_divuw, DIVUW>; +def : PatGprGpr<riscv_remuw, REMUW>; + +// Handle the specific cases where using DIVU/REMU would be correct and result +// in fewer instructions than emitting DIVUW/REMUW then zero-extending the +// result. +def : Pat<(zexti32 (riscv_divuw (zexti32 GPR:$rs1), (zexti32 GPR:$rs2))), + (DIVU GPR:$rs1, GPR:$rs2)>; +def : Pat<(zexti32 (riscv_remuw (zexti32 GPR:$rs1), (zexti32 GPR:$rs2))), + (REMU GPR:$rs1, GPR:$rs2)>; + // Although the sexti32 operands may not have originated from an i32 srem, // this pattern is safe as it is impossible for two sign extended inputs to // produce a result where res[63:32]=0 and res[31]=1. @@ -73,10 +81,4 @@ def : Pat<(srem (sexti32 GPR:$rs1), (sexti32 GPR:$rs2)), def : Pat<(sext_inreg (srem (sexti32 GPR:$rs1), (sexti32 GPR:$rs2)), i32), (REMW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sext_inreg (urem (zexti32 GPR:$rs1), (zexti32 GPR:$rs2)), i32), - (REMUW GPR:$rs1, GPR:$rs2)>; -// It's cheaper to perform a remuw and zero-extend the result than to -// zero-extend both inputs to a urem. -def : Pat<(urem (and GPR:$rs1, 0xffffffff), (and GPR:$rs2, 0xffffffff)), - (SRLI (SLLI (REMUW GPR:$rs1, GPR:$rs2), 32), 32)>; } // Predicates = [HasStdExtM, IsRV64] diff --git a/lib/Target/RISCV/RISCVMCInstLower.cpp b/lib/Target/RISCV/RISCVMCInstLower.cpp index e0100b1679be6..b1dbcfa7f7387 100644 --- a/lib/Target/RISCV/RISCVMCInstLower.cpp +++ b/lib/Target/RISCV/RISCVMCInstLower.cpp @@ -1,9 +1,8 @@ //===-- RISCVMCInstLower.cpp - Convert RISCV MachineInstr to an MCInst ------=// // -// 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 // //===----------------------------------------------------------------------===// // @@ -37,12 +36,42 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, case RISCVII::MO_None: Kind = RISCVMCExpr::VK_RISCV_None; break; + case RISCVII::MO_CALL: + Kind = RISCVMCExpr::VK_RISCV_CALL; + break; + case RISCVII::MO_PLT: + Kind = RISCVMCExpr::VK_RISCV_CALL_PLT; + break; case RISCVII::MO_LO: Kind = RISCVMCExpr::VK_RISCV_LO; break; case RISCVII::MO_HI: Kind = RISCVMCExpr::VK_RISCV_HI; break; + case RISCVII::MO_PCREL_LO: + Kind = RISCVMCExpr::VK_RISCV_PCREL_LO; + break; + case RISCVII::MO_PCREL_HI: + Kind = RISCVMCExpr::VK_RISCV_PCREL_HI; + break; + case RISCVII::MO_GOT_HI: + Kind = RISCVMCExpr::VK_RISCV_GOT_HI; + break; + case RISCVII::MO_TPREL_LO: + Kind = RISCVMCExpr::VK_RISCV_TPREL_LO; + break; + case RISCVII::MO_TPREL_HI: + Kind = RISCVMCExpr::VK_RISCV_TPREL_HI; + break; + case RISCVII::MO_TPREL_ADD: + Kind = RISCVMCExpr::VK_RISCV_TPREL_ADD; + break; + case RISCVII::MO_TLS_GOT_HI: + Kind = RISCVMCExpr::VK_RISCV_TLS_GOT_HI; + break; + case RISCVII::MO_TLS_GD_HI: + Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI; + break; } const MCExpr *ME = diff --git a/lib/Target/RISCV/RISCVMachineFunctionInfo.h b/lib/Target/RISCV/RISCVMachineFunctionInfo.h index 2fea3a1bdd2f4..585bff2bc20a2 100644 --- a/lib/Target/RISCV/RISCVMachineFunctionInfo.h +++ b/lib/Target/RISCV/RISCVMachineFunctionInfo.h @@ -1,9 +1,8 @@ //=- RISCVMachineFunctionInfo.h - RISCV machine function info -----*- C++ -*-=// // -// 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 // //===----------------------------------------------------------------------===// // @@ -33,8 +32,6 @@ private: int MoveF64FrameIndex = -1; public: - // RISCVMachineFunctionInfo() = default; - RISCVMachineFunctionInfo(MachineFunction &MF) : MF(MF) {} int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } diff --git a/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/lib/Target/RISCV/RISCVMergeBaseOffset.cpp index cea009c5447db..82b1209cb8e77 100644 --- a/lib/Target/RISCV/RISCVMergeBaseOffset.cpp +++ b/lib/Target/RISCV/RISCVMergeBaseOffset.cpp @@ -1,9 +1,8 @@ //===----- RISCVMergeBaseOffset.cpp - Optimise address calculations ------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Target/RISCV/RISCVRegisterInfo.cpp b/lib/Target/RISCV/RISCVRegisterInfo.cpp index 3ed1dec434cee..e6a126e3e513d 100644 --- a/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -1,9 +1,8 @@ //===-- RISCVRegisterInfo.cpp - RISCV Register Information ------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -33,17 +32,32 @@ RISCVRegisterInfo::RISCVRegisterInfo(unsigned HwMode) const MCPhysReg * RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + auto &Subtarget = MF->getSubtarget<RISCVSubtarget>(); if (MF->getFunction().hasFnAttribute("interrupt")) { - if (MF->getSubtarget<RISCVSubtarget>().hasStdExtD()) + if (Subtarget.hasStdExtD()) return CSR_XLEN_F64_Interrupt_SaveList; - if (MF->getSubtarget<RISCVSubtarget>().hasStdExtF()) + if (Subtarget.hasStdExtF()) return CSR_XLEN_F32_Interrupt_SaveList; return CSR_Interrupt_SaveList; } - return CSR_SaveList; + + switch (Subtarget.getTargetABI()) { + default: + llvm_unreachable("Unrecognized ABI"); + case RISCVABI::ABI_ILP32: + case RISCVABI::ABI_LP64: + return CSR_ILP32_LP64_SaveList; + case RISCVABI::ABI_ILP32F: + case RISCVABI::ABI_LP64F: + return CSR_ILP32F_LP64F_SaveList; + case RISCVABI::ABI_ILP32D: + case RISCVABI::ABI_LP64D: + return CSR_ILP32D_LP64D_SaveList; + } } BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = getFrameLowering(MF); BitVector Reserved(getNumRegs()); // Use markSuperRegs to ensure any register aliases are also reserved @@ -52,7 +66,8 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { markSuperRegs(Reserved, RISCV::X2); // sp markSuperRegs(Reserved, RISCV::X3); // gp markSuperRegs(Reserved, RISCV::X4); // tp - markSuperRegs(Reserved, RISCV::X8); // fp + if (TFI->hasFP(MF)) + markSuperRegs(Reserved, RISCV::X8); // fp assert(checkAllSuperRegsMarked(Reserved)); return Reserved; } @@ -109,7 +124,7 @@ void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); } -unsigned RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { +Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = getFrameLowering(MF); return TFI->hasFP(MF) ? RISCV::X8 : RISCV::X2; } @@ -117,12 +132,26 @@ unsigned RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const uint32_t * RISCVRegisterInfo::getCallPreservedMask(const MachineFunction & MF, CallingConv::ID /*CC*/) const { + auto &Subtarget = MF.getSubtarget<RISCVSubtarget>(); if (MF.getFunction().hasFnAttribute("interrupt")) { - if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD()) + if (Subtarget.hasStdExtD()) return CSR_XLEN_F64_Interrupt_RegMask; - if (MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) + if (Subtarget.hasStdExtF()) return CSR_XLEN_F32_Interrupt_RegMask; return CSR_Interrupt_RegMask; } - return CSR_RegMask; + + switch (Subtarget.getTargetABI()) { + default: + llvm_unreachable("Unrecognized ABI"); + case RISCVABI::ABI_ILP32: + case RISCVABI::ABI_LP64: + return CSR_ILP32_LP64_RegMask; + case RISCVABI::ABI_ILP32F: + case RISCVABI::ABI_LP64F: + return CSR_ILP32F_LP64F_RegMask; + case RISCVABI::ABI_ILP32D: + case RISCVABI::ABI_LP64D: + return CSR_ILP32D_LP64D_RegMask; + } } diff --git a/lib/Target/RISCV/RISCVRegisterInfo.h b/lib/Target/RISCV/RISCVRegisterInfo.h index cbbb70079dd17..4f339475508fd 100644 --- a/lib/Target/RISCV/RISCVRegisterInfo.h +++ b/lib/Target/RISCV/RISCVRegisterInfo.h @@ -1,9 +1,8 @@ //===-- RISCVRegisterInfo.h - RISCV Register Information Impl ---*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -40,7 +39,7 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo { unsigned FIOperandNum, RegScavenger *RS = nullptr) const override; - unsigned getFrameRegister(const MachineFunction &MF) const override; + Register getFrameRegister(const MachineFunction &MF) const override; bool requiresRegisterScavenging(const MachineFunction &MF) const override { return true; diff --git a/lib/Target/RISCV/RISCVRegisterInfo.td b/lib/Target/RISCV/RISCVRegisterInfo.td index 4be8ff9200e92..79f8ab12f6c0a 100644 --- a/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/lib/Target/RISCV/RISCVRegisterInfo.td @@ -1,9 +1,8 @@ //===-- RISCVRegisterInfo.td - RISC-V Register defs --------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -56,7 +55,7 @@ let RegAltNameIndices = [ABIRegAltName] in { def X6 : RISCVReg<6, "x6", ["t1"]>, DwarfRegNum<[6]>; def X7 : RISCVReg<7, "x7", ["t2"]>, DwarfRegNum<[7]>; } - def X8 : RISCVReg<8, "x8", ["s0"]>, DwarfRegNum<[8]>; + def X8 : RISCVReg<8, "x8", ["s0", "fp"]>, DwarfRegNum<[8]>; def X9 : RISCVReg<9, "x9", ["s1"]>, DwarfRegNum<[9]>; def X10 : RISCVReg<10,"x10", ["a0"]>, DwarfRegNum<[10]>; def X11 : RISCVReg<11,"x11", ["a1"]>, DwarfRegNum<[11]>; diff --git a/lib/Target/RISCV/RISCVSubtarget.cpp b/lib/Target/RISCV/RISCVSubtarget.cpp index b221ea84a33c2..6902ed75d8521 100644 --- a/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/lib/Target/RISCV/RISCVSubtarget.cpp @@ -1,9 +1,8 @@ //===-- RISCVSubtarget.cpp - RISCV Subtarget Information ------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -26,10 +25,10 @@ using namespace llvm; void RISCVSubtarget::anchor() {} -RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies(StringRef CPU, - StringRef FS, - bool Is64Bit) { +RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies( + const Triple &TT, StringRef CPU, StringRef FS, StringRef ABIName) { // Determine default and user-specified characteristics + bool Is64Bit = TT.isArch64Bit(); std::string CPUName = CPU; if (CPUName.empty()) CPUName = Is64Bit ? "generic-rv64" : "generic-rv32"; @@ -38,11 +37,14 @@ RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies(StringRef CPU, XLenVT = MVT::i64; XLen = 64; } + + TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName); + RISCVFeatures::validate(TT, getFeatureBits()); return *this; } -RISCVSubtarget::RISCVSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, const TargetMachine &TM) +RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef FS, + StringRef ABIName, const TargetMachine &TM) : RISCVGenSubtargetInfo(TT, CPU, FS), - FrameLowering(initializeSubtargetDependencies(CPU, FS, TT.isArch64Bit())), + FrameLowering(initializeSubtargetDependencies(TT, CPU, FS, ABIName)), InstrInfo(), RegInfo(getHwMode()), TLInfo(TM, *this) {} diff --git a/lib/Target/RISCV/RISCVSubtarget.h b/lib/Target/RISCV/RISCVSubtarget.h index 0e09391e7829b..106ff49f021a6 100644 --- a/lib/Target/RISCV/RISCVSubtarget.h +++ b/lib/Target/RISCV/RISCVSubtarget.h @@ -1,9 +1,8 @@ //===-- RISCVSubtarget.h - Define Subtarget for the RISCV -------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -17,6 +16,7 @@ #include "RISCVFrameLowering.h" #include "RISCVISelLowering.h" #include "RISCVInstrInfo.h" +#include "Utils/RISCVBaseInfo.h" #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" @@ -36,9 +36,11 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { bool HasStdExtD = false; bool HasStdExtC = false; bool HasRV64 = false; + bool IsRV32E = false; bool EnableLinkerRelax = false; unsigned XLen = 32; MVT XLenVT = MVT::i32; + RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; RISCVFrameLowering FrameLowering; RISCVInstrInfo InstrInfo; RISCVRegisterInfo RegInfo; @@ -47,13 +49,14 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { /// Initializes using the passed in CPU and feature strings so that we can /// use initializer lists for subtarget initialization. - RISCVSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS, - bool Is64Bit); + RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, + StringRef CPU, StringRef FS, + StringRef ABIName); public: // Initializes the data members to match that of the specified triple. - RISCVSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, const TargetMachine &TM); + RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef FS, + StringRef ABIName, const TargetMachine &TM); // Parses features string setting specified subtarget options. The // definition of this function is auto-generated by tblgen. @@ -78,9 +81,11 @@ public: bool hasStdExtD() const { return HasStdExtD; } bool hasStdExtC() const { return HasStdExtC; } bool is64Bit() const { return HasRV64; } + bool isRV32E() const { return IsRV32E; } bool enableLinkerRelax() const { return EnableLinkerRelax; } MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } + RISCVABI::ABI getTargetABI() const { return TargetABI; } }; } // End llvm namespace diff --git a/lib/Target/RISCV/RISCVSystemOperands.td b/lib/Target/RISCV/RISCVSystemOperands.td index f1b7984ffe6bc..a46a32c4e7f25 100644 --- a/lib/Target/RISCV/RISCVSystemOperands.td +++ b/lib/Target/RISCV/RISCVSystemOperands.td @@ -1,9 +1,8 @@ //===- RISCVSystemOperands.td ----------------------------*- tablegen -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -72,18 +71,16 @@ def : SysReg<"uip", 0x044>; // User Floating-Point CSRs //===-------------------------- -let FeaturesRequired = [{ {RISCV::FeatureStdExtF} }] in { -def : SysReg<"fflags", 0x001>; -def : SysReg<"frm", 0x002>; -def : SysReg<"fcsr", 0x003>; -} +def FFLAGS : SysReg<"fflags", 0x001>; +def FRM : SysReg<"frm", 0x002>; +def FCSR : SysReg<"fcsr", 0x003>; //===-------------------------- // User Counter/Timers //===-------------------------- -def : SysReg<"cycle", 0xC00>; -def : SysReg<"time", 0xC01>; -def : SysReg<"instret", 0xC02>; +def CYCLE : SysReg<"cycle", 0xC00>; +def TIME : SysReg<"time", 0xC01>; +def INSTRET : SysReg<"instret", 0xC02>; def : SysReg<"hpmcounter3", 0xC03>; def : SysReg<"hpmcounter4", 0xC04>; @@ -116,9 +113,9 @@ def : SysReg<"hpmcounter30", 0xC1E>; def : SysReg<"hpmcounter31", 0xC1F>; let isRV32Only = 1 in { -def: SysReg<"cycleh", 0xC80>; -def: SysReg<"timeh", 0xC81>; -def: SysReg<"instreth", 0xC82>; +def CYCLEH : SysReg<"cycleh", 0xC80>; +def TIMEH : SysReg<"timeh", 0xC81>; +def INSTRETH : SysReg<"instreth", 0xC82>; def: SysReg<"hpmcounter3h", 0xC83>; def: SysReg<"hpmcounter4h", 0xC84>; diff --git a/lib/Target/RISCV/RISCVTargetMachine.cpp b/lib/Target/RISCV/RISCVTargetMachine.cpp index 8937ec200bd74..f4e6ed9f6284a 100644 --- a/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -1,9 +1,8 @@ //===-- RISCVTargetMachine.cpp - Define TargetMachine for RISCV -----------===// // -// 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,10 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "RISCV.h" #include "RISCVTargetMachine.h" +#include "RISCV.h" #include "RISCVTargetObjectFile.h" +#include "RISCVTargetTransformInfo.h" +#include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -31,7 +33,7 @@ extern "C" void LLVMInitializeRISCVTarget() { initializeRISCVExpandPseudoPass(*PR); } -static std::string computeDataLayout(const Triple &TT) { +static StringRef computeDataLayout(const Triple &TT) { if (TT.isArch64Bit()) { return "e-m:e-p:64:64-i64:64-i128:128-n64-S128"; } else { @@ -57,10 +59,15 @@ RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT, getEffectiveRelocModel(TT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), TLOF(make_unique<RISCVELFTargetObjectFile>()), - Subtarget(TT, CPU, FS, *this) { + Subtarget(TT, CPU, FS, Options.MCOptions.getABIName(), *this) { initAsmInfo(); } +TargetTransformInfo +RISCVTargetMachine::getTargetTransformInfo(const Function &F) { + return TargetTransformInfo(RISCVTTIImpl(this, F)); +} + namespace { class RISCVPassConfig : public TargetPassConfig { public: diff --git a/lib/Target/RISCV/RISCVTargetMachine.h b/lib/Target/RISCV/RISCVTargetMachine.h index 02361dddebf7b..ebf3f3c079557 100644 --- a/lib/Target/RISCV/RISCVTargetMachine.h +++ b/lib/Target/RISCV/RISCVTargetMachine.h @@ -1,9 +1,8 @@ //===-- RISCVTargetMachine.h - Define TargetMachine for RISCV ---*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -40,6 +39,8 @@ public: TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } + + TargetTransformInfo getTargetTransformInfo(const Function &F) override; }; } diff --git a/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/lib/Target/RISCV/RISCVTargetObjectFile.cpp index 46e81b628b65b..bbd45c970d3dc 100644 --- a/lib/Target/RISCV/RISCVTargetObjectFile.cpp +++ b/lib/Target/RISCV/RISCVTargetObjectFile.cpp @@ -1,14 +1,16 @@ //===-- RISCVTargetObjectFile.cpp - RISCV Object Info -----------------===// // -// 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 // //===----------------------------------------------------------------------===// #include "RISCVTargetObjectFile.h" #include "RISCVTargetMachine.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" using namespace llvm; @@ -16,4 +18,97 @@ void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(TM.Options.UseInitArray); + + SmallDataSection = getContext().getELFSection( + ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC); +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section could be addressed by +// using gp_rel operator. +bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { + // gcc has traditionally not treated zero-sized objects as small data, so this + // is effectively part of the ABI. + return Size > 0 && Size <= SSThreshold; +} + +// Return true if this global address should be placed into small data/bss +// section. +bool RISCVELFTargetObjectFile::isGlobalInSmallSection( + const GlobalObject *GO, const TargetMachine &TM) const { + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); + if (!GVA) + return false; + + // If the variable has an explicit section, it is placed in that section. + if (GVA->hasSection()) { + StringRef Section = GVA->getSection(); + + // Explicitly placing any variable in the small data section overrides + // the global -G value. + if (Section == ".sdata" || Section == ".sbss") + return true; + + // Otherwise reject putting the variable to small section if it has an + // explicit section name. + return false; + } + + if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || + GVA->hasCommonLinkage())) + return false; + + Type *Ty = GVA->getValueType(); + // It is possible that the type of the global is unsized, i.e. a declaration + // of a extern struct. In this case don't presume it is in the small data + // section. This happens e.g. when building the FreeBSD kernel. + if (!Ty->isSized()) + return false; + + return isInSmallSection( + GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); +} + +MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + // Handle Small Section classification here. + if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) + return SmallBSSSection; + if (Kind.isData() && isGlobalInSmallSection(GO, TM)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); +} + +void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { + SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; + M.getModuleFlagsMetadata(ModuleFlags); + + for (const auto &MFE : ModuleFlags) { + StringRef Key = MFE.Key->getString(); + if (Key == "SmallDataLimit") { + SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); + break; + } + } +} + +/// Return true if this constant should be placed into small data section. +bool RISCVELFTargetObjectFile::isConstantInSmallSection( + const DataLayout &DL, const Constant *CN) const { + return isInSmallSection(DL.getTypeAllocSize(CN->getType())); +} + +MCSection *RISCVELFTargetObjectFile::getSectionForConstant( + const DataLayout &DL, SectionKind Kind, const Constant *C, + unsigned &Align) const { + if (isConstantInSmallSection(DL, C)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align); } diff --git a/lib/Target/RISCV/RISCVTargetObjectFile.h b/lib/Target/RISCV/RISCVTargetObjectFile.h index 5467220301c1f..b2daaaa9d364d 100644 --- a/lib/Target/RISCV/RISCVTargetObjectFile.h +++ b/lib/Target/RISCV/RISCVTargetObjectFile.h @@ -1,9 +1,8 @@ //===-- RISCVTargetObjectFile.h - RISCV Object Info -*- C++ ---------*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -17,7 +16,31 @@ class RISCVTargetMachine; /// This implementation is used for RISCV ELF targets. class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF { + MCSection *SmallDataSection; + MCSection *SmallBSSSection; + unsigned SSThreshold = 8; + +public: void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + /// Return true if this global address should be placed into small data/bss + /// section. + bool isGlobalInSmallSection(const GlobalObject *GO, + const TargetMachine &TM) const; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + /// Return true if this constant should be placed into small data section. + bool isConstantInSmallSection(const DataLayout &DL, const Constant *CN) const; + + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; + + void getModuleMetadata(Module &M) override; + + bool isInSmallSection(uint64_t Size) const; }; } // end namespace llvm diff --git a/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/lib/Target/RISCV/RISCVTargetTransformInfo.cpp new file mode 100644 index 0000000000000..2c6400cbb1eba --- /dev/null +++ b/lib/Target/RISCV/RISCVTargetTransformInfo.cpp @@ -0,0 +1,92 @@ +//===-- RISCVTargetTransformInfo.cpp - RISC-V specific TTI ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "RISCVTargetTransformInfo.h" +#include "Utils/RISCVMatInt.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/CodeGen/TargetLowering.h" +using namespace llvm; + +#define DEBUG_TYPE "riscvtti" + +int RISCVTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty) { + assert(Ty->isIntegerTy() && + "getIntImmCost can only estimate cost of materialising integers"); + + // We have a Zero register, so 0 is always free. + if (Imm == 0) + return TTI::TCC_Free; + + // Otherwise, we check how many instructions it will take to materialise. + const DataLayout &DL = getDataLayout(); + return RISCVMatInt::getIntMatCost(Imm, DL.getTypeSizeInBits(Ty), + getST()->is64Bit()); +} + +int RISCVTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, + Type *Ty) { + assert(Ty->isIntegerTy() && + "getIntImmCost can only estimate cost of materialising integers"); + + // We have a Zero register, so 0 is always free. + if (Imm == 0) + return TTI::TCC_Free; + + // Some instructions in RISC-V can take a 12-bit immediate. Some of these are + // commutative, in others the immediate comes from a specific argument index. + bool Takes12BitImm = false; + unsigned ImmArgIdx = ~0U; + + switch (Opcode) { + case Instruction::GetElementPtr: + // Never hoist any arguments to a GetElementPtr. CodeGenPrepare will + // split up large offsets in GEP into better parts than ConstantHoisting + // can. + return TTI::TCC_Free; + case Instruction::Add: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Mul: + Takes12BitImm = true; + break; + case Instruction::Sub: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + Takes12BitImm = true; + ImmArgIdx = 1; + break; + default: + break; + } + + if (Takes12BitImm) { + // Check immediate is the correct argument... + if (Instruction::isCommutative(Opcode) || Idx == ImmArgIdx) { + // ... and fits into the 12-bit immediate. + if (Imm.getMinSignedBits() <= 64 && + getTLI()->isLegalAddImmediate(Imm.getSExtValue())) { + return TTI::TCC_Free; + } + } + + // Otherwise, use the full materialisation cost. + return getIntImmCost(Imm, Ty); + } + + // By default, prevent hoisting. + return TTI::TCC_Free; +} + +int RISCVTTIImpl::getIntImmCost(Intrinsic::ID IID, unsigned Idx, + const APInt &Imm, Type *Ty) { + // Prevent hoisting in unknown cases. + return TTI::TCC_Free; +} diff --git a/lib/Target/RISCV/RISCVTargetTransformInfo.h b/lib/Target/RISCV/RISCVTargetTransformInfo.h new file mode 100644 index 0000000000000..f361b25a0c707 --- /dev/null +++ b/lib/Target/RISCV/RISCVTargetTransformInfo.h @@ -0,0 +1,52 @@ +//===- RISCVTargetTransformInfo.h - RISC-V specific TTI ---------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file defines a TargetTransformInfo::Concept conforming object specific +/// to the RISC-V target machine. It uses the target's detailed information to +/// provide more precise answers to certain TTI queries, while letting the +/// target independent and default TTI implementations handle the rest. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H + +#include "RISCVSubtarget.h" +#include "RISCVTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/IR/Function.h" + +namespace llvm { + +class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> { + using BaseT = BasicTTIImplBase<RISCVTTIImpl>; + using TTI = TargetTransformInfo; + + friend BaseT; + + const RISCVSubtarget *ST; + const RISCVTargetLowering *TLI; + + const RISCVSubtarget *getST() const { return ST; } + const RISCVTargetLowering *getTLI() const { return TLI; } + +public: + explicit RISCVTTIImpl(const RISCVTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + int getIntImmCost(const APInt &Imm, Type *Ty); + int getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty); + int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, + Type *Ty); +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H
\ No newline at end of file diff --git a/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp index 0f369d960fe14..e44984a3fcc5b 100644 --- a/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp +++ b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp @@ -1,26 +1,24 @@ //===-- RISCVTargetInfo.cpp - RISCV Target Implementation -----------------===// // -// 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 // //===----------------------------------------------------------------------===// +#include "TargetInfo/RISCVTargetInfo.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; -namespace llvm { -Target &getTheRISCV32Target() { +Target &llvm::getTheRISCV32Target() { static Target TheRISCV32Target; return TheRISCV32Target; } -Target &getTheRISCV64Target() { +Target &llvm::getTheRISCV64Target() { static Target TheRISCV64Target; return TheRISCV64Target; } -} extern "C" void LLVMInitializeRISCVTargetInfo() { RegisterTarget<Triple::riscv32> X(getTheRISCV32Target(), "riscv32", diff --git a/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.h b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.h new file mode 100644 index 0000000000000..ef3d9d116efab --- /dev/null +++ b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.h @@ -0,0 +1,21 @@ +//===-- RISCVTargetInfo.h - RISCV Target Implementation ---------*- 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_RISCV_TARGETINFO_RISCVTARGETINFO_H +#define LLVM_LIB_TARGET_RISCV_TARGETINFO_RISCVTARGETINFO_H + +namespace llvm { + +class Target; + +Target &getTheRISCV32Target(); +Target &getTheRISCV64Target(); + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_RISCV_TARGETINFO_RISCVTARGETINFO_H diff --git a/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp b/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp index 964af1f74cecb..bc5395768ca15 100644 --- a/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp +++ b/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp @@ -1,9 +1,80 @@ #include "RISCVBaseInfo.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { namespace RISCVSysReg { #define GET_SysRegsList_IMPL #include "RISCVGenSystemOperands.inc" } // namespace RISCVSysReg + +namespace RISCVABI { +ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, + StringRef ABIName) { + auto TargetABI = StringSwitch<ABI>(ABIName) + .Case("ilp32", ABI_ILP32) + .Case("ilp32f", ABI_ILP32F) + .Case("ilp32d", ABI_ILP32D) + .Case("ilp32e", ABI_ILP32E) + .Case("lp64", ABI_LP64) + .Case("lp64f", ABI_LP64F) + .Case("lp64d", ABI_LP64D) + .Default(ABI_Unknown); + + bool IsRV64 = TT.isArch64Bit(); + bool IsRV32E = FeatureBits[RISCV::FeatureRV32E]; + + if (!ABIName.empty() && TargetABI == ABI_Unknown) { + errs() + << "'" << ABIName + << "' is not a recognized ABI for this target (ignoring target-abi)\n"; + } else if (ABIName.startswith("ilp32") && IsRV64) { + errs() << "32-bit ABIs are not supported for 64-bit targets (ignoring " + "target-abi)\n"; + TargetABI = ABI_Unknown; + } else if (ABIName.startswith("lp64") && !IsRV64) { + errs() << "64-bit ABIs are not supported for 32-bit targets (ignoring " + "target-abi)\n"; + TargetABI = ABI_Unknown; + } else if (ABIName.endswith("f") && !FeatureBits[RISCV::FeatureStdExtF]) { + errs() << "Hard-float 'f' ABI can't be used for a target that " + "doesn't support the F instruction set extension (ignoring " + "target-abi)\n"; + TargetABI = ABI_Unknown; + } else if (ABIName.endswith("d") && !FeatureBits[RISCV::FeatureStdExtD]) { + errs() << "Hard-float 'd' ABI can't be used for a target that " + "doesn't support the D instruction set extension (ignoring " + "target-abi)\n"; + TargetABI = ABI_Unknown; + } else if (IsRV32E && TargetABI != ABI_ILP32E && TargetABI != ABI_Unknown) { + errs() + << "Only the ilp32e ABI is supported for RV32E (ignoring target-abi)\n"; + TargetABI = ABI_Unknown; + } + + if (TargetABI != ABI_Unknown) + return TargetABI; + + // For now, default to the ilp32/ilp32e/lp64 ABI if no explicit ABI is given + // or an invalid/unrecognised string is given. In the future, it might be + // worth changing this to default to ilp32f/lp64f and ilp32d/lp64d when + // hardware support for floating point is present. + if (IsRV32E) + return ABI_ILP32E; + if (IsRV64) + return ABI_LP64; + return ABI_ILP32; +} +} // namespace RISCVABI + +namespace RISCVFeatures { + +void validate(const Triple &TT, const FeatureBitset &FeatureBits) { + if (TT.isArch64Bit() && FeatureBits[RISCV::FeatureRV32E]) + report_fatal_error("RV32E can't be enabled for an RV64 target"); +} + +} // namespace RISCVFeatures + } // namespace llvm diff --git a/lib/Target/RISCV/Utils/RISCVBaseInfo.h b/lib/Target/RISCV/Utils/RISCVBaseInfo.h index 372e0e80bbaf8..c33c72f243199 100644 --- a/lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ b/lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -1,9 +1,8 @@ //===-- RISCVBaseInfo.h - Top level definitions for RISCV MC ----*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -49,9 +48,18 @@ enum { enum { MO_None, + MO_CALL, + MO_PLT, MO_LO, MO_HI, + MO_PCREL_LO, MO_PCREL_HI, + MO_GOT_HI, + MO_TPREL_LO, + MO_TPREL_HI, + MO_TPREL_ADD, + MO_TLS_GOT_HI, + MO_TLS_GD_HI, }; } // namespace RISCVII @@ -153,6 +161,34 @@ struct SysReg { #include "RISCVGenSystemOperands.inc" } // end namespace RISCVSysReg +namespace RISCVABI { + +enum ABI { + ABI_ILP32, + ABI_ILP32F, + ABI_ILP32D, + ABI_ILP32E, + ABI_LP64, + ABI_LP64F, + ABI_LP64D, + ABI_Unknown +}; + +// Returns the target ABI, or else a StringError if the requested ABIName is +// not supported for the given TT and FeatureBits combination. +ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, + StringRef ABIName); + +} // namespace RISCVABI + +namespace RISCVFeatures { + +// Validates if the given combination of features are valid for the target +// triple. Exits with report_fatal_error if not. +void validate(const Triple &TT, const FeatureBitset &FeatureBits); + +} // namespace RISCVFeatures + } // namespace llvm #endif diff --git a/lib/Target/RISCV/Utils/RISCVMatInt.cpp b/lib/Target/RISCV/Utils/RISCVMatInt.cpp index 3dc298246bc56..f390ddb89e3c9 100644 --- a/lib/Target/RISCV/Utils/RISCVMatInt.cpp +++ b/lib/Target/RISCV/Utils/RISCVMatInt.cpp @@ -1,9 +1,8 @@ //===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// @@ -17,7 +16,7 @@ namespace llvm { namespace RISCVMatInt { -void generateInstSeq(int64_t Val, bool Is64Bit, InstSeq &Res) { +void generateInstSeq(int64_t Val, bool IsRV64, InstSeq &Res) { if (isInt<32>(Val)) { // Depending on the active bits in the immediate Value v, the following // instruction sequences are emitted: @@ -33,13 +32,13 @@ void generateInstSeq(int64_t Val, bool Is64Bit, InstSeq &Res) { Res.push_back(Inst(RISCV::LUI, Hi20)); if (Lo12 || Hi20 == 0) { - unsigned AddiOpc = (Is64Bit && Hi20) ? RISCV::ADDIW : RISCV::ADDI; + unsigned AddiOpc = (IsRV64 && Hi20) ? RISCV::ADDIW : RISCV::ADDI; Res.push_back(Inst(AddiOpc, Lo12)); } return; } - assert(Is64Bit && "Can't emit >32-bit imm for non-RV64 target"); + assert(IsRV64 && "Can't emit >32-bit imm for non-RV64 target"); // In the worst case, for a full 64-bit constant, a sequence of 8 instructions // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note @@ -65,15 +64,30 @@ void generateInstSeq(int64_t Val, bool Is64Bit, InstSeq &Res) { // performed when the recursion returns. int64_t Lo12 = SignExtend64<12>(Val); - int64_t Hi52 = (Val + 0x800) >> 12; + int64_t Hi52 = ((uint64_t)Val + 0x800ull) >> 12; int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52); Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount); - generateInstSeq(Hi52, Is64Bit, Res); + generateInstSeq(Hi52, IsRV64, Res); Res.push_back(Inst(RISCV::SLLI, ShiftAmount)); if (Lo12) Res.push_back(Inst(RISCV::ADDI, Lo12)); } + +int getIntMatCost(const APInt &Val, unsigned Size, bool IsRV64) { + int PlatRegSize = IsRV64 ? 64 : 32; + + // Split the constant into platform register sized chunks, and calculate cost + // of each chunk. + int Cost = 0; + for (unsigned ShiftVal = 0; ShiftVal < Size; ShiftVal += PlatRegSize) { + APInt Chunk = Val.ashr(ShiftVal).sextOrTrunc(PlatRegSize); + InstSeq MatSeq; + generateInstSeq(Chunk.getSExtValue(), IsRV64, MatSeq); + Cost += MatSeq.size(); + } + return std::max(1, Cost); +} } // namespace RISCVMatInt } // namespace llvm diff --git a/lib/Target/RISCV/Utils/RISCVMatInt.h b/lib/Target/RISCV/Utils/RISCVMatInt.h index 49d1d89adc7a1..b12ae2eade999 100644 --- a/lib/Target/RISCV/Utils/RISCVMatInt.h +++ b/lib/Target/RISCV/Utils/RISCVMatInt.h @@ -1,15 +1,15 @@ //===- RISCVMatInt.h - Immediate materialisation ---------------*- C++ -*--===// // -// 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_RISCV_MATINT_H #define LLVM_LIB_TARGET_RISCV_MATINT_H +#include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/MachineValueType.h" #include <cstdint> @@ -31,6 +31,14 @@ using InstSeq = SmallVector<Inst, 8>; // order to allow this helper to be used from both the MC layer and during // instruction selection. void generateInstSeq(int64_t Val, bool IsRV64, InstSeq &Res); + +// Helper to estimate the number of instructions required to materialise the +// given immediate value into a register. This estimate does not account for +// `Val` possibly fitting into an immediate, and so may over-estimate. +// +// This will attempt to produce instructions to materialise `Val` as an +// `Size`-bit immediate. `IsRV64` should match the target architecture. +int getIntMatCost(const APInt &Val, unsigned Size, bool IsRV64); } // namespace RISCVMatInt } // namespace llvm #endif |
