Index: test/tools/llvm-mca/ARM/unsupported-write-variant.s =================================================================== --- test/tools/llvm-mca/ARM/unsupported-write-variant.s +++ test/tools/llvm-mca/ARM/unsupported-write-variant.s @@ -0,0 +1,6 @@ +# RUN: not llvm-mca -march=arm -mcpu=swift -all-views=false 2>&1 < %s | FileCheck %s + +add r3, r1, r12, lsl #2 + +# CHECK: error: unable to resolve scheduling class for write variant. +# CHECK-NEXT: note: instruction: add r3, r1, r12, lsl #2 Index: tools/llvm-mca/include/InstrBuilder.h =================================================================== --- tools/llvm-mca/include/InstrBuilder.h +++ tools/llvm-mca/include/InstrBuilder.h @@ -17,7 +17,6 @@ #include "Instruction.h" #include "Support.h" -#include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" @@ -41,7 +40,6 @@ const llvm::MCInstrInfo &MCII; const llvm::MCRegisterInfo &MRI; const llvm::MCInstrAnalysis &MCIA; - llvm::MCInstPrinter &MCIP; llvm::SmallVector ProcResourceMasks; llvm::DenseMap> Descriptors; @@ -66,8 +64,8 @@ public: InstrBuilder(const llvm::MCSubtargetInfo &sti, const llvm::MCInstrInfo &mcii, const llvm::MCRegisterInfo &mri, - const llvm::MCInstrAnalysis &mcia, llvm::MCInstPrinter &mcip) - : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), MCIP(mcip), + const llvm::MCInstrAnalysis &mcia) + : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), ProcResourceMasks(STI.getSchedModel().getNumProcResourceKinds()) { computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); } Index: tools/llvm-mca/include/Support.h =================================================================== --- tools/llvm-mca/include/Support.h +++ tools/llvm-mca/include/Support.h @@ -18,9 +18,30 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCSchedule.h" +#include "llvm/Support/Error.h" namespace mca { +template +class InstructionError : public llvm::ErrorInfo> { +public: + static char ID; + std::string Message; + const T &Inst; + + InstructionError(std::string M, const T &MCI) : Message(M), Inst(MCI) {} + + void log(llvm::raw_ostream &OS) const override { + OS << Message; + } + + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } +}; + +template char InstructionError::ID; + /// This class represents the number of cycles per resource (fractions of /// cycles). That quantity is managed here as a ratio, and accessed via the /// double cast-operator below. The two quantities, number of cycles and Index: tools/llvm-mca/lib/InstrBuilder.cpp =================================================================== --- tools/llvm-mca/lib/InstrBuilder.cpp +++ tools/llvm-mca/lib/InstrBuilder.cpp @@ -215,9 +215,8 @@ } if (CurrentDef != NumExplicitDefs) { - return make_error( - "error: Expected more register operand definitions.", - inconvertibleErrorCode()); + return make_error>( + "Expected more register operand definitions.", MCI); } CurrentDef = 0; @@ -253,11 +252,12 @@ // Always assume that the optional definition is the last operand of the // MCInst sequence. const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1); - if (i == MCI.getNumOperands() || !Op.isReg()) - return make_error( - "error: expected a register operand for an optional " - "definition. Instruction has not be correctly analyzed.", - inconvertibleErrorCode()); + if (i == MCI.getNumOperands() || !Op.isReg()) { + std::string Message = + "expected a register operand for an optional definition. Instruction " + "has not been correctly analyzed."; + return make_error>(Message, MCI); + } WriteDescriptor &Write = ID.Writes[TotalDefs - 1]; Write.OpIndex = MCI.getNumOperands() - 1; @@ -284,9 +284,8 @@ } if (NumExplicitDefs) { - return make_error( - "error: Expected more register operand definitions. ", - inconvertibleErrorCode()); + return make_error>( + "Expected more register operand definitions.", MCI); } unsigned NumExplicitUses = MCI.getNumOperands() - i; @@ -332,23 +331,18 @@ if (!UsesMemory && !UsesBuffers && !UsesResources) return ErrorSuccess(); - std::string ToString; - raw_string_ostream OS(ToString); + std::string Message; if (UsesMemory) { - WithColor::error() << "found an inconsistent instruction that decodes " - << "into zero opcodes and that consumes load/store " - << "unit resources.\n"; + Message = "found an inconsistent instruction that decodes " + "into zero opcodes and that consumes load/store " + "unit resources."; } else { - WithColor::error() << "found an inconsistent instruction that decodes" - << " to zero opcodes and that consumes scheduler " - << "resources.\n"; + Message = "found an inconsistent instruction that decodes" + " to zero opcodes and that consumes scheduler " + "resources."; } - MCIP.printInst(&MCI, OS, "", STI); - OS.flush(); - WithColor::note() << "instruction: " << ToString << '\n'; - return make_error("Invalid instruction definition found", - inconvertibleErrorCode()); + return make_error>(Message, MCI); } Expected @@ -371,24 +365,17 @@ SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID); if (!SchedClassID) { - return make_error("unable to resolve this variant class.", - inconvertibleErrorCode()); + return make_error>( + "unable to resolve scheduling class for write variant.", MCI); } } // Check if this instruction is supported. Otherwise, report an error. const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { - std::string ToString; - 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'; - return make_error( - "Don't know how to analyze unsupported instructions", - inconvertibleErrorCode()); + return make_error>( + "found an unsupported instruction in the input assembly sequence.", + MCI); } // Create a new empty descriptor. Index: tools/llvm-mca/llvm-mca.cpp =================================================================== --- tools/llvm-mca/llvm-mca.cpp +++ tools/llvm-mca/llvm-mca.cpp @@ -35,6 +35,7 @@ #include "Views/TimelineView.h" #include "include/Context.h" #include "include/Pipeline.h" +#include "include/Support.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectFileInfo.h" @@ -326,6 +327,29 @@ processOptionImpl(PrintRetireStats, Default); } +// Returns true on success. +bool runPipeline(mca::Pipeline &P, MCInstPrinter &MCIP, MCSubtargetInfo &STI) { + // Handle pipeline errors here. + if (auto Err = P.run()) { + if (auto NewE = handleErrors( + std::move(Err), + [&MCIP, &STI](const mca::InstructionError &IE) { + std::string InstructionStr; + raw_string_ostream SS(InstructionStr); + WithColor::error() << IE.Message << '\n'; + MCIP.printInst(&IE.Inst, SS, "", STI); + SS.flush(); + WithColor::note() << "instruction: " << InstructionStr << '\n'; + })) { + // Default case. + WithColor::error() << toString(std::move(NewE)); + } + return false; + } + + return true; +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); @@ -462,7 +486,7 @@ Width = DispatchWidth; // Create an instruction builder. - mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA, *IP); + mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA); // Create a context to control ownership of the pipeline hardware. mca::Context MCA(*MRI, *STI); @@ -504,9 +528,10 @@ } Printer.addView( llvm::make_unique(*STI, *IP, S)); - auto Err = P->run(); - if (Err) - report_fatal_error(toString(std::move(Err))); + + if (!runPipeline(*P, *IP, *STI)) + return 1; + Printer.printReport(TOF->os()); continue; } @@ -543,9 +568,9 @@ *STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles)); } - auto Err = P->run(); - if (Err) - report_fatal_error(toString(std::move(Err))); + if (!runPipeline(*P, *IP, *STI)) + return 1; + Printer.printReport(TOF->os()); // Clear the InstrBuilder internal state in preparation for another round.