Index: include/llvm/CodeGen/Passes.h =================================================================== --- include/llvm/CodeGen/Passes.h +++ include/llvm/CodeGen/Passes.h @@ -374,6 +374,10 @@ createMachineFunctionPrinterPass(raw_ostream &OS, const std::string &Banner =""); + /// MIRModulePrinting pass - this pass prints out the LLVM IR into the given + /// stream using the MIR serialization format. + ModulePass *createMIRModulePrintingPass(raw_ostream &OS); + /// createCodeGenPreparePass - Transform the code to expose more pattern /// matching during instruction selection. FunctionPass *createCodeGenPreparePass(const TargetMachine *TM = nullptr); @@ -488,6 +492,10 @@ /// MachineFunctionPrinterPass - This pass prints out MachineInstr's. extern char &MachineFunctionPrinterPassID; + /// MIRModulePrintingPass - this pass prints out the LLVM IR using the MIR + /// serialization format. + extern char &MIRModulePrintingPassID; + /// TailDuplicate - Duplicate blocks with unconditional branches /// into tails of their predecessors. extern char &TailDuplicateID; Index: include/llvm/CodeGen/Serialization/Parser.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/Serialization/Parser.h @@ -0,0 +1,57 @@ +//===- Parser.h - MIR serialization format parser -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This MIR serialization library is currently a work in progress. It can't +// serialize machine functions at this time. +// +// This file declares the functions that parse the MIR serialization format +// files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SERIALIZATION_PARSER_H +#define LLVM_CODEGEN_SERIALIZATION_PARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ErrorOr.h" +#include +#include + +namespace llvm { + +class SMDiagnostic; + +/// \brief 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. +/// \param Filename - The name of the file to parse. +/// \param Errs - The array into which the parsing errors are placed. +/// \param Context - Context in which to allocate globals info. +std::unique_ptr parseMIRFile(StringRef Filename, + std::vector &Errs, + LLVMContext &Context); + +/// \brief 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. +/// \param Contents - The MemoryBuffer containing the machine level IR. +/// \param Errs - The array into which the parsing errors are placed. +/// \param Context - Context in which to allocate globals info. +std::unique_ptr parseMIR(std::unique_ptr Contents, + std::vector &Errs, + LLVMContext &Context); + +} // End llvm namespace + +#endif Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -289,6 +289,7 @@ void initializeSLPVectorizerPass(PassRegistry&); void initializeBBVectorizePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); +void initializeMIRModulePrintingPassPass(PassRegistry &); void initializeStackMapLivenessPass(PassRegistry&); void initializeMachineCombinerPass(PassRegistry &); void initializeLoadCombinePass(PassRegistry&); Index: include/llvm/Support/YAMLTraits.h =================================================================== --- include/llvm/Support/YAMLTraits.h +++ include/llvm/Support/YAMLTraits.h @@ -1090,6 +1090,9 @@ bool setCurrentDocument(); bool nextDocument(); + /// \brief Returns the current node that's being parsed by the YAML Parser. + const Node *getCurrentNode(); + private: llvm::SourceMgr SrcMgr; // must be before Strm std::unique_ptr Strm; Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -128,3 +128,4 @@ add_subdirectory(SelectionDAG) add_subdirectory(AsmPrinter) +add_subdirectory(Serialization) Index: lib/CodeGen/LLVMBuild.txt =================================================================== --- lib/CodeGen/LLVMBuild.txt +++ lib/CodeGen/LLVMBuild.txt @@ -16,10 +16,10 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = AsmPrinter SelectionDAG +subdirectories = AsmPrinter SelectionDAG Serialization [component_0] type = Library name = CodeGen parent = Libraries -required_libraries = Analysis Core MC Scalar Support Target TransformUtils +required_libraries = Analysis Core MC Scalar Support Target TransformUtils CodeGenSerialization Index: lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- lib/CodeGen/LLVMTargetMachine.cpp +++ lib/CodeGen/LLVMTargetMachine.cpp @@ -150,12 +150,8 @@ return true; if (StopAfter) { - // FIXME: The intent is that this should eventually write out a YAML file, - // containing the LLVM IR, the machine-level IR (when stopping after a - // machine-level pass), and whatever other information is needed to - // deserialize the code and resume compilation. For now, just write the - // LLVM IR. - PM.add(createPrintModulePass(Out)); + PM.add(createMIRModulePrintingPass(outs())); + // TODO: Print out the machine functions. return false; } Index: lib/CodeGen/Makefile =================================================================== --- lib/CodeGen/Makefile +++ lib/CodeGen/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. LIBRARYNAME = LLVMCodeGen -PARALLEL_DIRS = SelectionDAG AsmPrinter +PARALLEL_DIRS = SelectionDAG AsmPrinter Serialization BUILD_ARCHIVE = 1 include $(LEVEL)/Makefile.common Index: lib/CodeGen/Serialization/CMakeLists.txt =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/CMakeLists.txt @@ -0,0 +1,8 @@ +add_llvm_library(LLVMCodeGenSerialization + YAMLMapping.cpp + MIRPrintingPasses.cpp + Parser.cpp + MIRParser.cpp + ) + +add_dependencies(LLVMCodeGenSerialization intrinsics_gen) Index: lib/CodeGen/Serialization/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/CodeGen/Serialization/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = CodeGenSerialization +parent = CodeGen +required_libraries = Core Support Target AsmParser Index: lib/CodeGen/Serialization/MIRParser.h =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/MIRParser.h @@ -0,0 +1,52 @@ +//===- MIRParser.h - MIR serialization format parser ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the class that parses the optional LLVM IR and machine +// functions that are stored in MIR files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_SERIALIZATION_MIRPARSER_H +#define LLVM_LIB_CODEGEN_SERIALIZATION_MIRPARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace llvm { + +class SMDiagnostic; + +/// \brief This class implements the parsing of LLVM IR that's embedded inside +/// of a MIR file. +class MIRParserImpl { + SourceMgr SM; + StringRef Filename; + LLVMContext &Context; + +public: + MIRParserImpl(std::unique_ptr Contents, StringRef Filename, + LLVMContext &Context); + + /// \brief Try to parse the optional LLVM module in the MIR file. Return null + /// if an error occurred while parsing the LLVM module. + std::unique_ptr parseLLVMModule(std::vector &Errs); + +private: + /// \brief Parse the LLVM module in the given string. + std::unique_ptr parseLLVMModule(StringRef Str, + std::vector &Errs); +}; + +} // End llvm namespace + +#endif Index: lib/CodeGen/Serialization/MIRParser.cpp =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/MIRParser.cpp @@ -0,0 +1,36 @@ +//===- MIRParser.cpp - MIR serialization format parser implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the class that parses the optional LLVM IR and machine +// functions that are stored in MIR files. +// +//===----------------------------------------------------------------------===// + +#include "MIRParser.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MIRParserImpl::MIRParserImpl(std::unique_ptr Contents, + StringRef Filename, LLVMContext &Context) + : SM(), Filename(Filename), Context(Context) { + SM.AddNewSourceBuffer(std::move(Contents), SMLoc()); +} + +std::unique_ptr +MIRParserImpl::parseLLVMModule(StringRef Str, std::vector &Errs) { + SMDiagnostic LLErr; + auto Mod = parseAssembly(MemoryBufferRef(Str, Filename), LLErr, Context); + if (LLErr.getLineNo()) + Errs.push_back(LLErr); + return Mod; +} Index: lib/CodeGen/Serialization/MIRPrintingPasses.cpp =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/MIRPrintingPasses.cpp @@ -0,0 +1,65 @@ +//===- MIRPrintingPasses.cpp - Passes that print out using the MIR format -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass that prints out the LLVM module using the MIR +// serialization format. +// TODO: Implement a pass the prints out the machine functions. +// +//===----------------------------------------------------------------------===// + +#include "YAMLMapping.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +/// MIRModulePrintingPass - This pass prints out the LLVM IR to an output stream +/// using the MIR serialization format. +struct MIRModulePrintingPass : public ModulePass { + static char ID; + raw_ostream &OS; + + MIRModulePrintingPass() : ModulePass(ID), OS(dbgs()) {} + MIRModulePrintingPass(raw_ostream &OS) : ModulePass(ID), OS(OS) {} + + const char *getPassName() const override { + return "MIR Module Printing Pass"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + ModulePass::getAnalysisUsage(AU); + } + + virtual bool runOnModule(Module &M) override { + MIRPrinter Printer(OS); + Printer.printModule(&M); + return false; + } +}; + +char MIRModulePrintingPass::ID = 0; +} + +char &llvm::MIRModulePrintingPassID = MIRModulePrintingPass::ID; +INITIALIZE_PASS(MIRModulePrintingPass, "mir-module-printer", + "MIR Module Printer", false, false) + +namespace llvm { + +ModulePass *createMIRModulePrintingPass(raw_ostream &OS) { + return new MIRModulePrintingPass(OS); +} +} Index: lib/CodeGen/Serialization/Makefile =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/Makefile @@ -0,0 +1,13 @@ +##===- lib/CodeGen/Serialization/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMCodeGenSerialization + +include $(LEVEL)/Makefile.common Index: lib/CodeGen/Serialization/Parser.cpp =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/Parser.cpp @@ -0,0 +1,42 @@ +//===- Parser.cpp - MIR serialization format parser implementation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the functions that parse the MIR serialization format. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/Serialization/Parser.h" +#include "MIRParser.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +std::unique_ptr llvm::parseMIRFile(StringRef Filename, + std::vector &Errs, + LLVMContext &Context) { + auto FileOrErr = MemoryBuffer::getFile(Filename); + if (auto EC = FileOrErr.getError()) { + Errs.push_back(SMDiagnostic(Filename, SourceMgr::DK_Error, + "Could not open input file: " + EC.message())); + return std::unique_ptr(); + } + return parseMIR(std::move(FileOrErr.get()), Errs, Context); +} + +std::unique_ptr llvm::parseMIR(std::unique_ptr Contents, + std::vector &Errs, + LLVMContext &Context) { + auto Filename = Contents->getBufferIdentifier(); + MIRParserImpl Parser(std::move(Contents), Filename, Context); + return Parser.parseLLVMModule(Errs); +} Index: lib/CodeGen/Serialization/YAMLMapping.h =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/YAMLMapping.h @@ -0,0 +1,37 @@ +//===- YAMLMapping.h - Describes the mapping between MIR and YAML ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares some of the utility classes for handling the YAML +// representation of MIR data structures. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_SERIALIZATION_YAMLMAPPING_H +#define LLVM_LIB_CODEGEN_SERIALIZATION_YAMLMAPPING_H + +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { + +class Module; + +/// \brief This class prints out the LLVM IR using the MIR serialization format +/// and YAML I/O. +class MIRPrinter { + raw_ostream &OS; + +public: + MIRPrinter(raw_ostream &OS); + + void printModule(const Module *Mod); +}; + +} // End llvm namespace + +#endif Index: lib/CodeGen/Serialization/YAMLMapping.cpp =================================================================== --- /dev/null +++ lib/CodeGen/Serialization/YAMLMapping.cpp @@ -0,0 +1,65 @@ +//===- YAMLMapping.cpp - Describes the mapping between MIR and YAML -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the mapping between various MIR data structures and +// their corresponding YAML representation. +// +//===----------------------------------------------------------------------===// + +#include "YAMLMapping.h" +#include "MIRParser.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +typedef const Module *ModuleRef; + +namespace llvm { +namespace yaml { + +/// \brief This struct serializes the LLVM IR module. +template <> struct BlockScalarTraits { + static void output(const ModuleRef &Mod, void *Ctxt, raw_ostream &OS) { + Mod->print(OS, nullptr); + } + static StringRef input(StringRef Str, void *Ctxt, ModuleRef &Mod) { + assert(false && "LLVM Module is supposed to be parsed separately"); + return StringRef(); + } +}; +} +} + +MIRPrinter::MIRPrinter(raw_ostream &OS) : OS(OS) {} + +void MIRPrinter::printModule(const Module *Mod) { + yaml::Output Out(OS); + Out << Mod; +} + +std::unique_ptr +MIRParserImpl::parseLLVMModule(std::vector &Errs) { + yaml::Input In(SM.getMemoryBuffer(SM.getMainFileID())->getBuffer()); + + // Parse the block scalar manually so that we can return unique pointer + // without having to go trough YAML traits. + if (In.setCurrentDocument()) { + if (const auto *BSN = + dyn_cast_or_null(In.getCurrentNode())) { + return parseLLVMModule(BSN->getValue(), Errs); + } + } + + // Create an new, empty module. + return llvm::make_unique(Filename, Context); +} Index: lib/Support/YAMLTraits.cpp =================================================================== --- lib/Support/YAMLTraits.cpp +++ lib/Support/YAMLTraits.cpp @@ -97,6 +97,10 @@ return ++DocIterator != Strm->end(); } +const Node *Input::getCurrentNode() { + return CurrentNode ? CurrentNode->_node : nullptr; +} + bool Input::mapTag(StringRef Tag, bool Default) { std::string foundTag = CurrentNode->_node->getVerbatimTag(); if (foundTag.empty()) { Index: test/CodeGen/Generic/stop-after.ll =================================================================== --- test/CodeGen/Generic/stop-after.ll +++ test/CodeGen/Generic/stop-after.ll @@ -1,9 +1,10 @@ ; RUN: llc < %s -debug-pass=Structure -stop-after=loop-reduce -o /dev/null 2>&1 | FileCheck %s -check-prefix=STOP ; RUN: llc < %s -debug-pass=Structure -start-after=loop-reduce -o /dev/null 2>&1 | FileCheck %s -check-prefix=START -; STOP: -loop-reduce -print-module +; STOP: -loop-reduce ; STOP: Loop Strength Reduction ; STOP-NEXT: Machine Function Analysis +; STOP-NEXT: MIR Module Printing Pass ; START: -machine-branch-prob -gc-lowering ; START: FunctionPass Manager Index: test/CodeGen/Serialization/lit.local.cfg =================================================================== --- /dev/null +++ test/CodeGen/Serialization/lit.local.cfg @@ -0,0 +1,2 @@ +config.suffixes = ['.mir'] + Index: test/CodeGen/Serialization/llvmIR.mir =================================================================== --- /dev/null +++ test/CodeGen/Serialization/llvmIR.mir @@ -0,0 +1,35 @@ +# RUN: ~/build/llvm/bin/llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s +# This test ensures that the LLVM IR that's embedded with machine level IR is +# parsed correctly. + +--- | + target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-apple-darwin14.3.0" + + ; CHECK: define i32 @foo(i32 %x, i32 %y) + ; CHECK: %z = alloca i32, align 4 + ; CHECK: store i32 %x, i32* %z, align 4 + ; CHECK: br label %Test + ; CHECK: Test: + ; CHECK: %m = load i32, i32* %z, align 4 + ; CHECK: %cond = icmp eq i32 %y, %m + ; CHECK: br i1 %cond, label %IfEqual, label %IfUnequal + ; CHECK: IfEqual: + ; CHECK: ret i32 1 + ; CHECK: IfUnequal: + ; CHECK: ret i32 0 + define i32 @foo(i32 %x, i32 %y) { + %z = alloca i32, align 4 + store i32 %x, i32* %z, align 4 + br label %Test + Test: + %m = load i32, i32* %z, align 4 + %cond = icmp eq i32 %y, %m + br i1 %cond, label %IfEqual, label %IfUnequal + IfEqual: + ret i32 1 + IfUnequal: + ret i32 0 + } + +... Index: test/CodeGen/Serialization/llvmIRMissing.mir =================================================================== --- /dev/null +++ test/CodeGen/Serialization/llvmIRMissing.mir @@ -0,0 +1,5 @@ +# RUN: ~/build/llvm/bin/llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s +# This test ensures that the MIR parser accepts files without the LLVM IR. + +--- +... Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" +#include "llvm/CodeGen/Serialization/Parser.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" @@ -109,6 +110,8 @@ StringRef IFN = InputFilename; if (IFN.endswith(".bc") || IFN.endswith(".ll")) OutputFilename = IFN.drop_back(3); + else if (IFN.endswith(".mir")) + OutputFilename = IFN.drop_back(4); else OutputFilename = IFN; @@ -206,6 +209,7 @@ static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; + std::vector Errs; std::unique_ptr M; Triple TheTriple; @@ -214,10 +218,19 @@ // If user just wants to list available options, skip module loading if (!SkipModule) { - M = parseIRFile(InputFilename, Err, Context); - if (!M) { - Err.print(argv[0], errs()); - return 1; + if (StringRef(InputFilename).endswith_lower(".mir")) { + M = parseMIRFile(InputFilename, Errs, Context); + if (!M) { + for (const auto &Err : Errs) + Err.print(argv[0], errs()); + return 1; + } + } else { + M = parseIRFile(InputFilename, Err, Context); + if (!M) { + Err.print(argv[0], errs()); + return 1; + } } // Verify module immediately to catch problems before doInitialization() is