Index: include/llvm/CodeGen/MIR/MIRParser.h =================================================================== --- include/llvm/CodeGen/MIR/MIRParser.h +++ include/llvm/CodeGen/MIR/MIRParser.h @@ -21,11 +21,40 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/Module.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" #include namespace llvm { -class SMDiagnostic; +class MachineFunction; +class MIRParserImpl; + +/// This class initializes machine functions by applying the state loaded from +/// a MIR file. +class MIRParser { + std::unique_ptr Impl; + SMDiagnostic Error; + +public: + MIRParser(std::unique_ptr Impl); + MIRParser(const MIRParser &) = delete; + ~MIRParser(); + + /// Initialize the machine function to the state that's described in the MIR + /// file. + /// + /// Return true if error occurred. + bool initializeMachineFunction(MachineFunction &MF); + + /// Return true if the machine function initialization failed during the + /// machine function analysis pass. + bool failed() const { return !Error.getMessage().empty(); } + + const SMDiagnostic &error() const { return Error; } +}; + +typedef std::pair, std::unique_ptr> + MIRParseResult; /// This function is the main interface to the MIR serialization format parser. /// @@ -34,8 +63,8 @@ /// \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); +MIRParseResult parseMIRFile(StringRef Filename, SMDiagnostic &Error, + LLVMContext &Context); /// This function is another interface to the MIR serialization format parser. /// @@ -44,8 +73,8 @@ /// \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); +MIRParseResult parseMIR(std::unique_ptr Contents, + SMDiagnostic &Error, 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 MIRParser; class TargetMachine; /// MachineFunctionAnalysis - This class is a Pass that manages a @@ -28,9 +29,11 @@ const TargetMachine &TM; MachineFunction *MF; unsigned NextFnNum; + MIRParser *MIR; + public: static char ID; - explicit MachineFunctionAnalysis(const TargetMachine &tm); + explicit MachineFunctionAnalysis(const TargetMachine &tm, MIRParser *MIR); ~MachineFunctionAnalysis() override; MachineFunction &getMF() const { return *MF; } 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 MIRParser; class MCAsmInfo; class MCCodeGenInfo; class MCContext; @@ -212,7 +213,8 @@ CodeGenFileType, bool /*DisableVerify*/ = true, AnalysisID /*StartAfter*/ = nullptr, - AnalysisID /*StopAfter*/ = nullptr) { + AnalysisID /*StopAfter*/ = nullptr, + MIRParser * /*MIR*/ = nullptr) { return true; } @@ -259,7 +261,8 @@ bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, bool DisableVerify = true, AnalysisID StartAfter = nullptr, - AnalysisID StopAfter = nullptr) override; + AnalysisID StopAfter = nullptr, + MIRParser *MIR = 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,10 @@ } /// 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, MIRParser *MIR = nullptr) { // Add internal analysis passes from the target machine. PM.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); @@ -121,7 +120,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, MIR)); // Enable FastISel with -fast, but allow that to be overridden. if (EnableFastISelOption == cl::BOU_TRUE || @@ -142,10 +141,11 @@ bool LLVMTargetMachine::addPassesToEmitFile( PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, - bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter) { + bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter, + MIRParser *MIR) { // Add common CodeGen passes. MCContext *Context = addPassesToGenerateCode(this, PM, DisableVerify, - StartAfter, StopAfter); + StartAfter, StopAfter, MIR); if (!Context) return true; Index: lib/CodeGen/MIR/MIRParser.cpp =================================================================== --- lib/CodeGen/MIR/MIRParser.cpp +++ lib/CodeGen/MIR/MIRParser.cpp @@ -15,8 +15,10 @@ #include "llvm/CodeGen/MIR/MIRParser.h" #include "YAMLMapping.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/IR/Module.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" @@ -26,7 +28,7 @@ using namespace llvm; -namespace { +namespace llvm { /// This class implements the parsing of LLVM IR that's embedded inside a MIR /// file. @@ -34,6 +36,7 @@ SourceMgr SM; StringRef Filename; LLVMContext &Context; + StringMap> Functions; public: MIRParserImpl(std::unique_ptr Contents, StringRef Filename, @@ -49,9 +52,15 @@ /// /// 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, SMDiagnostic &Error); }; -} // end anonymous namespace +} // end namespace llvm MIRParserImpl::MIRParserImpl(std::unique_ptr Contents, StringRef Filename, LLVMContext &Context) @@ -102,31 +111,57 @@ } 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, + SMDiagnostic &Error) { + auto It = Functions.find(MF.getName()); + if (It == Functions.end()) { + auto Message = (Twine("No machine function information for function '") + + MF.getName() + "' in the MIR file") + .str(); + Error = SMDiagnostic(Filename, SourceMgr::DK_Error, Message); + return true; + } + // TODO: Recreate the machine function. return false; } -std::unique_ptr llvm::parseMIRFile(StringRef Filename, - SMDiagnostic &Error, - LLVMContext &Context) { +MIRParser::MIRParser(std::unique_ptr Impl) + : Impl(std::move(Impl)) {} + +MIRParser::~MIRParser() {} + +bool MIRParser::initializeMachineFunction(MachineFunction &MF) { + return Impl->initializeMachineFunction(MF, Error); +} + +MIRParseResult llvm::parseMIRFile(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 MIRParseResult(); } return parseMIR(std::move(FileOrErr.get()), Error, Context); } -std::unique_ptr llvm::parseMIR(std::unique_ptr Contents, - SMDiagnostic &Error, - LLVMContext &Context) { +MIRParseResult llvm::parseMIR(std::unique_ptr Contents, + SMDiagnostic &Error, LLVMContext &Context) { auto Filename = Contents->getBufferIdentifier(); - MIRParserImpl Parser(std::move(Contents), Filename, Context); - return Parser.parse(Error); + auto Parser = + llvm::make_unique(std::move(Contents), Filename, Context); + auto Mod = Parser->parse(Error); + if (!Mod) + return MIRParseResult(); + return std::make_pair(std::move(Mod), + llvm::make_unique(std::move(Parser))); } 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/MIR/MIRParser.h" using namespace llvm; char MachineFunctionAnalysis::ID = 0; -MachineFunctionAnalysis::MachineFunctionAnalysis(const TargetMachine &tm) : - FunctionPass(ID), TM(tm), MF(nullptr) { +MachineFunctionAnalysis::MachineFunctionAnalysis(const TargetMachine &tm, + MIRParser *MIR) + : FunctionPass(ID), TM(tm), MF(nullptr), MIR(MIR) { initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry()); } @@ -47,6 +49,8 @@ assert(!MF && "MachineFunctionAnalysis already initialized!"); MF = new MachineFunction(&F, TM, NextFnNum++, getAnalysis()); + if (MIR) + MIR->initializeMachineFunction(*MF); return false; } Index: lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- lib/Target/CppBackend/CPPBackend.cpp +++ lib/Target/CppBackend/CPPBackend.cpp @@ -2151,7 +2151,8 @@ bool CPPTargetMachine::addPassesToEmitFile( PassManagerBase &PM, raw_pwrite_stream &o, CodeGenFileType FileType, - bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter) { + bool DisableVerify, AnalysisID StartAfter, AnalysisID StopAfter, + MIRParser *MIR) { 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, + MIRParser *MIR) 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 @@ -210,6 +210,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 +218,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")) { + auto ParseResult = parseMIRFile(InputFilename, Err, Context); + M = std::move(ParseResult.first); + MIR = std::move(ParseResult.second); + } else M = parseIRFile(InputFilename, Err, Context); if (!M) { Err.print(argv[0], errs()); @@ -349,7 +352,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; @@ -361,6 +364,13 @@ PM.run(*M); } + // Check if machine function loading failed in the machine function analysis + // pass. + if (MIR && MIR->failed()) { + MIR->error().print(argv[0], errs()); + return 1; + } + // Declare success. Out->keep();