1 //===- MIRParser.cpp - MIR serialization format parser implementation -----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the class that parses the optional LLVM IR and machine
11 // functions that are stored in MIR files.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CodeGen/MIRParser/MIRParser.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/AsmParser/Parser.h"
19 #include "llvm/CodeGen/MIRYamlMapping.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/Support/LineIterator.h"
22 #include "llvm/Support/SMLoc.h"
23 #include "llvm/Support/SourceMgr.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/YAMLTraits.h"
32 /// This class implements the parsing of LLVM IR that's embedded inside a MIR
40 MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename,
41 LLVMContext &Context);
43 /// Try to parse the optional LLVM module and the machine functions in the MIR
46 /// Return null if an error occurred.
47 std::unique_ptr<Module> parse(SMDiagnostic &Error);
49 /// Parse the machine function in the current YAML document.
51 /// Return true if an error occurred.
52 bool parseMachineFunction(yaml::Input &In);
55 /// Return a MIR diagnostic converted from an LLVM assembly diagnostic.
56 SMDiagnostic diagFromLLVMAssemblyDiag(const SMDiagnostic &Error,
60 } // end anonymous namespace
62 MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents,
63 StringRef Filename, LLVMContext &Context)
64 : SM(), Filename(Filename), Context(Context) {
65 SM.AddNewSourceBuffer(std::move(Contents), SMLoc());
68 static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) {
69 *reinterpret_cast<SMDiagnostic *>(Context) = Diag;
72 std::unique_ptr<Module> MIRParserImpl::parse(SMDiagnostic &Error) {
73 yaml::Input In(SM.getMemoryBuffer(SM.getMainFileID())->getBuffer(),
74 /*Ctxt=*/nullptr, handleYAMLDiag, &Error);
76 if (!In.setCurrentDocument()) {
77 if (!Error.getMessage().empty())
79 // Create an empty module when the MIR file is empty.
80 return llvm::make_unique<Module>(Filename, Context);
83 std::unique_ptr<Module> M;
84 // Parse the block scalar manually so that we can return unique pointer
85 // without having to go trough YAML traits.
87 dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
88 M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
91 Error = diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange());
95 if (!In.setCurrentDocument())
98 // Create an new, empty module.
99 M = llvm::make_unique<Module>(Filename, Context);
102 // Parse the machine functions.
104 if (parseMachineFunction(In))
107 } while (In.setCurrentDocument());
112 bool MIRParserImpl::parseMachineFunction(yaml::Input &In) {
113 yaml::MachineFunction MF;
114 yaml::yamlize(In, MF, false);
117 // TODO: Initialize the real machine function with the state in the yaml
118 // machine function later on.
122 SMDiagnostic MIRParserImpl::diagFromLLVMAssemblyDiag(const SMDiagnostic &Error,
123 SMRange SourceRange) {
124 assert(SourceRange.isValid());
126 // Translate the location of the error from the location in the llvm IR string
127 // to the corresponding location in the MIR file.
128 auto LineAndColumn = SM.getLineAndColumn(SourceRange.Start);
129 unsigned Line = LineAndColumn.first + Error.getLineNo() - 1;
130 unsigned Column = Error.getColumnNo();
131 StringRef LineStr = Error.getLineContents();
132 SMLoc Loc = Error.getLoc();
134 // Get the full line and adjust the column number by taking the indentation of
135 // LLVM IR into account.
136 for (line_iterator L(*SM.getMemoryBuffer(SM.getMainFileID()), false), E;
138 if (L.line_number() == Line) {
140 Loc = SMLoc::getFromPointer(LineStr.data());
141 auto Indent = LineStr.find(Error.getLineContents());
142 if (Indent != StringRef::npos)
148 return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(),
149 Error.getMessage(), LineStr, Error.getRanges(),
153 std::unique_ptr<Module> llvm::parseMIRFile(StringRef Filename,
155 LLVMContext &Context) {
156 auto FileOrErr = MemoryBuffer::getFile(Filename);
157 if (std::error_code EC = FileOrErr.getError()) {
158 Error = SMDiagnostic(Filename, SourceMgr::DK_Error,
159 "Could not open input file: " + EC.message());
160 return std::unique_ptr<Module>();
162 return parseMIR(std::move(FileOrErr.get()), Error, Context);
165 std::unique_ptr<Module> llvm::parseMIR(std::unique_ptr<MemoryBuffer> Contents,
167 LLVMContext &Context) {
168 auto Filename = Contents->getBufferIdentifier();
169 MIRParserImpl Parser(std::move(Contents), Filename, Context);
170 return Parser.parse(Error);