Skip to content

Commit

Permalink
Resubmit r237954 (MIR Serialization: print and parse LLVM IR using MI…
Browse files Browse the repository at this point in the history
…R format).

This commit a 3rd attempt at comitting the initial MIR serialization patch.
The first commit (r237708) was reverted in 237730. Then the second commit
(r237954) was reverted in r238007, as the MIR library under CodeGen caused
a circular dependency where the CodeGen library depended on MIR and MIR
library depended on CodeGen.

This commit has fixed the dependencies between CodeGen and MIR by
reorganizing the MIR serialization code - the code that prints out
MIR has been moved to CodeGen, and the MIR library has been renamed
to MIRParser. Now the CodeGen library doesn't depend on the
MIRParser library, thus the circular dependency no longer exists.

--Original Commit Message--

MIR Serialization: print and parse LLVM IR using MIR format.

This commit is the initial commit for the MIR serialization project.
It creates a new library under CodeGen called 'MIR'. This new
library adds a new machine function pass that prints out the LLVM IR
using the MIR format. This pass is then added as a last pass when a
'stop-after' option is used in llc. The new library adds the initial
functionality for parsing of MIR files as well. This commit also
extends the llc tool so that it can recognize and parse MIR input files.

Reviewers: Duncan P. N. Exon Smith, Matthias Braun, Philip Reames

Differential Revision: http://reviews.llvm.org/D9616 

llvm-svn: 238341
  • Loading branch information
hyp committed May 27, 2015
1 parent 4669541 commit 2bdb4e1
Show file tree
Hide file tree
Showing 22 changed files with 339 additions and 12 deletions.
52 changes: 52 additions & 0 deletions llvm/include/llvm/CodeGen/MIRParser/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_MIRPARSER_MIRPARSER_H
#define LLVM_CODEGEN_MIRPARSER_MIRPARSER_H

#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>

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<Module> 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<Module> parseMIR(std::unique_ptr<MemoryBuffer> Contents,
SMDiagnostic &Error, LLVMContext &Context);

} // end namespace llvm

#endif
8 changes: 8 additions & 0 deletions llvm/include/llvm/CodeGen/Passes.h
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Expand Up @@ -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&);
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Support/YAMLTraits.h
Expand Up @@ -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<llvm::yaml::Stream> Strm;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/CMakeLists.txt
Expand Up @@ -71,6 +71,7 @@ add_llvm_library(LLVMCodeGen
MachineSink.cpp
MachineTraceMetrics.cpp
MachineVerifier.cpp
MIRPrintingPass.cpp
OcamlGC.cpp
OptimizePHIs.cpp
PHIElimination.cpp
Expand Down Expand Up @@ -129,3 +130,4 @@ add_dependencies(LLVMCodeGen intrinsics_gen)

add_subdirectory(SelectionDAG)
add_subdirectory(AsmPrinter)
add_subdirectory(MIRParser)
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/LLVMBuild.txt
Expand Up @@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;

[common]
subdirectories = AsmPrinter SelectionDAG
subdirectories = AsmPrinter SelectionDAG MIRParser

[component_0]
type = Library
Expand Down
7 changes: 1 addition & 6 deletions llvm/lib/CodeGen/LLVMTargetMachine.cpp
Expand Up @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/MIRParser/CMakeLists.txt
@@ -0,0 +1,5 @@
add_llvm_library(LLVMMIRParser
MIRParser.cpp
)

add_dependencies(LLVMMIRParser intrinsics_gen)
22 changes: 22 additions & 0 deletions llvm/lib/CodeGen/MIRParser/LLVMBuild.txt
@@ -0,0 +1,22 @@
;===- ./lib/CodeGen/MIRParser/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 = MIRParser
parent = CodeGen
required_libraries = Core Support Target AsmParser CodeGen
90 changes: 90 additions & 0 deletions llvm/lib/CodeGen/MIRParser/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/MIRParser/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 <memory>

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<MemoryBuffer> 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<Module> parseLLVMModule(SMDiagnostic &Error);
};

} // end anonymous namespace

MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents,
StringRef Filename, LLVMContext &Context)
: SM(), Filename(Filename), Context(Context) {
SM.AddNewSourceBuffer(std::move(Contents), SMLoc());
}

std::unique_ptr<Module> 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<yaml::BlockScalarNode>(In.getCurrentNode())) {
return parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
Context);
}
}

// Create an new, empty module.
return llvm::make_unique<Module>(Filename, Context);
}

std::unique_ptr<Module> 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<Module>();
}
return parseMIR(std::move(FileOrErr.get()), Error, Context);
}

std::unique_ptr<Module> llvm::parseMIR(std::unique_ptr<MemoryBuffer> Contents,
SMDiagnostic &Error,
LLVMContext &Context) {
auto Filename = Contents->getBufferIdentifier();
MIRParserImpl Parser(std::move(Contents), Filename, Context);
return Parser.parseLLVMModule(Error);
}
13 changes: 13 additions & 0 deletions llvm/lib/CodeGen/MIRParser/Makefile
@@ -0,0 +1,13 @@
##===- lib/CodeGen/MIRParser/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 = LLVMMIRParser

include $(LEVEL)/Makefile.common
85 changes: 85 additions & 0 deletions llvm/lib/CodeGen/MIRPrintingPass.cpp
@@ -0,0 +1,85 @@
//===- 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 "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLTraits.h"

using namespace llvm;

namespace llvm {
namespace yaml {

/// This struct serializes the LLVM IR module.
template <> struct BlockScalarTraits<Module> {
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

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 {
yaml::Output Out(OS);
Out << 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
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/Makefile
Expand Up @@ -9,7 +9,7 @@

LEVEL = ../..
LIBRARYNAME = LLVMCodeGen
PARALLEL_DIRS = SelectionDAG AsmPrinter
PARALLEL_DIRS = SelectionDAG AsmPrinter MIRParser
BUILD_ARCHIVE = 1

include $(LEVEL)/Makefile.common
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Support/YAMLTraits.cpp
Expand Up @@ -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()) {
Expand Down
3 changes: 2 additions & 1 deletion 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
Expand Down
2 changes: 2 additions & 0 deletions llvm/test/CodeGen/MIR/lit.local.cfg
@@ -0,0 +1,2 @@
config.suffixes = ['.mir']

0 comments on commit 2bdb4e1

Please sign in to comment.