diff options
Diffstat (limited to 'llvm/lib/Target/RISCV')
32 files changed, 707 insertions, 168 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 300ba8dc675c9..53562f42a1847 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -15,6 +15,7 @@ #include "Utils/RISCVMatInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/CodeGen/Register.h" #include "llvm/MC/MCAssembler.h" @@ -37,10 +38,15 @@ using namespace llvm; +#define DEBUG_TYPE "riscv-asm-parser" + // Include the auto-generated portion of the compress emitter. #define GEN_COMPRESS_INSTR #include "RISCVGenCompressInstEmitter.inc" +STATISTIC(RISCVNumInstrsCompressed, + "Number of RISC-V Compressed instructions emitted"); + namespace { struct RISCVOperand; @@ -188,6 +194,18 @@ public: Parser.addAliasForDirective(".word", ".4byte"); Parser.addAliasForDirective(".dword", ".8byte"); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + if (Options.ABIName.back() == 'f' && + !getSTI().getFeatureBits()[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"; + } else if (Options.ABIName.back() == 'd' && + !getSTI().getFeatureBits()[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"; + } } }; @@ -258,6 +276,11 @@ public: bool isMem() const override { return false; } bool isSystemRegister() const { return Kind == KindTy::SystemRegister; } + bool isGPR() const { + return Kind == KindTy::Register && + RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.RegNum); + } + static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm, RISCVMCExpr::VariantKind &VK) { if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) { @@ -738,7 +761,9 @@ public: } // end anonymous namespace. #define GET_REGISTER_MATCHER +#define GET_SUBTARGET_FEATURE_NAME #define GET_MATCHER_IMPLEMENTATION +#define GET_MNEMONIC_SPELL_CHECKER #include "RISCVGenAsmMatcher.inc" static Register convertFPR64ToFPR32(Register Reg) { @@ -775,24 +800,45 @@ bool RISCVAsmParser::generateImmOutOfRangeError( return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); } +static std::string RISCVMnemonicSpellCheck(StringRef S, + const FeatureBitset &FBS, + unsigned VariantID = 0); + bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; + FeatureBitset MissingFeatures; auto Result = - MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, + MatchingInlineAsm); switch (Result) { default: break; case Match_Success: return processInstruction(Inst, IDLoc, Operands, Out); - case Match_MissingFeature: - return Error(IDLoc, "instruction use requires an option to be enabled"); - case Match_MnemonicFail: - return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_MissingFeature: { + assert(MissingFeatures.any() && "Unknown missing features!"); + bool FirstFeature = true; + std::string Msg = "instruction requires the following:"; + for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { + if (MissingFeatures[i]) { + Msg += FirstFeature ? " " : ", "; + Msg += getSubtargetFeatureName(i); + FirstFeature = false; + } + } + return Error(IDLoc, Msg); + } + case Match_MnemonicFail: { + FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + std::string Suggestion = RISCVMnemonicSpellCheck( + ((RISCVOperand &)*Operands[0]).getToken(), FBS); + return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion); + } case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0U) { @@ -1587,7 +1633,8 @@ bool RISCVAsmParser::parseDirectiveOption() { void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); - CInst.setLoc(Inst.getLoc()); + if (Res) + ++RISCVNumInstrsCompressed; S.EmitInstruction((Res ? CInst : Inst), getSTI()); } @@ -1837,7 +1884,7 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, return false; } -extern "C" void LLVMInitializeRISCVAsmParser() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmParser() { RegisterMCAsmParser<RISCVAsmParser> X(getTheRISCV32Target()); RegisterMCAsmParser<RISCVAsmParser> Y(getTheRISCV64Target()); } diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index 15943ba42156f..1461a40227bf9 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -38,7 +38,6 @@ public: DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, - raw_ostream &VStream, raw_ostream &CStream) const override; }; } // end anonymous namespace @@ -49,7 +48,7 @@ static MCDisassembler *createRISCVDisassembler(const Target &T, return new RISCVDisassembler(STI, Ctx); } -extern "C" void LLVMInitializeRISCVDisassembler() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVDisassembler() { // Register the disassembler for each target. TargetRegistry::RegisterMCDisassembler(getTheRISCV32Target(), createRISCVDisassembler); @@ -315,7 +314,6 @@ static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn, DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, - raw_ostream &OS, raw_ostream &CS) const { // TODO: This will need modification when supporting instruction set // extensions with instructions > 32-bits (up to 176 bits wide). diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index f6b727ae37c75..5881a0a86ef77 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -64,11 +64,15 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, case RISCV::fixup_riscv_tls_gd_hi20: ShouldForce = true; break; - case RISCV::fixup_riscv_pcrel_hi20: - ShouldForce = T->getValue()->findAssociatedFragment() != - Fixup.getValue()->findAssociatedFragment(); + case RISCV::fixup_riscv_pcrel_hi20: { + MCFragment *TFragment = T->getValue()->findAssociatedFragment(); + MCFragment *FixupFragment = Fixup.getValue()->findAssociatedFragment(); + assert(FixupFragment && "We should have a fragment for this fixup"); + ShouldForce = + !TFragment || TFragment->getParent() != FixupFragment->getParent(); break; } + } break; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index cab2bbcb81bcd..08b75795ed4b1 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -9,6 +9,7 @@ #include "MCTargetDesc/RISCVFixupKinds.h" #include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCObjectWriter.h" @@ -54,7 +55,8 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, if (IsPCRel) { switch (Kind) { default: - llvm_unreachable("invalid fixup kind!"); + Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); + return ELF::R_RISCV_NONE; case FK_Data_4: case FK_PCRel_4: return ELF::R_RISCV_32_PCREL; @@ -87,7 +89,14 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, switch (Kind) { default: - llvm_unreachable("invalid fixup kind!"); + Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); + return ELF::R_RISCV_NONE; + case FK_Data_1: + Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported"); + return ELF::R_RISCV_NONE; + case FK_Data_2: + Ctx.reportError(Fixup.getLoc(), "2-byte data relocations not supported"); + return ELF::R_RISCV_NONE; case FK_Data_4: if (Expr->getKind() == MCExpr::Target && cast<RISCVMCExpr>(Expr)->getKind() == RISCVMCExpr::VK_RISCV_32_PCREL) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp index 8b5fe6dd82526..22bb80ae34e24 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -63,8 +63,9 @@ bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) { return false; } -void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O, - StringRef Annot, const MCSubtargetInfo &STI) { +void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &O) { bool Res = false; const MCInst *NewMI = MI; MCInst UncompressedMI; @@ -73,7 +74,7 @@ void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O, if (Res) NewMI = const_cast<MCInst *>(&UncompressedMI); if (NoAliases || !printAliasInstr(NewMI, STI, O)) - printInstruction(NewMI, STI, O); + printInstruction(NewMI, Address, STI, O); printAnnotation(O, Annot); } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h index 189d72626f3e2..aeb2ea6360605 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h @@ -27,8 +27,8 @@ public: bool applyTargetSpecificCLOption(StringRef Opt) override; - void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, - const MCSubtargetInfo &STI) override; + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override; void printRegName(raw_ostream &O, unsigned RegNo) const override; void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, @@ -43,8 +43,8 @@ public: const MCSubtargetInfo &STI, raw_ostream &O); // Autogenerated by tblgen. - void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI, - raw_ostream &O); + void printInstruction(const MCInst *MI, uint64_t Address, + const MCSubtargetInfo &STI, raw_ostream &O); bool printAliasInstr(const MCInst *MI, const MCSubtargetInfo &STI, raw_ostream &O); void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index ae25ec8181710..7aa9b5e7d6839 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -139,7 +139,11 @@ bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, findAssociatedFragment()->getParent()) return false; - uint64_t AUIPCOffset = AUIPCSymbol->getOffset(); + // We must use TargetFixup rather than AUIPCSymbol here. They will almost + // always have the same offset, except for the case when AUIPCSymbol is at + // the end of a fragment and the fixup comes from offset 0 in the next + // fragment. + uint64_t AUIPCOffset = TargetFixup->getOffset(); Res = MCValue::get(Target.getSymA(), nullptr, Target.getConstant() + (Fixup->getOffset() - AUIPCOffset)); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp index 5a4c86e48f1ef..c37482be3c2c1 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -51,7 +51,8 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) { } static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI, - const Triple &TT) { + const Triple &TT, + const MCTargetOptions &Options) { MCAsmInfo *MAI = new RISCVMCAsmInfo(TT); Register SP = MRI.getDwarfRegNum(RISCV::X2, true); @@ -92,7 +93,7 @@ static MCTargetStreamer *createRISCVAsmTargetStreamer(MCStreamer &S, return new RISCVTargetAsmStreamer(S, OS); } -extern "C" void LLVMInitializeRISCVTargetMC() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); TargetRegistry::RegisterMCInstrInfo(*T, createRISCVMCInstrInfo); diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td index 46530a8f74a88..82afa13aece33 100644 --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -16,45 +16,53 @@ def FeatureStdExtM : SubtargetFeature<"m", "HasStdExtM", "true", "'M' (Integer Multiplication and Division)">; def HasStdExtM : Predicate<"Subtarget->hasStdExtM()">, - AssemblerPredicate<"FeatureStdExtM">; + AssemblerPredicate<"FeatureStdExtM", + "'M' (Integer Multiplication and Division)">; def FeatureStdExtA : SubtargetFeature<"a", "HasStdExtA", "true", "'A' (Atomic Instructions)">; def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">, - AssemblerPredicate<"FeatureStdExtA">; + AssemblerPredicate<"FeatureStdExtA", + "'A' (Atomic Instructions)">; def FeatureStdExtF : SubtargetFeature<"f", "HasStdExtF", "true", "'F' (Single-Precision Floating-Point)">; def HasStdExtF : Predicate<"Subtarget->hasStdExtF()">, - AssemblerPredicate<"FeatureStdExtF">; + AssemblerPredicate<"FeatureStdExtF", + "'F' (Single-Precision Floating-Point)">; def FeatureStdExtD : SubtargetFeature<"d", "HasStdExtD", "true", "'D' (Double-Precision Floating-Point)", [FeatureStdExtF]>; def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">, - AssemblerPredicate<"FeatureStdExtD">; + AssemblerPredicate<"FeatureStdExtD", + "'D' (Double-Precision Floating-Point)">; def FeatureStdExtC : SubtargetFeature<"c", "HasStdExtC", "true", "'C' (Compressed Instructions)">; def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, - AssemblerPredicate<"FeatureStdExtC">; + AssemblerPredicate<"FeatureStdExtC", + "'C' (Compressed Instructions)">; def FeatureRVCHints : SubtargetFeature<"rvc-hints", "EnableRVCHintInstrs", "true", "Enable RVC Hint Instructions.">; def HasRVCHints : Predicate<"Subtarget->enableRVCHintInstrs()">, - AssemblerPredicate<"FeatureRVCHints">; + AssemblerPredicate<"FeatureRVCHints", + "RVC Hint Instructions">; def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; def IsRV64 : Predicate<"Subtarget->is64Bit()">, - AssemblerPredicate<"Feature64Bit">; + AssemblerPredicate<"Feature64Bit", + "RV64I Base Instruction Set">; def IsRV32 : Predicate<"!Subtarget->is64Bit()">, - AssemblerPredicate<"!Feature64Bit">; + AssemblerPredicate<"!Feature64Bit", + "RV32I Base Instruction Set">; def RV64 : HwMode<"+64bit">; def RV32 : HwMode<"-64bit">; @@ -69,6 +77,11 @@ def FeatureRelax : SubtargetFeature<"relax", "EnableLinkerRelax", "true", "Enable Linker relaxation.">; +foreach i = {1-31} in + def FeatureReserveX#i : + SubtargetFeature<"reserve-x"#i, "UserReservedRegister[RISCV::X"#i#"]", + "true", "Reserve X"#i>; + //===----------------------------------------------------------------------===// // Named operands for CSR instructions. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp index 57631dcb5115c..f4aa28bcc0c1b 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -16,6 +16,7 @@ #include "MCTargetDesc/RISCVMCExpr.h" #include "RISCVTargetMachine.h" #include "TargetInfo/RISCVTargetInfo.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -31,6 +32,9 @@ using namespace llvm; #define DEBUG_TYPE "asm-printer" +STATISTIC(RISCVNumInstrsCompressed, + "Number of RISC-V Compressed instructions emitted"); + namespace { class RISCVAsmPrinter : public AsmPrinter { public: @@ -64,6 +68,8 @@ void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, *TM.getMCSubtargetInfo(), OutStreamer->getContext()); + if (Res) + ++RISCVNumInstrsCompressed; AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); } @@ -115,6 +121,14 @@ bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, case MachineOperand::MO_Register: OS << RISCVInstPrinter::getRegisterName(MO.getReg()); return false; + case MachineOperand::MO_GlobalAddress: + PrintSymbolOperand(MO, OS); + return false; + case MachineOperand::MO_BlockAddress: { + MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); + Sym->print(OS, MAI); + return false; + } default: break; } @@ -141,7 +155,7 @@ bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, } // Force static initialization. -extern "C" void LLVMInitializeRISCVAsmPrinter() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target()); RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target()); } diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index da5cd16e750c1..84bce0f485625 100644 --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -319,9 +319,9 @@ static void doMaskedAtomicBinOpExpansion( default: llvm_unreachable("Unexpected AtomicRMW BinOp"); case AtomicRMWInst::Xchg: - BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg) - .addReg(RISCV::X0) - .addReg(IncrReg); + BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg) + .addReg(IncrReg) + .addImm(0); break; case AtomicRMWInst::Add: BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg) diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 6b6f62e18ce96..c60fc3fc6b42b 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/MC/MCDwarf.h" using namespace llvm; @@ -31,6 +32,13 @@ bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const { MFI.isFrameAddressTaken(); } +bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + + return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF); +} + // Determines the size of the frame and maximum call frame size. void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { MachineFrameInfo &MFI = MF.getFrameInfo(); @@ -99,22 +107,15 @@ static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } void RISCVFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { - assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); - MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); const RISCVRegisterInfo *RI = STI.getRegisterInfo(); const RISCVInstrInfo *TII = STI.getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); - if (RI->needsStackRealignment(MF) && MFI.hasVarSizedObjects()) { - report_fatal_error( - "RISC-V backend can't currently handle functions that need stack " - "realignment and have variable sized objects"); - } - Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); + Register BPReg = RISCVABI::getBPReg(); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. @@ -131,6 +132,12 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, if (StackSize == 0 && !MFI.adjustsStack()) return; + // If the stack pointer has been marked as reserved, then produce an error if + // the frame requires stack allocation + if (STI.isRegisterReservedByUser(SPReg)) + MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ + MF.getFunction(), "Stack pointer required, but has been reserved."}); + uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); // Split the SP adjustment to reduce the offsets of callee saved spill. if (FirstSPAdjustAmount) @@ -167,6 +174,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, // Generate new FP. if (hasFP(MF)) { + if (STI.isRegisterReservedByUser(FPReg)) + MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ + MF.getFunction(), "Frame pointer required, but has been reserved."}); + adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); @@ -184,11 +195,16 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, "SecondSPAdjustAmount should be greater than zero"); adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, MachineInstr::FrameSetup); - // Emit ".cfi_def_cfa_offset StackSize" - unsigned CFIIndex = MF.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); - BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); + + // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", + // don't emit an sp-based .cfi_def_cfa_offset + if (!hasFP(MF)) { + // Emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } } if (hasFP(MF)) { @@ -213,21 +229,43 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, .addReg(VR) .addImm(ShiftAmount); } + // FP will be used to restore the frame in the epilogue, so we need + // another base register BP to record SP after re-alignment. SP will + // track the current stack after allocating variable sized objects. + if (hasBP(MF)) { + // move BP, SP + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), BPReg) + .addReg(SPReg) + .addImm(0); + } } } } void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { - MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); const RISCVRegisterInfo *RI = STI.getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); - DebugLoc DL = MBBI->getDebugLoc(); - const RISCVInstrInfo *TII = STI.getInstrInfo(); Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); + // Get the insert location for the epilogue. If there were no terminators in + // the block, get the last instruction. + MachineBasicBlock::iterator MBBI = MBB.end(); + DebugLoc DL; + if (!MBB.empty()) { + MBBI = MBB.getFirstTerminator(); + if (MBBI == MBB.end()) + MBBI = MBB.getLastNonDebugInstr(); + DL = MBBI->getDebugLoc(); + + // If this is not a terminator, the actual insert location should be after the + // last instruction. + if (!MBBI->isTerminator()) + MBBI = std::next(MBBI); + } + // Skip to before the restores of callee-saved registers // FIXME: assumes exactly one instruction is used to restore each // callee-saved register. @@ -253,46 +291,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, MachineInstr::FrameDestroy); - - // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" - unsigned CFIIndex = - MF.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, - -FirstSPAdjustAmount)); - BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } - - 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()) { - Register 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) { - Register 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); } if (FirstSPAdjustAmount) @@ -300,13 +298,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, // 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, @@ -340,12 +331,14 @@ int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, Offset += FirstSPAdjustAmount; else Offset += MF.getFrameInfo().getStackSize(); - } else if (RI->needsStackRealignment(MF)) { - assert(!MFI.hasVarSizedObjects() && - "Unexpected combination of stack realignment and varsized objects"); + } else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { // If the stack was realigned, the frame pointer is set in order to allow - // SP to be restored, but we still access stack objects using SP. - FrameReg = RISCV::X2; + // SP to be restored, so we need another base register to record the stack + // after realignment. + if (hasBP(MF)) + FrameReg = RISCVABI::getBPReg(); + else + FrameReg = RISCV::X2; Offset += MF.getFrameInfo().getStackSize(); } else { FrameReg = RI->getFrameRegister(MF); @@ -367,6 +360,9 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, SavedRegs.set(RISCV::X1); SavedRegs.set(RISCV::X8); } + // Mark BP as used if function has dedicated base pointer. + if (hasBP(MF)) + SavedRegs.set(RISCVABI::getBPReg()); // If interrupt is enabled and there are calls in the handler, // unconditionally save all Caller-saved registers and diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h index f4a5949773d97..3a16cf93cf100 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h @@ -40,6 +40,8 @@ public: bool hasFP(const MachineFunction &MF) const override; + bool hasBP(const MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const override; MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index 1a12d9177d2a6..f66d06c20e377 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -27,7 +27,7 @@ using namespace llvm; // SelectionDAG operations. namespace { class RISCVDAGToDAGISel final : public SelectionDAGISel { - const RISCVSubtarget *Subtarget; + const RISCVSubtarget *Subtarget = nullptr; public: explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine) @@ -173,7 +173,6 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { switch (ConstraintID) { - case InlineAsm::Constraint_i: case InlineAsm::Constraint_m: // We just support simple memory operands that have a single address // operand and need no special handling. diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index dc829fce90136..5a2cffbc824cd 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -30,6 +30,7 @@ #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/IntrinsicsRISCV.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -50,6 +51,20 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, RISCVABI::ABI ABI = Subtarget.getTargetABI(); assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI"); + if ((ABI == RISCVABI::ABI_ILP32F || ABI == RISCVABI::ABI_LP64F) && + !Subtarget.hasStdExtF()) { + 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"; + ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; + } else if ((ABI == RISCVABI::ABI_ILP32D || ABI == RISCVABI::ABI_LP64D) && + !Subtarget.hasStdExtD()) { + 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"; + ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; + } + switch (ABI) { default: report_fatal_error("Don't know how to lower this ABI"); @@ -146,7 +161,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, ISD::SETGE, ISD::SETNE}; ISD::NodeType FPOpToExtend[] = { - ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM}; + ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FP16_TO_FP, + ISD::FP_TO_FP16}; if (Subtarget.hasStdExtF()) { setOperationAction(ISD::FMINNUM, MVT::f32, Legal); @@ -158,6 +174,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::BR_CC, MVT::f32, Expand); for (auto Op : FPOpToExtend) setOperationAction(Op, MVT::f32, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); + setTruncStoreAction(MVT::f32, MVT::f16, Expand); } if (Subtarget.hasStdExtF() && Subtarget.is64Bit()) @@ -175,6 +193,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setTruncStoreAction(MVT::f64, MVT::f32, Expand); for (auto Op : FPOpToExtend) setOperationAction(Op, MVT::f64, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand); + setTruncStoreAction(MVT::f64, MVT::f16, Expand); } setOperationAction(ISD::GlobalAddress, XLenVT, Custom); @@ -188,6 +208,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Subtarget.is64Bit() ? Legal : Custom); + setOperationAction(ISD::TRAP, MVT::Other, Legal); + setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); + if (Subtarget.hasStdExtA()) { setMaxAtomicSizeInBitsSupported(Subtarget.getXLen()); setMinCmpXchgSizeInBits(32); @@ -573,10 +596,7 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, int64_t Offset = N->getOffset(); MVT XLenVT = Subtarget.getXLenVT(); - // Non-PIC TLS lowering should always use the LocalExec model. - TLSModel::Model Model = isPositionIndependent() - ? getTargetMachine().getTLSModel(N->getGlobal()) - : TLSModel::LocalExec; + TLSModel::Model Model = getTargetMachine().getTLSModel(N->getGlobal()); SDValue Addr; switch (Model) { @@ -2010,10 +2030,6 @@ bool RISCVTargetLowering::isEligibleForTailCallOptimization( auto &Caller = MF.getFunction(); auto CallerCC = Caller.getCallingConv(); - // Do not tail call opt functions with "disable-tail-calls" attribute. - if (Caller.getFnAttribute("disable-tail-calls").getValueAsString() == "true") - return false; - // Exception-handling functions need a special set of instructions to // indicate a return to the hardware. Tail-calling another function would // probably break this. @@ -2247,6 +2263,16 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, Glue = Chain.getValue(1); } + // Validate that none of the argument registers have been marked as + // reserved, if so report an error. Do the same for the return address if this + // is not a tailcall. + validateCCReservedRegs(RegsToPass, MF); + if (!IsTailCall && + MF.getSubtarget<RISCVSubtarget>().isRegisterReservedByUser(RISCV::X1)) + MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ + MF.getFunction(), + "Return address register required, but has been reserved."}); + // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. @@ -2362,6 +2388,9 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { + const MachineFunction &MF = DAG.getMachineFunction(); + const RISCVSubtarget &STI = MF.getSubtarget<RISCVSubtarget>(); + // Stores the assignment of the return value to a location. SmallVector<CCValAssign, 16> RVLocs; @@ -2391,6 +2420,13 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, Register RegLo = VA.getLocReg(); assert(RegLo < RISCV::X31 && "Invalid register pair"); Register RegHi = RegLo + 1; + + if (STI.isRegisterReservedByUser(RegLo) || + STI.isRegisterReservedByUser(RegHi)) + MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ + MF.getFunction(), + "Return value register required, but has been reserved."}); + Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue); Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(RegLo, MVT::i32)); @@ -2402,6 +2438,11 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, Val = convertValVTToLocVT(DAG, Val, VA, DL); Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); + if (STI.isRegisterReservedByUser(VA.getLocReg())) + MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ + MF.getFunction(), + "Return value register required, but has been reserved."}); + // Guarantee that all emitted copies are stuck together. Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); @@ -2440,6 +2481,19 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, return DAG.getNode(RISCVISD::RET_FLAG, DL, MVT::Other, RetOps); } +void RISCVTargetLowering::validateCCReservedRegs( + const SmallVectorImpl<std::pair<llvm::Register, llvm::SDValue>> &Regs, + MachineFunction &MF) const { + const Function &F = MF.getFunction(); + const RISCVSubtarget &STI = MF.getSubtarget<RISCVSubtarget>(); + + if (std::any_of(std::begin(Regs), std::end(Regs), [&STI](auto Reg) { + return STI.isRegisterReservedByUser(Reg.first); + })) + F.getContext().diagnose(DiagnosticInfoUnsupported{ + F, "Argument register required, but has been reserved."}); +} + const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((RISCVISD::NodeType)Opcode) { case RISCVISD::FIRST_NUMBER: @@ -2848,3 +2902,22 @@ bool RISCVTargetLowering::shouldExtendTypeInLibCall(EVT Type) const { return true; } + +#define GET_REGISTER_MATCHER +#include "RISCVGenAsmMatcher.inc" + +Register +RISCVTargetLowering::getRegisterByName(const char *RegName, LLT VT, + const MachineFunction &MF) const { + Register Reg = MatchRegisterAltName(RegName); + if (Reg == RISCV::NoRegister) + Reg = MatchRegisterName(RegName); + if (Reg == RISCV::NoRegister) + report_fatal_error( + Twine("Invalid register name \"" + StringRef(RegName) + "\".")); + BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); + if (!ReservedRegs.test(Reg) && !Subtarget.isRegisterReservedByUser(Reg)) + report_fatal_error(Twine("Trying to obtain non-reserved register \"" + + StringRef(RegName) + "\".")); + return Reg; +} diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 18fc7350bbbf7..b2ad75d670249 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -147,6 +147,13 @@ public: bool shouldExtendTypeInLibCall(EVT Type) const override; + /// Returns the register with the specified architectural or ABI name. This + /// method is necessary to lower the llvm.read_register.* and + /// llvm.write_register.* intrinsics. Allocatable registers must be reserved + /// with the clang -ffixed-xX flag for access to be allowed. + Register getRegisterByName(const char *RegName, LLT VT, + const MachineFunction &MF) const override; + private: void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins, @@ -210,6 +217,12 @@ private: Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override; + + /// Generate error diagnostics if any register used by CC has been marked + /// reserved. + void validateCCReservedRegs( + const SmallVectorImpl<std::pair<llvm::Register, llvm::SDValue>> &Regs, + MachineFunction &MF) const; }; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 0848392995309..3b416ce3d3f4d 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -24,6 +24,9 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" +#define GEN_CHECK_COMPRESS_INSTR +#include "RISCVGenCompressInstEmitter.inc" + #define GET_INSTRINFO_CTOR_DTOR #include "RISCVGenInstrInfo.inc" @@ -84,8 +87,8 @@ unsigned RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI, void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL, unsigned DstReg, - unsigned SrcReg, bool KillSrc) const { + const DebugLoc &DL, MCRegister DstReg, + MCRegister SrcReg, bool KillSrc) const { if (RISCV::GPRRegClass.contains(DstReg, SrcReg)) { BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg) .addReg(SrcReg, getKillRegState(KillSrc)) @@ -451,7 +454,18 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { unsigned Opcode = MI.getOpcode(); switch (Opcode) { - default: { return get(Opcode).getSize(); } + default: { + if (MI.getParent() && MI.getParent()->getParent()) { + const auto MF = MI.getMF(); + const auto &TM = static_cast<const RISCVTargetMachine &>(MF->getTarget()); + const MCRegisterInfo &MRI = *TM.getMCRegisterInfo(); + const MCSubtargetInfo &STI = *TM.getMCSubtargetInfo(); + const RISCVSubtarget &ST = MF->getSubtarget<RISCVSubtarget>(); + if (isCompressibleInst(MI, &ST, MRI, STI)) + return 2; + } + return get(Opcode).getSize(); + } case TargetOpcode::EH_LABEL: case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: @@ -542,3 +556,242 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI, return true; } + +// Return true if get the base operand, byte offset of an instruction and the +// memory width. Width is the size of memory that is being loaded/stored. +bool RISCVInstrInfo::getMemOperandWithOffsetWidth( + const MachineInstr &LdSt, const MachineOperand *&BaseReg, int64_t &Offset, + unsigned &Width, const TargetRegisterInfo *TRI) const { + if (!LdSt.mayLoadOrStore()) + return false; + + // Here we assume the standard RISC-V ISA, which uses a base+offset + // addressing mode. You'll need to relax these conditions to support custom + // load/stores instructions. + if (LdSt.getNumExplicitOperands() != 3) + return false; + if (!LdSt.getOperand(1).isReg() || !LdSt.getOperand(2).isImm()) + return false; + + if (!LdSt.hasOneMemOperand()) + return false; + + Width = (*LdSt.memoperands_begin())->getSize(); + BaseReg = &LdSt.getOperand(1); + Offset = LdSt.getOperand(2).getImm(); + return true; +} + +bool RISCVInstrInfo::areMemAccessesTriviallyDisjoint( + const MachineInstr &MIa, const MachineInstr &MIb) const { + assert(MIa.mayLoadOrStore() && "MIa must be a load or store."); + assert(MIb.mayLoadOrStore() && "MIb must be a load or store."); + + if (MIa.hasUnmodeledSideEffects() || MIb.hasUnmodeledSideEffects() || + MIa.hasOrderedMemoryRef() || MIb.hasOrderedMemoryRef()) + return false; + + // Retrieve the base register, offset from the base register and width. Width + // is the size of memory that is being loaded/stored (e.g. 1, 2, 4). If + // base registers are identical, and the offset of a lower memory access + + // the width doesn't overlap the offset of a higher memory access, + // then the memory accesses are different. + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + const MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr; + int64_t OffsetA = 0, OffsetB = 0; + unsigned int WidthA = 0, WidthB = 0; + if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, WidthA, TRI) && + getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, WidthB, TRI)) { + if (BaseOpA->isIdenticalTo(*BaseOpB)) { + int LowOffset = std::min(OffsetA, OffsetB); + int HighOffset = std::max(OffsetA, OffsetB); + int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB; + if (LowOffset + LowWidth <= HighOffset) + return true; + } + } + return false; +} + +std::pair<unsigned, unsigned> +RISCVInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { + const unsigned Mask = RISCVII::MO_DIRECT_FLAG_MASK; + return std::make_pair(TF & Mask, TF & ~Mask); +} + +ArrayRef<std::pair<unsigned, const char *>> +RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { + using namespace RISCVII; + static const std::pair<unsigned, const char *> TargetFlags[] = { + {MO_CALL, "riscv-call"}, + {MO_PLT, "riscv-plt"}, + {MO_LO, "riscv-lo"}, + {MO_HI, "riscv-hi"}, + {MO_PCREL_LO, "riscv-pcrel-lo"}, + {MO_PCREL_HI, "riscv-pcrel-hi"}, + {MO_GOT_HI, "riscv-got-hi"}, + {MO_TPREL_LO, "riscv-tprel-lo"}, + {MO_TPREL_HI, "riscv-tprel-hi"}, + {MO_TPREL_ADD, "riscv-tprel-add"}, + {MO_TLS_GOT_HI, "riscv-tls-got-hi"}, + {MO_TLS_GD_HI, "riscv-tls-gd-hi"}}; + return makeArrayRef(TargetFlags); +} +bool RISCVInstrInfo::isFunctionSafeToOutlineFrom( + MachineFunction &MF, bool OutlineFromLinkOnceODRs) const { + const Function &F = MF.getFunction(); + + // Can F be deduplicated by the linker? If it can, don't outline from it. + if (!OutlineFromLinkOnceODRs && F.hasLinkOnceODRLinkage()) + return false; + + // Don't outline from functions with section markings; the program could + // expect that all the code is in the named section. + if (F.hasSection()) + return false; + + // It's safe to outline from MF. + return true; +} + +bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, + unsigned &Flags) const { + // More accurate safety checking is done in getOutliningCandidateInfo. + return true; +} + +// Enum values indicating how an outlined call should be constructed. +enum MachineOutlinerConstructionID { + MachineOutlinerDefault +}; + +outliner::OutlinedFunction RISCVInstrInfo::getOutliningCandidateInfo( + std::vector<outliner::Candidate> &RepeatedSequenceLocs) const { + + // First we need to filter out candidates where the X5 register (IE t0) can't + // be used to setup the function call. + auto CannotInsertCall = [](outliner::Candidate &C) { + const TargetRegisterInfo *TRI = C.getMF()->getSubtarget().getRegisterInfo(); + + C.initLRU(*TRI); + LiveRegUnits LRU = C.LRU; + return !LRU.available(RISCV::X5); + }; + + RepeatedSequenceLocs.erase(std::remove_if(RepeatedSequenceLocs.begin(), + RepeatedSequenceLocs.end(), + CannotInsertCall), + RepeatedSequenceLocs.end()); + + // If the sequence doesn't have enough candidates left, then we're done. + if (RepeatedSequenceLocs.size() < 2) + return outliner::OutlinedFunction(); + + unsigned SequenceSize = 0; + + auto I = RepeatedSequenceLocs[0].front(); + auto E = std::next(RepeatedSequenceLocs[0].back()); + for (; I != E; ++I) + SequenceSize += getInstSizeInBytes(*I); + + // call t0, function = 8 bytes. + unsigned CallOverhead = 8; + for (auto &C : RepeatedSequenceLocs) + C.setCallInfo(MachineOutlinerDefault, CallOverhead); + + // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled. + unsigned FrameOverhead = 4; + if (RepeatedSequenceLocs[0].getMF()->getSubtarget() + .getFeatureBits()[RISCV::FeatureStdExtC]) + FrameOverhead = 2; + + return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize, + FrameOverhead, MachineOutlinerDefault); +} + +outliner::InstrType +RISCVInstrInfo::getOutliningType(MachineBasicBlock::iterator &MBBI, + unsigned Flags) const { + MachineInstr &MI = *MBBI; + MachineBasicBlock *MBB = MI.getParent(); + const TargetRegisterInfo *TRI = + MBB->getParent()->getSubtarget().getRegisterInfo(); + + // Positions generally can't safely be outlined. + if (MI.isPosition()) { + // We can manually strip out CFI instructions later. + if (MI.isCFIInstruction()) + return outliner::InstrType::Invisible; + + return outliner::InstrType::Illegal; + } + + // Don't trust the user to write safe inline assembly. + if (MI.isInlineAsm()) + return outliner::InstrType::Illegal; + + // We can't outline branches to other basic blocks. + if (MI.isTerminator() && !MBB->succ_empty()) + return outliner::InstrType::Illegal; + + // We need support for tail calls to outlined functions before return + // statements can be allowed. + if (MI.isReturn()) + return outliner::InstrType::Illegal; + + // Don't allow modifying the X5 register which we use for return addresses for + // these outlined functions. + if (MI.modifiesRegister(RISCV::X5, TRI) || + MI.getDesc().hasImplicitDefOfPhysReg(RISCV::X5)) + return outliner::InstrType::Illegal; + + // Make sure the operands don't reference something unsafe. + for (const auto &MO : MI.operands()) + if (MO.isMBB() || MO.isBlockAddress() || MO.isCPI()) + return outliner::InstrType::Illegal; + + // Don't allow instructions which won't be materialized to impact outlining + // analysis. + if (MI.isMetaInstruction()) + return outliner::InstrType::Invisible; + + return outliner::InstrType::Legal; +} + +void RISCVInstrInfo::buildOutlinedFrame( + MachineBasicBlock &MBB, MachineFunction &MF, + const outliner::OutlinedFunction &OF) const { + + // Strip out any CFI instructions + bool Changed = true; + while (Changed) { + Changed = false; + auto I = MBB.begin(); + auto E = MBB.end(); + for (; I != E; ++I) { + if (I->isCFIInstruction()) { + I->removeFromParent(); + Changed = true; + break; + } + } + } + + // Add in a return instruction to the end of the outlined frame. + MBB.insert(MBB.end(), BuildMI(MF, DebugLoc(), get(RISCV::JALR)) + .addReg(RISCV::X0, RegState::Define) + .addReg(RISCV::X5) + .addImm(0)); +} + +MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall( + Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It, + MachineFunction &MF, const outliner::Candidate &C) const { + + // Add in a call instruction to the outlined function at the given location. + It = MBB.insert(It, + BuildMI(MF, DebugLoc(), get(RISCV::PseudoCALLReg), RISCV::X5) + .addGlobalAddress(M.getNamedValue(MF.getName()), 0, + RISCVII::MO_CALL)); + return It; +} diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h index d3ae04aefe04a..625b618751333 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h @@ -34,7 +34,7 @@ public: int &FrameIndex) const override; void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL, unsigned DstReg, unsigned SrcReg, + const DebugLoc &DL, MCRegister DstReg, MCRegister SrcReg, bool KillSrc) const override; void storeRegToStackSlot(MachineBasicBlock &MBB, @@ -86,6 +86,50 @@ public: bool verifyInstruction(const MachineInstr &MI, StringRef &ErrInfo) const override; + bool getMemOperandWithOffsetWidth(const MachineInstr &LdSt, + const MachineOperand *&BaseOp, + int64_t &Offset, unsigned &Width, + const TargetRegisterInfo *TRI) const; + + bool areMemAccessesTriviallyDisjoint(const MachineInstr &MIa, + const MachineInstr &MIb) const override; + + + std::pair<unsigned, unsigned> + decomposeMachineOperandsTargetFlags(unsigned TF) const override; + + ArrayRef<std::pair<unsigned, const char *>> + getSerializableDirectMachineOperandTargetFlags() const override; + + // Return true if the function can safely be outlined from. + virtual bool + isFunctionSafeToOutlineFrom(MachineFunction &MF, + bool OutlineFromLinkOnceODRs) const override; + + // Return true if MBB is safe to outline from, and return any target-specific + // information in Flags. + virtual bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, + unsigned &Flags) const override; + + // Calculate target-specific information for a set of outlining candidates. + outliner::OutlinedFunction getOutliningCandidateInfo( + std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override; + + // Return if/how a given MachineInstr should be outlined. + virtual outliner::InstrType + getOutliningType(MachineBasicBlock::iterator &MBBI, + unsigned Flags) const override; + + // Insert a custom frame for outlined functions. + virtual void + buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF, + const outliner::OutlinedFunction &OF) const override; + + // Insert a call to an outlined function into a given basic block. + virtual MachineBasicBlock::iterator + insertOutlinedCall(Module &M, MachineBasicBlock &MBB, + MachineBasicBlock::iterator &It, MachineFunction &MF, + const outliner::Candidate &C) const override; protected: const RISCVSubtarget &STI; }; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index db2ecc49d14e4..8e9ad49655838 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -636,9 +636,6 @@ def : InstAlias<"jr $rs, $offset", (JALR X0, GPR:$rs, simm12:$offset 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 def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, INSTRET.Encoding, X0)>; @@ -901,7 +898,7 @@ 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 +// PseudoCALLReg 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. @@ -1022,13 +1019,13 @@ defm : StPat<store, SW, GPR>, Requires<[IsRV32]>; // Manual: Volume I. // fence acquire -> fence r, rw -def : Pat<(atomic_fence (XLenVT 4), (imm)), (FENCE 0b10, 0b11)>; +def : Pat<(atomic_fence (XLenVT 4), (timm)), (FENCE 0b10, 0b11)>; // fence release -> fence rw, w -def : Pat<(atomic_fence (XLenVT 5), (imm)), (FENCE 0b11, 0b1)>; +def : Pat<(atomic_fence (XLenVT 5), (timm)), (FENCE 0b11, 0b1)>; // fence acq_rel -> fence.tso -def : Pat<(atomic_fence (XLenVT 6), (imm)), (FENCE_TSO)>; +def : Pat<(atomic_fence (XLenVT 6), (timm)), (FENCE_TSO)>; // fence seq_cst -> fence rw, rw -def : Pat<(atomic_fence (XLenVT 7), (imm)), (FENCE 0b11, 0b11)>; +def : Pat<(atomic_fence (XLenVT 7), (timm)), (FENCE 0b11, 0b11)>; // Lowering for atomic load and store is defined in RISCVInstrInfoA.td. // Although these are lowered to fence+load/store instructions defined in the @@ -1097,6 +1094,16 @@ let Predicates = [IsRV32], usesCustomInserter = 1, hasSideEffects = 0, mayLoad = 0, mayStore = 0, hasNoSchedulingInfo = 1 in def ReadCycleWide : Pseudo<(outs GPR:$lo, GPR:$hi), (ins), [], "", "">; +/// traps + +// We lower `trap` to `unimp`, as this causes a hard exception on nearly all +// systems. +def : Pat<(trap), (UNIMP)>; + +// We lower `debugtrap` to `ebreak`, as this will get the attention of the +// debugger if possible. +def : Pat<(debugtrap), (EBREAK)>; + //===----------------------------------------------------------------------===// // Standard extensions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td index 38ba3f9fb24ed..7321f4bd9d2f1 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td @@ -20,7 +20,7 @@ def AtomicMemOpOperand : AsmOperandClass { let Name = "AtomicMemOpOperand"; let RenderMethod = "addRegOperands"; - let PredicateMethod = "isReg"; + let PredicateMethod = "isGPR"; let ParserMethod = "parseAtomicMemOp"; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td index fe38c4ff02d33..b5343e8a83098 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td @@ -231,6 +231,9 @@ def : Pat<(fabs FPR64:$rs1), (FSGNJX_D $rs1, $rs1)>; def : PatFpr64Fpr64<fcopysign, FSGNJ_D>; def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>; +def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2))>; +def : Pat<(fcopysign FPR32:$rs1, FPR64:$rs2), (FSGNJ_S $rs1, (FCVT_S_D $rs2, + 0b111))>; // fmadd: rs1 * rs2 + rs3 def : Pat<(fma FPR64:$rs1, FPR64:$rs2, FPR64:$rs3), diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp index 66557687c0b62..1d41994ef1e33 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -66,21 +66,35 @@ RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { } BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { - const TargetFrameLowering *TFI = getFrameLowering(MF); + const RISCVFrameLowering *TFI = getFrameLowering(MF); BitVector Reserved(getNumRegs()); + // Mark any registers requested to be reserved as such + for (size_t Reg = 0; Reg < getNumRegs(); Reg++) { + if (MF.getSubtarget<RISCVSubtarget>().isRegisterReservedByUser(Reg)) + markSuperRegs(Reserved, Reg); + } + // Use markSuperRegs to ensure any register aliases are also reserved markSuperRegs(Reserved, RISCV::X0); // zero - markSuperRegs(Reserved, RISCV::X1); // ra markSuperRegs(Reserved, RISCV::X2); // sp markSuperRegs(Reserved, RISCV::X3); // gp markSuperRegs(Reserved, RISCV::X4); // tp if (TFI->hasFP(MF)) markSuperRegs(Reserved, RISCV::X8); // fp + // Reserve the base register if we need to realign the stack and allocate + // variable-sized objects at runtime. + if (TFI->hasBP(MF)) + markSuperRegs(Reserved, RISCVABI::getBPReg()); // bp assert(checkAllSuperRegsMarked(Reserved)); return Reserved; } +bool RISCVRegisterInfo::isAsmClobberable(const MachineFunction &MF, + unsigned PhysReg) const { + return !MF.getSubtarget<RISCVSubtarget>().isRegisterReservedByUser(PhysReg); +} + bool RISCVRegisterInfo::isConstantPhysReg(unsigned PhysReg) const { return PhysReg == RISCV::X0; } diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h index 56a50fe6ddc0c..30b639517fde8 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h @@ -30,6 +30,8 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo { const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; BitVector getReservedRegs(const MachineFunction &MF) const override; + bool isAsmClobberable(const MachineFunction &MF, + unsigned PhysReg) const override; bool isConstantPhysReg(unsigned PhysReg) const override; diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp index f114c6ac1925f..83e7e2d52cc1d 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -50,6 +50,7 @@ RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies( RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef FS, StringRef ABIName, const TargetMachine &TM) : RISCVGenSubtargetInfo(TT, CPU, FS), + UserReservedRegister(RISCV::NUM_TARGET_REGS), FrameLowering(initializeSubtargetDependencies(TT, CPU, FS, ABIName)), InstrInfo(*this), RegInfo(getHwMode()), TLInfo(TM, *this) { CallLoweringInfo.reset(new RISCVCallLowering(*getTargetLowering())); diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h index 7d0373a5253a8..605d4abcc9ae7 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -46,6 +46,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { unsigned XLen = 32; MVT XLenVT = MVT::i32; RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; + BitVector UserReservedRegister; RISCVFrameLowering FrameLowering; RISCVInstrInfo InstrInfo; RISCVRegisterInfo RegInfo; @@ -93,6 +94,10 @@ public: MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } RISCVABI::ABI getTargetABI() const { return TargetABI; } + bool isRegisterReservedByUser(Register i) const { + assert(i < RISCV::NUM_TARGET_REGS && "Register out of range"); + return UserReservedRegister[i]; + } protected: // GlobalISel related APIs. diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index 5ffc6eda6bd7c..2bb26988c7daf 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -25,12 +25,13 @@ #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/InitializePasses.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; -extern "C" void LLVMInitializeRISCVTarget() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() { RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target()); RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target()); auto PR = PassRegistry::getPassRegistry(); @@ -63,9 +64,35 @@ RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT, : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, getEffectiveRelocModel(TT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), - TLOF(std::make_unique<RISCVELFTargetObjectFile>()), - Subtarget(TT, CPU, FS, Options.MCOptions.getABIName(), *this) { + TLOF(std::make_unique<RISCVELFTargetObjectFile>()) { initAsmInfo(); + + // RISC-V supports the MachineOutliner. + setMachineOutliner(true); +} + +const RISCVSubtarget * +RISCVTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + std::string Key = CPU + FS; + auto &I = SubtargetMap[Key]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // creation will depend on the TM and the code generation flags on the + // function that reside in TargetOptions. + resetTargetOptions(F); + I = std::make_unique<RISCVSubtarget>(TargetTriple, CPU, FS, + Options.MCOptions.getABIName(), *this); + } + return I.get(); } TargetTransformInfo diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/llvm/lib/Target/RISCV/RISCVTargetMachine.h index ebf3f3c079557..a4476fa40a7d6 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.h +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.h @@ -22,7 +22,7 @@ namespace llvm { class RISCVTargetMachine : public LLVMTargetMachine { std::unique_ptr<TargetLoweringObjectFile> TLOF; - RISCVSubtarget Subtarget; + mutable StringMap<std::unique_ptr<RISCVSubtarget>> SubtargetMap; public: RISCVTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -30,9 +30,11 @@ public: Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT); - const RISCVSubtarget *getSubtargetImpl(const Function &) const override { - return &Subtarget; - } + const RISCVSubtarget *getSubtargetImpl(const Function &F) const override; + // DO NOT IMPLEMENT: There is no such thing as a valid default subtarget, + // subtargets are per-function entities based on the target-specific + // attributes of each function. + const RISCVSubtarget *getSubtargetImpl() const = delete; TargetPassConfig *createPassConfig(PassManagerBase &PM) override; diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp index 2c6400cbb1eba..90fcd679c5234 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp @@ -29,7 +29,7 @@ int RISCVTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty) { getST()->is64Bit()); } -int RISCVTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, +int RISCVTTIImpl::getIntImmCostInst(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty) { assert(Ty->isIntegerTy() && "getIntImmCost can only estimate cost of materialising integers"); @@ -85,8 +85,8 @@ int RISCVTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, return TTI::TCC_Free; } -int RISCVTTIImpl::getIntImmCost(Intrinsic::ID IID, unsigned Idx, - const APInt &Imm, Type *Ty) { +int RISCVTTIImpl::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, + const APInt &Imm, Type *Ty) { // Prevent hoisting in unknown cases. return TTI::TCC_Free; } diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h index f361b25a0c707..d219ba81bb56b 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h +++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h @@ -42,9 +42,9 @@ public: 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); + int getIntImmCostInst(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty); + int getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, + Type *Ty); }; } // end namespace llvm diff --git a/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp b/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp index e44984a3fcc5b..4f265d556380b 100644 --- a/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp +++ b/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp @@ -20,7 +20,7 @@ Target &llvm::getTheRISCV64Target() { return TheRISCV64Target; } -extern "C" void LLVMInitializeRISCVTargetInfo() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetInfo() { RegisterTarget<Triple::riscv32> X(getTheRISCV32Target(), "riscv32", "32-bit RISC-V", "RISCV"); RegisterTarget<Triple::riscv64> Y(getTheRISCV64Target(), "riscv64", diff --git a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp index bc5395768ca15..432ebb294d464 100644 --- a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp @@ -37,17 +37,8 @@ ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, 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) { + // TODO: move this checking to RISCVTargetLowering and RISCVAsmParser errs() << "Only the ilp32e ABI is supported for RV32E (ignoring target-abi)\n"; TargetABI = ABI_Unknown; @@ -66,6 +57,12 @@ ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, return ABI_LP64; return ABI_ILP32; } + +// To avoid the BP value clobbered by a function call, we need to choose a +// callee saved register to save the value. RV32E only has X8 and X9 as callee +// saved registers and X8 will be used as fp. So we choose X9 as bp. +Register getBPReg() { return RISCV::X9; } + } // namespace RISCVABI namespace RISCVFeatures { diff --git a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h index 30e475e80a01b..cf078df9609a2 100644 --- a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -13,6 +13,7 @@ #ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H #define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H +#include "RISCVRegisterInfo.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -47,20 +48,26 @@ enum { InstFormatMask = 31 }; +// RISC-V Specific Machine Operand Flags 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, + MO_None = 0, + MO_CALL = 1, + MO_PLT = 2, + MO_LO = 3, + MO_HI = 4, + MO_PCREL_LO = 5, + MO_PCREL_HI = 6, + MO_GOT_HI = 7, + MO_TPREL_LO = 8, + MO_TPREL_HI = 9, + MO_TPREL_ADD = 10, + MO_TLS_GOT_HI = 11, + MO_TLS_GD_HI = 12, + + // Used to differentiate between target-specific "direct" flags and "bitmask" + // flags. A machine operand can only have one "direct" flag, but can have + // multiple "bitmask" flags. + MO_DIRECT_FLAG_MASK = 15 }; } // namespace RISCVII @@ -195,6 +202,9 @@ enum ABI { ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, StringRef ABIName); +// Returns the register used to hold the stack pointer after realignment. +Register getBPReg(); + } // namespace RISCVABI namespace RISCVFeatures { |
