Index: test/tools/llvm-mca/X86/BtVer2/unsupported-instruction.s =================================================================== --- test/tools/llvm-mca/X86/BtVer2/unsupported-instruction.s +++ test/tools/llvm-mca/X86/BtVer2/unsupported-instruction.s @@ -2,5 +2,4 @@ bzhi %eax, %ebx, %ecx -# CHECK: error: found an unsupported instruction in the input assembly sequence. -# CHECK-NEXT: note: instruction: bzhil %eax, %ebx, %ecx +# CHECK: LLVM ERROR: Found an unsupported instruction in the input assembly sequence: bzhil %eax, %ebx, %ecx Index: tools/llvm-mca/Context.h =================================================================== --- tools/llvm-mca/Context.h +++ tools/llvm-mca/Context.h @@ -21,6 +21,7 @@ #include "InstrBuilder.h" #include "Pipeline.h" #include "SourceMgr.h" +#include "Status.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -42,7 +43,7 @@ bool AssumeNoAlias; }; -class Context { +class Context : public StatusManager { llvm::SmallVector, 4> Hardware; const llvm::MCRegisterInfo &MRI; const llvm::MCSubtargetInfo &STI; Index: tools/llvm-mca/Context.cpp =================================================================== --- tools/llvm-mca/Context.cpp +++ tools/llvm-mca/Context.cpp @@ -35,7 +35,8 @@ // Create the hardware units defining the backend. auto RCU = llvm::make_unique(SM); - auto PRF = llvm::make_unique(SM, MRI, Opts.RegisterFileSize); + auto PRF = + llvm::make_unique(SM, MRI, *this, Opts.RegisterFileSize); auto HWS = llvm::make_unique( SM, Opts.LoadQueueSize, Opts.StoreQueueSize, Opts.AssumeNoAlias); Index: tools/llvm-mca/InstrBuilder.h =================================================================== --- tools/llvm-mca/InstrBuilder.h +++ tools/llvm-mca/InstrBuilder.h @@ -25,6 +25,7 @@ namespace mca { +class Context; class DispatchUnit; /// A builder class that knows how to construct Instruction objects. @@ -43,6 +44,7 @@ const llvm::MCRegisterInfo &MRI; const llvm::MCInstrAnalysis &MCIA; llvm::MCInstPrinter &MCIP; + mca::Context &Ctx; llvm::SmallVector ProcResourceMasks; llvm::DenseMap> Descriptors; @@ -61,8 +63,9 @@ 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, llvm::MCInstPrinter &mcip, + mca::Context &ctx) + : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), MCIP(mcip), Ctx(ctx), ProcResourceMasks(STI.getSchedModel().getNumProcResourceKinds()) { computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); } Index: tools/llvm-mca/InstrBuilder.cpp =================================================================== --- tools/llvm-mca/InstrBuilder.cpp +++ tools/llvm-mca/InstrBuilder.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "InstrBuilder.h" +#include "Context.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCInst.h" @@ -216,8 +217,7 @@ } if (CurrentDef != NumExplicitDefs) - llvm::report_fatal_error( - "error: Expected more register operand definitions. "); + Ctx.notifyFatalError("Expected more register operand definitions."); CurrentDef = 0; for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { @@ -253,10 +253,9 @@ // MCInst sequence. const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1); if (i == MCI.getNumOperands() || !Op.isReg()) - llvm::report_fatal_error( - "error: expected a register operand for an optional " - "definition. Instruction has not be correctly analyzed.\n", - false); + Ctx.notifyFatalError( + "Expected a register operand for an optional " + "definition. Instruction has not be correctly analyzed."); WriteDescriptor &Write = ID.Writes[TotalDefs - 1]; Write.OpIndex = MCI.getNumOperands() - 1; @@ -281,8 +280,7 @@ } if (NumExplicitDefs) - llvm::report_fatal_error( - "error: Expected more register operand definitions. ", false); + Ctx.notifyFatalError("Expected more register operand definitions."); unsigned NumExplicitUses = MCI.getNumOperands() - i; unsigned NumImplicitUses = MCDesc.getNumImplicitUses(); @@ -334,7 +332,7 @@ SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID); if (!SchedClassID) - llvm::report_fatal_error("unable to resolve this variant class."); + Ctx.notifyFatalError("Unable to resolve this variant class."); } // Check if this instruction is supported. Otherwise, report a fatal error. @@ -342,14 +340,11 @@ if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { std::string ToString; 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."); + Ctx.notifyFatalError( + "Found an unsupported instruction in the input assembly sequence: " + + ToString); } // Create a new empty descriptor. Index: tools/llvm-mca/RegisterFile.h =================================================================== --- tools/llvm-mca/RegisterFile.h +++ tools/llvm-mca/RegisterFile.h @@ -24,6 +24,7 @@ namespace mca { +class Context; class ReadState; class WriteState; class WriteRef; @@ -32,6 +33,7 @@ /// register renaming purposes. class RegisterFile : public HardwareUnit { const llvm::MCRegisterInfo &MRI; + Context &Ctx; // Each register file is associated with an instance of // RegisterMappingTracker. @@ -130,7 +132,7 @@ public: RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri, - unsigned NumRegs = 0); + Context &C, unsigned NumRegs = 0); // This method updates the register mappings inserting a new register // definition. This method is also responsible for updating the number of Index: tools/llvm-mca/RegisterFile.cpp =================================================================== --- tools/llvm-mca/RegisterFile.cpp +++ tools/llvm-mca/RegisterFile.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "RegisterFile.h" +#include "Context.h" #include "Instruction.h" #include "llvm/Support/Debug.h" @@ -25,9 +26,11 @@ namespace mca { RegisterFile::RegisterFile(const llvm::MCSchedModel &SM, - const llvm::MCRegisterInfo &mri, unsigned NumRegs) - : MRI(mri), RegisterMappings(mri.getNumRegs(), - {WriteRef(), {IndexPlusCostPairTy(0, 1), 0}}) { + const llvm::MCRegisterInfo &mri, Context &C, + unsigned NumRegs) + : MRI(mri), Ctx(C), + RegisterMappings(mri.getNumRegs(), + {WriteRef(), {IndexPlusCostPairTy(0, 1), 0}}) { initialize(SM, NumRegs); } @@ -306,7 +309,7 @@ // 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( + Ctx.notifyFatalError( "Not enough microarchitectural registers in the register file"); } Index: tools/llvm-mca/Status.h =================================================================== --- /dev/null +++ tools/llvm-mca/Status.h @@ -0,0 +1,108 @@ +//===----------------------------- Status.h ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides the status handling functionality of llvm-mca. +/// Included here are the handlers and message type for reporting warnings and +/// errors within llvm-mca. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_STATUS_H +#define LLVM_TOOLS_LLVM_MCA_STATUS_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include +#include + +namespace mca { + +/// The following class defines the most basic level of messages +/// communicated across the llvm-mca status handling framework. The handlers +/// can choose how to display these message and if additional action should be +/// taken (e.g., calling exit or aborting). +class StatusMessage { + std::string M; + +public: + StatusMessage(const char *Message) : M(Message) {} + StatusMessage(std::string Message) : M(Message) {} + llvm::StringRef getMessage() const { return M; } +}; + +using StatusCallback = std::function; + +/// Each status type (error, warning, etc.) has an associated handler. +/// This class contains the callback routine that is triggered when +/// a status event of type 'HandlerType' occurs. +enum HandlerType { Error, FatalError, Note, Warning }; +class StatusHandler { + StatusCallback CB; + HandlerType Type; + +public: + StatusHandler(StatusCallback &Fn, HandlerType T) : CB(Fn), Type(T) {} + void operator()(const StatusMessage &SM) { CB(SM); } + HandlerType getType() const { return Type; } +}; + +/// This class contains the handlers used for communicating error messages. +/// The notifyX methods are to be used to notify the handlers of a particular +/// status change within the framework. +class StatusManager { + std::vector> Handlers; + + void notify(const StatusMessage &M, HandlerType T) { + bool IssuedCallback = false; + for (auto &H : Handlers) { + if (H->getType() == T) { + (*H)(M); + IssuedCallback = true; + } + } + // If a notification was requested but no registered handler + // for that type of status notification exists, then assert. + assert(IssuedCallback && "No handlers found for notification type."); + } + +public: + void notifyFatalError(const StatusMessage &M) { + notify(M, HandlerType::FatalError); + } + + void registerHandler(std::unique_ptr S) { + Handlers.push_back(std::move(S)); + } + + void registerHandler(StatusHandler S) { + registerHandler(llvm::make_unique(S)); + } + + void registerErrorHandler(StatusCallback CB) { + registerHandler(StatusHandler(CB, HandlerType::Error)); + } + + void registerFatalErrorHandler(StatusCallback CB) { + registerHandler(StatusHandler(CB, HandlerType::FatalError)); + } + + void registerNoteHandler(StatusCallback CB) { + registerHandler(StatusHandler(CB, HandlerType::Note)); + } + + void registerWarningHandler(StatusCallback CB) { + registerHandler(StatusHandler(CB, HandlerType::Warning)); + } +}; + +} // namespace mca + +#endif // LLVM_TOOLS_LLVM_MCA_STATUS_H Index: tools/llvm-mca/llvm-mca.cpp =================================================================== --- tools/llvm-mca/llvm-mca.cpp +++ tools/llvm-mca/llvm-mca.cpp @@ -33,6 +33,7 @@ #include "ResourcePressureView.h" #include "RetireControlUnitStatistics.h" #include "SchedulerStatistics.h" +#include "Status.h" #include "SummaryView.h" #include "TimelineView.h" #include "llvm/MC/MCAsmInfo.h" @@ -459,14 +460,24 @@ if (DispatchWidth) Width = DispatchWidth; - // Create an instruction builder. - mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA, *IP); - // Create a context to control ownership of the pipeline hardware. mca::Context MCA(*MRI, *STI); + // Register a callback routine for handling fatal errors. + MCA.registerFatalErrorHandler([](const mca::StatusMessage &M) { + llvm::report_fatal_error(M.getMessage()); + }); + + // Register a callback routine for handling warnings. + MCA.registerWarningHandler([](const mca::StatusMessage &M){ + llvm::WithColor::warning() << M.getMessage() << '\n'; + }); + mca::PipelineOptions PO(Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias); + + // Create an instruction builder. + mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA, *IP, MCA); // Number each region in the sequence. unsigned RegionIdx = 0;