Index: include/llvm/CodeGen/MIRParser/MIRParser.h =================================================================== --- include/llvm/CodeGen/MIRParser/MIRParser.h +++ include/llvm/CodeGen/MIRParser/MIRParser.h @@ -19,33 +19,62 @@ #define LLVM_CODEGEN_MIRPARSER_MIRPARSER_H #include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineFunctionInitializer.h" #include "llvm/IR/Module.h" #include "llvm/Support/MemoryBuffer.h" #include namespace llvm { +class MIRParserImpl; class SMDiagnostic; +/// This class initializes machine functions by applying the state loaded from +/// a MIR file. +class MIRParser : public MachineFunctionInitializer { + std::unique_ptr Impl; + +public: + MIRParser(std::unique_ptr Impl); + MIRParser(const MIRParser &) = delete; + ~MIRParser(); + + /// Parse the optional LLVM IR module that's embedded in the MIR file. + /// + /// A new, empty module is created if the LLVM IR isn't present. + /// Returns null if a parsing error occurred. + std::unique_ptr parseLLVMModule(SMDiagnostic &Error); + + /// Initialize the machine function to the state that's described in the MIR + /// file. + /// + /// Return true if error occurred. + bool initializeMachineFunction(MachineFunction &MF) override; +}; + /// This function is the main interface to the MIR serialization format parser. /// -/// It reads a YAML file that has an optional LLVM IR and returns an LLVM -/// module. +/// It reads in a MIR file and returns a MIR parser that can parse the embedded +/// LLVM IR module and initialize the machine functions by parsing the machine +/// function's state. +/// /// \param Filename - The name of the file to parse. /// \param Error - Error result info. -/// \param Context - Context in which to allocate globals info. -std::unique_ptr parseMIRFile(StringRef Filename, SMDiagnostic &Error, - LLVMContext &Context); +/// \param Context - Context which will be used for the parsed LLVM IR module. +std::unique_ptr createMIRParserFromFile(StringRef Filename, + SMDiagnostic &Error, + LLVMContext &Context); /// This function is another interface to the MIR serialization format parser. /// -/// It parses the optional LLVM IR in the given buffer, and returns an LLVM -/// module. +/// It returns a MIR parser that works with the given memory buffer and that can +/// parse the embedded LLVM IR module and initialize the machine functions by +/// parsing the machine function's state. +/// /// \param Contents - The MemoryBuffer containing the machine level IR. -/// \param Error - Error result info. -/// \param Context - Context in which to allocate globals info. -std::unique_ptr parseMIR(std::unique_ptr Contents, - SMDiagnostic &Error, LLVMContext &Context); +/// \param Context - Context which will be used for the parsed LLVM IR module. +std::unique_ptr +createMIRParser(std::unique_ptr Contents, LLVMContext &Context); } // end namespace llvm Index: include/llvm/CodeGen/MachineFunctionAnalysis.h =================================================================== --- include/llvm/CodeGen/MachineFunctionAnalysis.h +++ include/llvm/CodeGen/MachineFunctionAnalysis.h @@ -19,6 +19,7 @@ namespace llvm { class MachineFunction; +class MachineFunctionInitializer; class TargetMachine; /// MachineFunctionAnalysis - This class is a Pass that manages a @@ -28,9 +29,12 @@ const TargetMachine &TM; MachineFunction *MF; unsigned NextFnNum; + MachineFunctionInitializer *MFInitializer; + public: static char ID; - explicit MachineFunctionAnalysis(const TargetMachine &tm); + explicit MachineFunctionAnalysis(const TargetMachine &tm, + MachineFunctionInitializer *MFInitializer); ~MachineFunctionAnalysis() override; MachineFunction &getMF() const { return *MF; } Index: include/llvm/CodeGen/MachineFunctionInitializer.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/MachineFunctionInitializer.h @@ -0,0 +1,38 @@ +//===- MachineFunctionInitalizer.h - machine function initializer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares an interface that allows custom machine function +// initialization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINEFUNCTIONINITIALIZER_H +#define LLVM_CODEGEN_MACHINEFUNCTIONINITIALIZER_H + +namespace llvm { + +class MachineFunction; + +/// This interface provides a way to initialize machine functions after they are +/// created by the machine function analysis pass. +class MachineFunctionInitializer { + virtual void anchor(); + +public: + virtual ~MachineFunctionInitializer() {} + + /// Initialize the machine function. + /// + /// Return true if error occurred. + virtual bool initializeMachineFunction(MachineFunction &MF) = 0; +}; + +} // end namespace llvm + +#endif Index: include/llvm/IR/DiagnosticInfo.h =================================================================== --- include/llvm/IR/DiagnosticInfo.h +++ include/llvm/IR/DiagnosticInfo.h @@ -32,6 +32,7 @@ class Twine; class Value; class DebugLoc; +class SMDiagnostic; /// \brief Defines the different supported severity of a diagnostic. enum DiagnosticSeverity { @@ -56,6 +57,7 @@ DK_OptimizationRemarkMissed, DK_OptimizationRemarkAnalysis, DK_OptimizationFailure, + DK_MIRParser, DK_FirstPluginKind }; @@ -386,6 +388,24 @@ bool isEnabled() const override; }; +/// Diagnostic information for machine IR parser. +class DiagnosticInfoMIRParser : public DiagnosticInfo { + const SMDiagnostic &Diagnostic; + +public: + DiagnosticInfoMIRParser(DiagnosticSeverity Severity, + const SMDiagnostic &Diagnostic) + : DiagnosticInfo(DK_MIRParser, Severity), Diagnostic(Diagnostic) {} + + const SMDiagnostic &getDiagnostic() const { return Diagnostic; } + + void print(DiagnosticPrinter &DP) const override; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_MIRParser; + } +}; + // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef) Index: include/llvm/Target/TargetMachine.h =================================================================== --- include/llvm/Target/TargetMachine.h +++ include/llvm/Target/TargetMachine.h @@ -27,6 +27,7 @@ class InstrItineraryData; class GlobalValue; class Mangler; +class MachineFunctionInitializer; class MCAsmInfo; class MCCodeGenInfo; class MCContext; @@ -208,11 +209,11 @@ /// emitted. Typically this will involve several steps of code generation. /// This method should return true if emission of this file type is not /// supported, or false on success. - virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &, - CodeGenFileType, - bool /*DisableVerify*/ = true, - AnalysisID /*StartAfter*/ = nullptr, - AnalysisID /*StopAfter*/ = nullptr) { + virtual bool addPassesToEmitFile( + PassManagerBase &, raw_pwrite_stream &, CodeGenFileType, + bool /*DisableVerify*/ = true, AnalysisID /*StartAfter*/ = nullptr, + AnalysisID /*StopAfter*/ = nullptr, + MachineFunctionInitializer * /*MFInitializer*/ = nullptr) { return true; } @@ -256,10 +257,11 @@ /// Add passes to the specified pass manager to get the specified file /// emitted. Typically this will involve several steps of code generation. - bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out, - CodeGenFileType FileType, bool DisableVerify = true, - AnalysisID StartAfter = nullptr, - AnalysisID StopAfter = nullptr) override; + bool addPassesToEmitFile( + PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, + bool DisableVerify = true, AnalysisID StartAfter = nullptr, + AnalysisID StopAfter = nullptr, + MachineFunctionInitializer *MFInitializer = nullptr) override; /// Add passes to the specified pass manager to get machine code emitted with /// the MCJIT. This method returns true if machine code is not supported. It Index: lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- lib/CodeGen/LLVMTargetMachine.cpp +++ lib/CodeGen/LLVMTargetMachine.cpp @@ -87,11 +87,11 @@ } /// addPassesToX helper drives creation and initialization of TargetPassConfig. -static MCContext *addPassesToGenerateCode(LLVMTargetMachine *TM, - PassManagerBase &PM, - bool DisableVerify, - AnalysisID StartAfter, - AnalysisID StopAfter) { +static MCContext * +addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM, + bool DisableVerify, AnalysisID StartAfter, + AnalysisID StopAfter, + MachineFunctionInitializer *MFInitializer = nullptr) { // Add internal analysis passes from the target machine. PM.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); @@ -121,7 +121,7 @@ PM.add(MMI); // Set up a MachineFunction for the rest of CodeGen to work on. - PM.add(new MachineFunctionAnalysis(*TM)); + PM.add(new MachineFunctionAnalysis(*TM, MFInitializer)); // Enable FastISel with -fast, but allow that to be overridden. if (EnableFastISelOption == cl::BOU_TRUE || @@ -142,10 +142,11 @@ bool LLVMTargetMachine::addPassesToEmitFile( PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, - bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter) { + bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter, + MachineFunctionInitializer *MFInitializer) { // Add common CodeGen passes. - MCContext *Context = addPassesToGenerateCode(this, PM, DisableVerify, - StartAfter, StopAfter); + MCContext *Context = addPassesToGenerateCode( + this, PM, DisableVerify, StartAfter, StopAfter, MFInitializer); if (!Context) return true; Index: lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIRParser.cpp +++ lib/CodeGen/MIRParser/MIRParser.cpp @@ -14,9 +14,13 @@ #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MIRYamlMapping.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/SMLoc.h" @@ -27,7 +31,7 @@ using namespace llvm; -namespace { +namespace llvm { /// This class implements the parsing of LLVM IR that's embedded inside a MIR /// file. @@ -35,11 +39,19 @@ SourceMgr SM; StringRef Filename; LLVMContext &Context; + StringMap> Functions; public: MIRParserImpl(std::unique_ptr Contents, StringRef Filename, LLVMContext &Context); + void reportDiagnostic(const SMDiagnostic &Diag); + + /// Report an error at the given message. + /// + /// Always returns true. + bool error(const Twine &Message); + /// Try to parse the optional LLVM module and the machine functions in the MIR /// file. /// @@ -51,13 +63,19 @@ /// Return true if an error occurred. bool parseMachineFunction(yaml::Input &In); + /// Initialize the machine function to the state that's described in the MIR + /// file. + /// + /// Return true if error occurred. + bool initializeMachineFunction(MachineFunction &MF); + private: /// Return a MIR diagnostic converted from an LLVM assembly diagnostic. SMDiagnostic diagFromLLVMAssemblyDiag(const SMDiagnostic &Error, SMRange SourceRange); }; -} // end anonymous namespace +} // end namespace llvm MIRParserImpl::MIRParserImpl(std::unique_ptr Contents, StringRef Filename, LLVMContext &Context) @@ -65,13 +83,35 @@ SM.AddNewSourceBuffer(std::move(Contents), SMLoc()); } +bool MIRParserImpl::error(const Twine &Message) { + Context.diagnose(DiagnosticInfoMIRParser( + DS_Error, SMDiagnostic(Filename, SourceMgr::DK_Error, Message.str()))); + return true; +} + +void MIRParserImpl::reportDiagnostic(const SMDiagnostic &Diag) { + DiagnosticSeverity Kind; + switch (Diag.getKind()) { + case SourceMgr::DK_Error: + Kind = DS_Error; + break; + case SourceMgr::DK_Warning: + Kind = DS_Warning; + break; + case SourceMgr::DK_Note: + Kind = DS_Note; + break; + } + Context.diagnose(DiagnosticInfoMIRParser(Kind, Diag)); +} + static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) { - *reinterpret_cast(Context) = Diag; + reinterpret_cast(Context)->reportDiagnostic(Diag); } std::unique_ptr MIRParserImpl::parse(SMDiagnostic &Error) { yaml::Input In(SM.getMemoryBuffer(SM.getMainFileID())->getBuffer(), - /*Ctxt=*/nullptr, handleYAMLDiag, &Error); + /*Ctxt=*/nullptr, handleYAMLDiag, this); if (!In.setCurrentDocument()) { if (!Error.getMessage().empty()) @@ -110,12 +150,21 @@ } bool MIRParserImpl::parseMachineFunction(yaml::Input &In) { - yaml::MachineFunction MF; - yaml::yamlize(In, MF, false); + auto MF = llvm::make_unique(); + yaml::yamlize(In, *MF, false); if (In.error()) return true; - // TODO: Initialize the real machine function with the state in the yaml - // machine function later on. + auto FunctionName = MF->Name; + Functions.insert(std::make_pair(FunctionName, std::move(MF))); + return false; +} + +bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { + auto It = Functions.find(MF.getName()); + if (It == Functions.end()) + return error(Twine("no machine function information for function '") + + MF.getName() + "' in the MIR file"); + // TODO: Recreate the machine function. return false; } @@ -150,22 +199,35 @@ Error.getFixIts()); } -std::unique_ptr llvm::parseMIRFile(StringRef Filename, - SMDiagnostic &Error, - LLVMContext &Context) { +MIRParser::MIRParser(std::unique_ptr Impl) + : Impl(std::move(Impl)) {} + +MIRParser::~MIRParser() {} + +std::unique_ptr MIRParser::parseLLVMModule(SMDiagnostic &Error) { + return Impl->parse(Error); +} + +bool MIRParser::initializeMachineFunction(MachineFunction &MF) { + return Impl->initializeMachineFunction(MF); +} + +std::unique_ptr llvm::createMIRParserFromFile(StringRef Filename, + SMDiagnostic &Error, + LLVMContext &Context) { auto FileOrErr = MemoryBuffer::getFile(Filename); if (std::error_code EC = FileOrErr.getError()) { Error = SMDiagnostic(Filename, SourceMgr::DK_Error, "Could not open input file: " + EC.message()); - return std::unique_ptr(); + return nullptr; } - return parseMIR(std::move(FileOrErr.get()), Error, Context); + return createMIRParser(std::move(FileOrErr.get()), Context); } -std::unique_ptr llvm::parseMIR(std::unique_ptr Contents, - SMDiagnostic &Error, - LLVMContext &Context) { +std::unique_ptr +llvm::createMIRParser(std::unique_ptr Contents, + LLVMContext &Context) { auto Filename = Contents->getBufferIdentifier(); - MIRParserImpl Parser(std::move(Contents), Filename, Context); - return Parser.parse(Error); + return llvm::make_unique( + llvm::make_unique(std::move(Contents), Filename, Context)); } Index: lib/CodeGen/MachineFunction.cpp =================================================================== --- lib/CodeGen/MachineFunction.cpp +++ lib/CodeGen/MachineFunction.cpp @@ -19,6 +19,7 @@ #include "llvm/Analysis/ConstantFolding.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionInitializer.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" @@ -41,6 +42,8 @@ #define DEBUG_TYPE "codegen" +void MachineFunctionInitializer::anchor() {} + //===----------------------------------------------------------------------===// // MachineFunction implementation //===----------------------------------------------------------------------===// Index: lib/CodeGen/MachineFunctionAnalysis.cpp =================================================================== --- lib/CodeGen/MachineFunctionAnalysis.cpp +++ lib/CodeGen/MachineFunctionAnalysis.cpp @@ -15,12 +15,14 @@ #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFunctionInitializer.h" using namespace llvm; char MachineFunctionAnalysis::ID = 0; -MachineFunctionAnalysis::MachineFunctionAnalysis(const TargetMachine &tm) : - FunctionPass(ID), TM(tm), MF(nullptr) { +MachineFunctionAnalysis::MachineFunctionAnalysis( + const TargetMachine &tm, MachineFunctionInitializer *MFInitializer) + : FunctionPass(ID), TM(tm), MF(nullptr), MFInitializer(MFInitializer) { initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry()); } @@ -47,6 +49,8 @@ assert(!MF && "MachineFunctionAnalysis already initialized!"); MF = new MachineFunction(&F, TM, NextFnNum++, getAnalysis()); + if (MFInitializer) + MFInitializer->initializeMachineFunction(*MF); return false; } Index: lib/IR/DiagnosticInfo.cpp =================================================================== --- lib/IR/DiagnosticInfo.cpp +++ lib/IR/DiagnosticInfo.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/Atomic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/SourceMgr.h" #include using namespace llvm; @@ -170,6 +171,13 @@ PassRemarksAnalysisOptLoc.Pattern->match(getPassName()); } +void DiagnosticInfoMIRParser::print(DiagnosticPrinter &DP) const { + std::string Str; + raw_string_ostream StrOS(Str); + Diagnostic.print("", StrOS); + DP << StrOS.str(); +} + void llvm::emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, const Function &Fn, const DebugLoc &DLoc, const Twine &Msg) { Index: lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- lib/Target/CppBackend/CPPBackend.cpp +++ lib/Target/CppBackend/CPPBackend.cpp @@ -2148,7 +2148,8 @@ bool CPPTargetMachine::addPassesToEmitFile( PassManagerBase &PM, raw_pwrite_stream &o, CodeGenFileType FileType, - bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter) { + bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter, + MachineFunctionInitializer *MFInitializer) { if (FileType != TargetMachine::CGFT_AssemblyFile) return true; auto FOut = llvm::make_unique(o); Index: lib/Target/CppBackend/CPPTargetMachine.h =================================================================== --- lib/Target/CppBackend/CPPTargetMachine.h +++ lib/Target/CppBackend/CPPTargetMachine.h @@ -31,8 +31,8 @@ public: bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, bool DisableVerify, - AnalysisID StartAfter, - AnalysisID StopAfter) override; + AnalysisID StartAfter, AnalysisID StopAfter, + MachineFunctionInitializer *MFInitializer) override; }; extern Target TheCppBackendTarget; Index: test/CodeGen/MIR/function-missing-machine-function.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/function-missing-machine-function.mir @@ -0,0 +1,13 @@ +# RUN: not llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s +# This test verifies that an error is reported when a MIR file has some +# function but is missing a corresponding machine function. + +# CHECK: no machine function information for function 'foo' in the MIR file + +--- | + + define i32 @foo() { + ret i32 0 + } + +... Index: test/CodeGen/MIR/llvmIR.mir =================================================================== --- test/CodeGen/MIR/llvmIR.mir +++ test/CodeGen/MIR/llvmIR.mir @@ -30,3 +30,6 @@ } ... +--- +name: foo +... Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -22,6 +22,7 @@ #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" @@ -166,6 +167,22 @@ return FDOut; } +void handleLLVMDiagnostic(const DiagnosticInfo &DI, void *C) { + LLVMContext &Context = *reinterpret_cast(C); + + if (const auto *MIRDiagnostic = cast(&DI)) { + MIRDiagnostic->getDiagnostic().print("", errs()); + if (MIRDiagnostic->getSeverity() != DS_Error) + return; + exit(1); + } + + // Redirect the diagnostic back to the LLVM Context + Context.setDiagnosticHandler(nullptr); + Context.diagnose(DI); + Context.setDiagnosticHandler(handleLLVMDiagnostic, C); +} + // main - Entry point for the llc compiler. // int main(int argc, char **argv) { @@ -176,6 +193,7 @@ EnableDebugBuffering = true; LLVMContext &Context = getGlobalContext(); + Context.setDiagnosticHandler(handleLLVMDiagnostic, &Context); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Initialize targets first, so that --version shows registered targets. @@ -210,6 +228,7 @@ // Load the module to be compiled... SMDiagnostic Err; std::unique_ptr M; + std::unique_ptr MIR; Triple TheTriple; bool SkipModule = MCPU == "help" || @@ -217,9 +236,11 @@ // If user just wants to list available options, skip module loading if (!SkipModule) { - if (StringRef(InputFilename).endswith_lower(".mir")) - M = parseMIRFile(InputFilename, Err, Context); - else + if (StringRef(InputFilename).endswith_lower(".mir")) { + MIR = createMIRParserFromFile(InputFilename, Err, Context); + if (MIR) + M = MIR->parseLLVMModule(Err); + } else M = parseIRFile(InputFilename, Err, Context); if (!M) { Err.print(argv[0], errs()); @@ -350,7 +371,7 @@ // Ask the target to add backend passes as necessary. if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, StartAfterID, - StopAfterID)) { + StopAfterID, MIR.get())) { errs() << argv[0] << ": target does not support generation of this" << " file type!\n"; return 1;