Index: tools/llvm-mca/DispatchStage.h =================================================================== --- tools/llvm-mca/DispatchStage.h +++ tools/llvm-mca/DispatchStage.h @@ -94,7 +94,7 @@ // RetireStage::hasWorkToComplete will check for that case. virtual bool hasWorkToComplete() const override final { return false; } virtual void cycleStart() override final; - virtual bool execute(InstRef &IR) override final; + virtual llvm::Expected execute(InstRef &IR) override final; void notifyDispatchStall(const InstRef &IR, unsigned EventType); #ifndef NDEBUG Index: tools/llvm-mca/DispatchStage.cpp =================================================================== --- tools/llvm-mca/DispatchStage.cpp +++ tools/llvm-mca/DispatchStage.cpp @@ -136,7 +136,7 @@ CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U; } -bool DispatchStage::execute(InstRef &IR) { +Expected DispatchStage::execute(InstRef &IR) { const InstrDesc &Desc = IR.getInstruction()->getDesc(); if (!isAvailable(Desc.NumMicroOps) || !canDispatch(IR)) return false; Index: tools/llvm-mca/ExecuteStage.h =================================================================== --- tools/llvm-mca/ExecuteStage.h +++ tools/llvm-mca/ExecuteStage.h @@ -46,7 +46,7 @@ virtual bool hasWorkToComplete() const override final { return false; } virtual void cycleStart() override final; - virtual bool execute(InstRef &IR) override final; + virtual llvm::Expected execute(InstRef &IR) override final; void notifyInstructionIssued(const InstRef &IR, Index: tools/llvm-mca/ExecuteStage.cpp =================================================================== --- tools/llvm-mca/ExecuteStage.cpp +++ tools/llvm-mca/ExecuteStage.cpp @@ -96,7 +96,7 @@ } // Schedule the instruction for execution on the hardware. -bool ExecuteStage::execute(InstRef &IR) { +llvm::Expected ExecuteStage::execute(InstRef &IR) { #ifndef NDEBUG // Ensure that the HWS has not stored this instruction in its queues. HWS.sanityCheck(IR); Index: tools/llvm-mca/FetchStage.h =================================================================== --- tools/llvm-mca/FetchStage.h +++ tools/llvm-mca/FetchStage.h @@ -35,7 +35,7 @@ FetchStage &operator=(const FetchStage &Other) = delete; bool hasWorkToComplete() const override final; - bool execute(InstRef &IR) override final; + llvm::Expected execute(InstRef &IR) override final; void postExecute() override final; void cycleEnd() override final; }; Index: tools/llvm-mca/FetchStage.cpp =================================================================== --- tools/llvm-mca/FetchStage.cpp +++ tools/llvm-mca/FetchStage.cpp @@ -19,11 +19,15 @@ bool FetchStage::hasWorkToComplete() const { return SM.hasNext(); } -bool FetchStage::execute(InstRef &IR) { +llvm::Expected FetchStage::execute(InstRef &IR) { if (!SM.hasNext()) return false; const SourceRef SR = SM.peekNext(); - std::unique_ptr I = IB.createInstruction(*SR.second); + llvm::Expected> InstOrErr = + IB.createInstruction(*SR.second); + if (!InstOrErr) + return InstOrErr.takeError(); + std::unique_ptr I = std::move(*InstOrErr); IR = InstRef(SR.first, I.get()); Instructions[IR.getSourceIndex()] = std::move(I); return true; Index: tools/llvm-mca/InstrBuilder.h =================================================================== --- tools/llvm-mca/InstrBuilder.h +++ tools/llvm-mca/InstrBuilder.h @@ -22,6 +22,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Error.h" namespace mca { @@ -49,16 +50,18 @@ llvm::DenseMap> VariantDescriptors; - const InstrDesc &createInstrDescImpl(const llvm::MCInst &MCI); - const InstrDesc &getOrCreateInstrDesc(const llvm::MCInst &MCI); + llvm::Expected + createInstrDescImpl(const llvm::MCInst &MCI); + llvm::Expected + getOrCreateInstrDesc(const llvm::MCInst &MCI); InstrBuilder(const InstrBuilder &) = delete; InstrBuilder &operator=(const InstrBuilder &) = delete; - void populateWrites(InstrDesc &ID, const llvm::MCInst &MCI, - unsigned SchedClassID); - void populateReads(InstrDesc &ID, const llvm::MCInst &MCI, - unsigned SchedClassID); + llvm::Error populateWrites(InstrDesc &ID, const llvm::MCInst &MCI, + unsigned SchedClassID); + llvm::Error populateReads(InstrDesc &ID, const llvm::MCInst &MCI, + unsigned SchedClassID); public: InstrBuilder(const llvm::MCSubtargetInfo &sti, const llvm::MCInstrInfo &mcii, @@ -79,7 +82,8 @@ void clear() { VariantDescriptors.shrink_and_clear(); } - std::unique_ptr createInstruction(const llvm::MCInst &MCI); + llvm::Expected> + createInstruction(const llvm::MCInst &MCI); }; } // namespace mca Index: tools/llvm-mca/InstrBuilder.cpp =================================================================== --- tools/llvm-mca/InstrBuilder.cpp +++ tools/llvm-mca/InstrBuilder.cpp @@ -155,8 +155,8 @@ ID.MaxLatency = Latency < 0 ? 100U : static_cast(Latency); } -void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, - unsigned SchedClassID) { +Error InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, + unsigned SchedClassID) { const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); const MCSchedModel &SM = STI.getSchedModel(); const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); @@ -216,8 +216,9 @@ } if (CurrentDef != NumExplicitDefs) - llvm::report_fatal_error( - "error: Expected more register operand definitions. "); + return make_error( + "error: Expected more register operand definitions.", + inconvertibleErrorCode()); CurrentDef = 0; for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { @@ -253,10 +254,10 @@ // MCInst sequence. const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1); if (i == MCI.getNumOperands() || !Op.isReg()) - llvm::report_fatal_error( + return make_error( "error: expected a register operand for an optional " - "definition. Instruction has not be correctly analyzed.\n", - false); + "definition. Instruction has not be correctly analyzed.", + inconvertibleErrorCode()); WriteDescriptor &Write = ID.Writes[TotalDefs - 1]; Write.OpIndex = MCI.getNumOperands() - 1; @@ -265,10 +266,12 @@ Write.SClassOrWriteResourceID = 0; Write.IsOptionalDef = true; } + + return ErrorSuccess(); } -void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, - unsigned SchedClassID) { +Error InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, + unsigned SchedClassID) { const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); unsigned NumExplicitDefs = MCDesc.getNumDefs(); @@ -281,8 +284,9 @@ } if (NumExplicitDefs) - llvm::report_fatal_error( - "error: Expected more register operand definitions. ", false); + return make_error( + "error: Expected more register operand definitions. ", + inconvertibleErrorCode()); unsigned NumExplicitUses = MCI.getNumOperands() - i; unsigned NumImplicitUses = MCDesc.getNumImplicitUses(); @@ -292,7 +296,7 @@ } unsigned TotalUses = NumExplicitUses + NumImplicitUses; if (!TotalUses) - return; + return ErrorSuccess(); ID.Reads.resize(TotalUses); for (unsigned CurrentUse = 0; CurrentUse < NumExplicitUses; ++CurrentUse) { @@ -313,9 +317,11 @@ LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex << ", RegisterID=" << MRI.getName(Read.RegisterID) << '\n'); } + return ErrorSuccess(); } -const InstrDesc &InstrBuilder::createInstrDescImpl(const MCInst &MCI) { +Expected +InstrBuilder::createInstrDescImpl(const MCInst &MCI) { assert(STI.getSchedModel().hasInstrSchedModel() && "Itineraries are not yet supported!"); @@ -334,22 +340,20 @@ SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID); if (!SchedClassID) - llvm::report_fatal_error("unable to resolve this variant class."); + return make_error("unable to resolve this variant class.", + inconvertibleErrorCode()); } - // Check if this instruction is supported. Otherwise, report a fatal error. + // Check if this instruction is supported. Otherwise, report an error. const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { - std::string ToString; + std::string ToString = "note: instruction: "; llvm::raw_string_ostream OS(ToString); WithColor::error() << "found an unsupported instruction in the input" << " assembly sequence.\n"; MCIP.printInst(&MCI, OS, "", STI); OS.flush(); - - WithColor::note() << "instruction: " << ToString << '\n'; - llvm::report_fatal_error( - "Don't know how to analyze unsupported instructions."); + return make_error(ToString, inconvertibleErrorCode()); } // Create a new empty descriptor. @@ -375,8 +379,10 @@ initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks); computeMaxLatency(*ID, MCDesc, SCDesc, STI); - populateWrites(*ID, MCI, SchedClassID); - populateReads(*ID, MCI, SchedClassID); + if (auto Err = populateWrites(*ID, MCI, SchedClassID)) + return std::move(Err); + if (auto Err = populateReads(*ID, MCI, SchedClassID)) + return std::move(Err); LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n'); LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n'); @@ -392,7 +398,8 @@ return *VariantDescriptors[&MCI]; } -const InstrDesc &InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) { +Expected +InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) { if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end()) return *Descriptors[MCI.getOpcode()]; @@ -402,9 +409,12 @@ return createInstrDescImpl(MCI); } -std::unique_ptr +Expected> InstrBuilder::createInstruction(const MCInst &MCI) { - const InstrDesc &D = getOrCreateInstrDesc(MCI); + Expected ErrOrDesc = getOrCreateInstrDesc(MCI); + if (!ErrOrDesc) + return ErrOrDesc.takeError(); + const InstrDesc &D = *ErrOrDesc; std::unique_ptr NewIS = llvm::make_unique(D); // Initialize Reads first. @@ -433,7 +443,7 @@ // Early exit if there are no writes. if (D.Writes.empty()) - return NewIS; + return std::move(NewIS); // Track register writes that implicitly clear the upper portion of the // underlying super-registers using an APInt. @@ -464,6 +474,6 @@ ++WriteIndex; } - return NewIS; + return std::move(NewIS); } } // namespace mca Index: tools/llvm-mca/InstructionTables.h =================================================================== --- tools/llvm-mca/InstructionTables.h +++ tools/llvm-mca/InstructionTables.h @@ -36,7 +36,7 @@ : Stage(), SM(Model), IB(Builder) {} bool hasWorkToComplete() const override final { return false; } - bool execute(InstRef &IR) override final; + llvm::Expected execute(InstRef &IR) override final; }; } // namespace mca Index: tools/llvm-mca/InstructionTables.cpp =================================================================== --- tools/llvm-mca/InstructionTables.cpp +++ tools/llvm-mca/InstructionTables.cpp @@ -21,7 +21,7 @@ using namespace llvm; -bool InstructionTables::execute(InstRef &IR) { +llvm::Expected InstructionTables::execute(InstRef &IR) { ArrayRef Masks = IB.getProcResourceMasks(); const InstrDesc &Desc = IR.getInstruction()->getDesc(); UsedResources.clear(); Index: tools/llvm-mca/Pipeline.h =================================================================== --- tools/llvm-mca/Pipeline.h +++ tools/llvm-mca/Pipeline.h @@ -19,6 +19,7 @@ #include "Scheduler.h" #include "Stage.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" namespace mca { @@ -60,9 +61,9 @@ unsigned Cycles; void preExecuteStages(); - bool executeStages(InstRef &IR); + llvm::Expected executeStages(InstRef &IR); void postExecuteStages(); - void runCycle(); + llvm::Error runCycle(); bool hasWorkToProcess(); void notifyCycleBegin(); @@ -71,7 +72,7 @@ public: Pipeline() : Cycles(0) {} void appendStage(std::unique_ptr S) { Stages.push_back(std::move(S)); } - void run(); + llvm::Error run(); void addEventListener(HWEventListener *Listener); }; } // namespace mca Index: tools/llvm-mca/Pipeline.cpp =================================================================== --- tools/llvm-mca/Pipeline.cpp +++ tools/llvm-mca/Pipeline.cpp @@ -40,10 +40,14 @@ // This routine returns early if any stage returns 'false' after execute() is // called on it. -bool Pipeline::executeStages(InstRef &IR) { - for (const std::unique_ptr &S : Stages) - if (!S->execute(IR)) +Expected Pipeline::executeStages(InstRef &IR) { + for (const std::unique_ptr &S : Stages) { + Expected BoolOrErr = S->execute(IR); + if (!BoolOrErr) + return BoolOrErr.takeError(); + else if (!*BoolOrErr) return false; + } return true; } @@ -57,16 +61,18 @@ S->postExecute(); } -void Pipeline::run() { +llvm::Error Pipeline::run() { while (hasWorkToProcess()) { notifyCycleBegin(); - runCycle(); + if (llvm::Error Err = runCycle()) + return Err; notifyCycleEnd(); ++Cycles; } + return llvm::ErrorSuccess(); } -void Pipeline::runCycle() { +llvm::Error Pipeline::runCycle() { // Update the stages before we do any processing for this cycle. InstRef IR; for (auto &S : Stages) @@ -76,13 +82,17 @@ // progress. while (true) { preExecuteStages(); - if (!executeStages(IR)) + llvm::Expected Val = executeStages(IR); + if (!Val) + return Val.takeError(); + if (!*Val) break; postExecuteStages(); } for (auto &S : Stages) S->cycleEnd(); + return llvm::ErrorSuccess(); } void Pipeline::notifyCycleBegin() { Index: tools/llvm-mca/RegisterFile.h =================================================================== --- tools/llvm-mca/RegisterFile.h +++ tools/llvm-mca/RegisterFile.h @@ -21,6 +21,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" +#include "llvm/Support/Error.h" namespace mca { @@ -42,7 +43,7 @@ // register file for register renaming purpouses. A value of zero for this // field means: this register file has an unbounded number of physical // registers. - const unsigned NumPhysRegs; + unsigned NumPhysRegs; // Number of physical registers that are currently in use. unsigned NumUsedPhysRegs; @@ -155,7 +156,11 @@ // // Current implementation can simulate up to 32 register files (including the // special register file at index #0). - unsigned isAvailable(llvm::ArrayRef Regs) const; + // + // In the case that the instruction requires more than the number of + // registers in a register file, a warning is issued and the register file is + // adjusted to accommodate the register count of the instruction. + unsigned isAvailable(llvm::ArrayRef Regs); void collectWrites(llvm::SmallVectorImpl &Writes, unsigned RegID) const; void updateOnRead(ReadState &RS, unsigned RegID); Index: tools/llvm-mca/RegisterFile.cpp =================================================================== --- tools/llvm-mca/RegisterFile.cpp +++ tools/llvm-mca/RegisterFile.cpp @@ -17,6 +17,7 @@ #include "RegisterFile.h" #include "Instruction.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/WithColor.h" using namespace llvm; @@ -276,7 +277,7 @@ }); } -unsigned RegisterFile::isAvailable(ArrayRef Regs) const { +unsigned RegisterFile::isAvailable(ArrayRef Regs) { SmallVector NumPhysRegs(getNumRegisterFiles()); // Find how many new mappings must be created for each register file. @@ -306,8 +307,10 @@ // microarchitectural registers in register file #0 was changed by the // users via flag -reg-file-size. Alternatively, the scheduling model // specified a too small number of registers for this register file. - report_fatal_error( - "Not enough microarchitectural registers in the register file"); + WithColor::warning() + << "Not enough microarchitectural registers in register file " << I + << ". Increasing register file to " << NumRegs << " registers.\n"; + RegisterFiles[I].NumPhysRegs = NumRegs; } if (RMT.NumPhysRegs < (RMT.NumUsedPhysRegs + NumRegs)) Index: tools/llvm-mca/RetireStage.h =================================================================== --- tools/llvm-mca/RetireStage.h +++ tools/llvm-mca/RetireStage.h @@ -38,7 +38,9 @@ return !RCU.isEmpty(); } virtual void cycleStart() override final; - virtual bool execute(InstRef &IR) override final { return true; } + virtual llvm::Expected execute(InstRef &IR) override final { + return true; + } void notifyInstructionRetired(const InstRef &IR); void onInstructionExecuted(unsigned TokenID); }; Index: tools/llvm-mca/Stage.h =================================================================== --- tools/llvm-mca/Stage.h +++ tools/llvm-mca/Stage.h @@ -17,6 +17,7 @@ #define LLVM_TOOLS_LLVM_MCA_STAGE_H #include "HWEventListener.h" +#include "llvm/Support/Error.h" #include namespace mca { @@ -60,7 +61,7 @@ /// The primary action that this stage performs. /// Returning false prevents successor stages from having their 'execute' /// routine called. This can be called multiple times during a single cycle. - virtual bool execute(InstRef &IR) = 0; + virtual llvm::Expected execute(InstRef &IR) = 0; /// Add a listener to receive callbacks during the execution of this stage. void addListener(HWEventListener *Listener); Index: tools/llvm-mca/llvm-mca.cpp =================================================================== --- tools/llvm-mca/llvm-mca.cpp +++ tools/llvm-mca/llvm-mca.cpp @@ -42,6 +42,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -502,7 +503,11 @@ } Printer.addView( llvm::make_unique(*STI, *IP, S)); - P->run(); + auto Err = P->run(); + if (Err) { + report_fatal_error(toString(std::move(Err))); + return -1; + } Printer.printReport(TOF->os()); continue; } @@ -539,7 +544,11 @@ *STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles)); } - P->run(); + auto Err = P->run(); + if (Err) { + report_fatal_error(toString(std::move(Err))); + return -1; + } Printer.printReport(TOF->os()); // Clear the InstrBuilder internal state in preparation for another round.