diff --git a/llvm/include/llvm/CodeGen/MIR/MIRParser.h b/llvm/include/llvm/CodeGen/MIR/MIRParser.h new file mode 100644 index 0000000000000..8c1403439adff --- /dev/null +++ b/llvm/include/llvm/CodeGen/MIR/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 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_MIR_MIRPARSER_H +#define LLVM_CODEGEN_MIR_MIRPARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace llvm { + +class SMDiagnostic; + +/// 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 Error - Error result info. +/// \param Context - Context in which to allocate globals info. +std::unique_ptr parseMIRFile(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. +/// \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); + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 39f69549d7cf3..9671459458eff 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -374,6 +374,10 @@ namespace llvm { createMachineFunctionPrinterPass(raw_ostream &OS, const std::string &Banner =""); + /// MIRPrinting pass - this pass prints out the LLVM IR into the given stream + /// using the MIR serialization format. + MachineFunctionPass *createPrintMIRPass(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 @@ namespace llvm { /// MachineFunctionPrinterPass - This pass prints out MachineInstr's. extern char &MachineFunctionPrinterPassID; + /// MIRPrintingPass - this pass prints out the LLVM IR using the MIR + /// serialization format. + extern char &MIRPrintingPassID; + /// TailDuplicate - Duplicate blocks with unconditional branches /// into tails of their predecessors. extern char &TailDuplicateID; diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 497ac55da4b4a..4f95c886800fe 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -289,6 +289,7 @@ void initializeLoopVectorizePass(PassRegistry&); void initializeSLPVectorizerPass(PassRegistry&); void initializeBBVectorizePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); +void initializeMIRPrintingPassPass(PassRegistry&); void initializeStackMapLivenessPass(PassRegistry&); void initializeMachineCombinerPass(PassRegistry &); void initializeLoadCombinePass(PassRegistry&); diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index 3bdff20918093..6d934fe512848 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -1090,6 +1090,9 @@ class Input : public IO { bool setCurrentDocument(); bool nextDocument(); + /// Returns the current node that's being parsed by the YAML Parser. + const Node *getCurrentNode() const; + private: llvm::SourceMgr SrcMgr; // must be before Strm std::unique_ptr Strm; diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 6ce5b13ea3938..810dbe44e2a0c 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -128,3 +128,4 @@ add_dependencies(LLVMCodeGen intrinsics_gen) add_subdirectory(SelectionDAG) add_subdirectory(AsmPrinter) +add_subdirectory(MIR) diff --git a/llvm/lib/CodeGen/LLVMBuild.txt b/llvm/lib/CodeGen/LLVMBuild.txt index fee0347ea6592..02be11af05a6a 100644 --- a/llvm/lib/CodeGen/LLVMBuild.txt +++ b/llvm/lib/CodeGen/LLVMBuild.txt @@ -16,10 +16,10 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = AsmPrinter SelectionDAG +subdirectories = AsmPrinter SelectionDAG MIR [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 MIR diff --git a/llvm/lib/CodeGen/LLVMTargetMachine.cpp b/llvm/lib/CodeGen/LLVMTargetMachine.cpp index 610c9f47bac7c..ff5205801bc4a 100644 --- a/llvm/lib/CodeGen/LLVMTargetMachine.cpp +++ b/llvm/lib/CodeGen/LLVMTargetMachine.cpp @@ -150,12 +150,7 @@ bool LLVMTargetMachine::addPassesToEmitFile( 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(createPrintMIRPass(outs())); return false; } diff --git a/llvm/lib/CodeGen/MIR/CMakeLists.txt b/llvm/lib/CodeGen/MIR/CMakeLists.txt new file mode 100644 index 0000000000000..52b64f3f82659 --- /dev/null +++ b/llvm/lib/CodeGen/MIR/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(LLVMMIR + MIRPrinter.cpp + MIRPrintingPass.cpp + MIRParser.cpp + ) + +add_dependencies(LLVMMIR intrinsics_gen) diff --git a/llvm/lib/CodeGen/MIR/LLVMBuild.txt b/llvm/lib/CodeGen/MIR/LLVMBuild.txt new file mode 100644 index 0000000000000..71aeaffb9bb1f --- /dev/null +++ b/llvm/lib/CodeGen/MIR/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/CodeGen/MIR/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 = MIR +parent = CodeGen +required_libraries = Core Support Target AsmParser diff --git a/llvm/lib/CodeGen/MIR/MIRParser.cpp b/llvm/lib/CodeGen/MIR/MIRParser.cpp new file mode 100644 index 0000000000000..e484046b23b55 --- /dev/null +++ b/llvm/lib/CodeGen/MIR/MIRParser.cpp @@ -0,0 +1,90 @@ +//===- 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 "llvm/CodeGen/MIR/MIRParser.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" +#include + +using namespace llvm; + +namespace { + +/// This class implements the parsing of LLVM IR that's embedded inside a MIR +/// file. +class MIRParserImpl { + SourceMgr SM; + StringRef Filename; + LLVMContext &Context; + +public: + MIRParserImpl(std::unique_ptr Contents, StringRef Filename, + LLVMContext &Context); + + /// 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(SMDiagnostic &Error); +}; + +} // end anonymous namespace + +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(SMDiagnostic &Error) { + 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 parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, + Context); + } + } + + // Create an new, empty module. + return llvm::make_unique(Filename, Context); +} + +std::unique_ptr 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 parseMIR(std::move(FileOrErr.get()), Error, Context); +} + +std::unique_ptr llvm::parseMIR(std::unique_ptr Contents, + SMDiagnostic &Error, + LLVMContext &Context) { + auto Filename = Contents->getBufferIdentifier(); + MIRParserImpl Parser(std::move(Contents), Filename, Context); + return Parser.parseLLVMModule(Error); +} diff --git a/llvm/lib/CodeGen/MIR/MIRPrinter.cpp b/llvm/lib/CodeGen/MIR/MIRPrinter.cpp new file mode 100644 index 0000000000000..fae22286d617c --- /dev/null +++ b/llvm/lib/CodeGen/MIR/MIRPrinter.cpp @@ -0,0 +1,66 @@ +//===- MIRPrinter.cpp - MIR serialization format printer ------------------===// +// +// 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 prints out the LLVM IR and machine +// functions using the MIR serialization format. +// +//===----------------------------------------------------------------------===// + +#include "MIRPrinter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm; + +namespace { + +/// 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 anonymous namespace + +namespace llvm { +namespace yaml { + +/// This struct serializes the LLVM IR module. +template <> struct BlockScalarTraits { + static void output(const Module &Mod, void *Ctxt, raw_ostream &OS) { + Mod.print(OS, nullptr); + } + static StringRef input(StringRef Str, void *Ctxt, Module &Mod) { + llvm_unreachable("LLVM Module is supposed to be parsed separately"); + return ""; + } +}; + +} // end namespace yaml +} // end namespace llvm + +MIRPrinter::MIRPrinter(raw_ostream &OS) : OS(OS) {} + +void MIRPrinter::printModule(const Module &Mod) { + yaml::Output Out(OS); + Out << const_cast(Mod); +} + +void llvm::printMIR(raw_ostream &OS, const Module &Mod) { + MIRPrinter Printer(OS); + Printer.printModule(Mod); +} diff --git a/llvm/lib/CodeGen/MIR/MIRPrinter.h b/llvm/lib/CodeGen/MIR/MIRPrinter.h new file mode 100644 index 0000000000000..2e6d645af71a1 --- /dev/null +++ b/llvm/lib/CodeGen/MIR/MIRPrinter.h @@ -0,0 +1,29 @@ +//===- MIRPrinter.h - MIR serialization format printer --------------------===// +// +// 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 function that prints out the LLVM IR using the MIR +// serialization format. +// TODO: Print out machine functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_MIR_MIRPRINTER_H +#define LLVM_LIB_CODEGEN_MIR_MIRPRINTER_H + +namespace llvm { + +class Module; +class raw_ostream; + +/// Print LLVM IR using the MIR serialization format to the given output stream. +void printMIR(raw_ostream &OS, const Module &Mod); + +} // end namespace llvm + +#endif diff --git a/llvm/lib/CodeGen/MIR/MIRPrintingPass.cpp b/llvm/lib/CodeGen/MIR/MIRPrintingPass.cpp new file mode 100644 index 0000000000000..f5a67d9e315a1 --- /dev/null +++ b/llvm/lib/CodeGen/MIR/MIRPrintingPass.cpp @@ -0,0 +1,66 @@ +//===- MIRPrintingPass.cpp - Pass that prints 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. +// +//===----------------------------------------------------------------------===// + +#include "MIRPrinter.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +/// This pass prints out the LLVM IR to an output stream using the MIR +/// serialization format. +struct MIRPrintingPass : public MachineFunctionPass { + static char ID; + raw_ostream &OS; + + MIRPrintingPass() : MachineFunctionPass(ID), OS(dbgs()) {} + MIRPrintingPass(raw_ostream &OS) : MachineFunctionPass(ID), OS(OS) {} + + const char *getPassName() const override { return "MIR Printing Pass"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + virtual bool runOnMachineFunction(MachineFunction &MF) override { + // TODO: Print out the machine function. + return false; + } + + virtual bool doFinalization(Module &M) override { + printMIR(OS, M); + return false; + } +}; + +char MIRPrintingPass::ID = 0; + +} // end anonymous namespace + +char &llvm::MIRPrintingPassID = MIRPrintingPass::ID; +INITIALIZE_PASS(MIRPrintingPass, "mir-printer", "MIR Printer", false, false) + +namespace llvm { + +MachineFunctionPass *createPrintMIRPass(raw_ostream &OS) { + return new MIRPrintingPass(OS); +} + +} // end namespace llvm diff --git a/llvm/lib/CodeGen/MIR/Makefile b/llvm/lib/CodeGen/MIR/Makefile new file mode 100644 index 0000000000000..72f581c6cfb5b --- /dev/null +++ b/llvm/lib/CodeGen/MIR/Makefile @@ -0,0 +1,13 @@ +##===- lib/CodeGen/MIR/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 = LLVMMIR + +include $(LEVEL)/Makefile.common diff --git a/llvm/lib/CodeGen/Makefile b/llvm/lib/CodeGen/Makefile index 4ab3e3c0013eb..867a5cf3d0f3a 100644 --- a/llvm/lib/CodeGen/Makefile +++ b/llvm/lib/CodeGen/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. LIBRARYNAME = LLVMCodeGen -PARALLEL_DIRS = SelectionDAG AsmPrinter +PARALLEL_DIRS = SelectionDAG AsmPrinter MIR BUILD_ARCHIVE = 1 include $(LEVEL)/Makefile.common diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp index 90f34f6e232d5..0d47f37edbddf 100644 --- a/llvm/lib/Support/YAMLTraits.cpp +++ b/llvm/lib/Support/YAMLTraits.cpp @@ -97,6 +97,10 @@ bool Input::nextDocument() { return ++DocIterator != Strm->end(); } +const Node *Input::getCurrentNode() const { + return CurrentNode ? CurrentNode->_node : nullptr; +} + bool Input::mapTag(StringRef Tag, bool Default) { std::string foundTag = CurrentNode->_node->getVerbatimTag(); if (foundTag.empty()) { diff --git a/llvm/test/CodeGen/Generic/stop-after.ll b/llvm/test/CodeGen/Generic/stop-after.ll index 557e097840af0..791378c3737d2 100644 --- a/llvm/test/CodeGen/Generic/stop-after.ll +++ b/llvm/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 Printing Pass ; START: -machine-branch-prob -gc-lowering ; START: FunctionPass Manager diff --git a/llvm/test/CodeGen/MIR/lit.local.cfg b/llvm/test/CodeGen/MIR/lit.local.cfg new file mode 100644 index 0000000000000..e69aa5765356d --- /dev/null +++ b/llvm/test/CodeGen/MIR/lit.local.cfg @@ -0,0 +1,2 @@ +config.suffixes = ['.mir'] + diff --git a/llvm/test/CodeGen/MIR/llvmIR.mir b/llvm/test/CodeGen/MIR/llvmIR.mir new file mode 100644 index 0000000000000..b448f8aa9dbbd --- /dev/null +++ b/llvm/test/CodeGen/MIR/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 MIR 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 + } + +... diff --git a/llvm/test/CodeGen/MIR/llvmIRMissing.mir b/llvm/test/CodeGen/MIR/llvmIRMissing.mir new file mode 100644 index 0000000000000..3b3522a0c5761 --- /dev/null +++ b/llvm/test/CodeGen/MIR/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. + +--- +... diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index ca86a99524b4e..4fdcd4bfa695d 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/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/MIR/MIRParser.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" @@ -109,6 +110,8 @@ GetOutputStream(const char *TargetName, Triple::OSType OS, 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; @@ -214,7 +217,10 @@ static int compileModule(char **argv, LLVMContext &Context) { // If user just wants to list available options, skip module loading if (!SkipModule) { - M = parseIRFile(InputFilename, Err, Context); + if (StringRef(InputFilename).endswith_lower(".mir")) + M = parseMIRFile(InputFilename, Err, Context); + else + M = parseIRFile(InputFilename, Err, Context); if (!M) { Err.print(argv[0], errs()); return 1;