blob: 7a51b3881afc68afaa572643459b7c155903fb51 [file] [log] [blame]
Alex Lorenz2bdb4e12015-05-27 18:02:19 +00001//===- MIRParser.cpp - MIR serialization format parser implementation -----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the class that parses the optional LLVM IR and machine
11// functions that are stored in MIR files.
12//
13//===----------------------------------------------------------------------===//
14
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"
Alex Lorenz78d78312015-05-28 22:41:12 +000019#include "llvm/CodeGen/MIRYamlMapping.h"
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000020#include "llvm/IR/Module.h"
Alex Lorenz09b832c2015-05-29 17:05:41 +000021#include "llvm/Support/LineIterator.h"
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000022#include "llvm/Support/SMLoc.h"
23#include "llvm/Support/SourceMgr.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/YAMLTraits.h"
26#include <memory>
27
28using namespace llvm;
29
30namespace {
31
32/// This class implements the parsing of LLVM IR that's embedded inside a MIR
33/// file.
34class MIRParserImpl {
35 SourceMgr SM;
36 StringRef Filename;
37 LLVMContext &Context;
38
39public:
40 MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename,
41 LLVMContext &Context);
42
Alex Lorenz78d78312015-05-28 22:41:12 +000043 /// Try to parse the optional LLVM module and the machine functions in the MIR
44 /// file.
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000045 ///
Alex Lorenz78d78312015-05-28 22:41:12 +000046 /// Return null if an error occurred.
47 std::unique_ptr<Module> parse(SMDiagnostic &Error);
48
49 /// Parse the machine function in the current YAML document.
50 ///
51 /// Return true if an error occurred.
52 bool parseMachineFunction(yaml::Input &In);
Alex Lorenz09b832c2015-05-29 17:05:41 +000053
54private:
55 /// Return a MIR diagnostic converted from an LLVM assembly diagnostic.
56 SMDiagnostic diagFromLLVMAssemblyDiag(const SMDiagnostic &Error,
57 SMRange SourceRange);
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000058};
59
60} // end anonymous namespace
61
62MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents,
63 StringRef Filename, LLVMContext &Context)
64 : SM(), Filename(Filename), Context(Context) {
65 SM.AddNewSourceBuffer(std::move(Contents), SMLoc());
66}
67
Alex Lorenz78d78312015-05-28 22:41:12 +000068static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) {
69 *reinterpret_cast<SMDiagnostic *>(Context) = Diag;
70}
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000071
Alex Lorenz78d78312015-05-28 22:41:12 +000072std::unique_ptr<Module> MIRParserImpl::parse(SMDiagnostic &Error) {
73 yaml::Input In(SM.getMemoryBuffer(SM.getMainFileID())->getBuffer(),
74 /*Ctxt=*/nullptr, handleYAMLDiag, &Error);
75
76 if (!In.setCurrentDocument()) {
77 if (!Error.getMessage().empty())
78 return nullptr;
79 // Create an empty module when the MIR file is empty.
80 return llvm::make_unique<Module>(Filename, Context);
Alex Lorenz2bdb4e12015-05-27 18:02:19 +000081 }
82
Alex Lorenz78d78312015-05-28 22:41:12 +000083 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.
86 if (const auto *BSN =
87 dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
88 M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
89 Context);
Alex Lorenz09b832c2015-05-29 17:05:41 +000090 if (!M) {
91 Error = diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange());
Alex Lorenz78d78312015-05-28 22:41:12 +000092 return M;
Alex Lorenz09b832c2015-05-29 17:05:41 +000093 }
Alex Lorenz78d78312015-05-28 22:41:12 +000094 In.nextDocument();
95 if (!In.setCurrentDocument())
96 return M;
97 } else {
98 // Create an new, empty module.
99 M = llvm::make_unique<Module>(Filename, Context);
100 }
101
102 // Parse the machine functions.
103 do {
104 if (parseMachineFunction(In))
105 return nullptr;
106 In.nextDocument();
107 } while (In.setCurrentDocument());
108
109 return M;
110}
111
112bool MIRParserImpl::parseMachineFunction(yaml::Input &In) {
113 yaml::MachineFunction MF;
114 yaml::yamlize(In, MF, false);
115 if (In.error())
116 return true;
117 // TODO: Initialize the real machine function with the state in the yaml
118 // machine function later on.
119 return false;
Alex Lorenz2bdb4e12015-05-27 18:02:19 +0000120}
121
Alex Lorenz09b832c2015-05-29 17:05:41 +0000122SMDiagnostic MIRParserImpl::diagFromLLVMAssemblyDiag(const SMDiagnostic &Error,
123 SMRange SourceRange) {
124 assert(SourceRange.isValid());
125
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();
133
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;
137 L != E; ++L) {
138 if (L.line_number() == Line) {
139 LineStr = *L;
140 Loc = SMLoc::getFromPointer(LineStr.data());
141 auto Indent = LineStr.find(Error.getLineContents());
142 if (Indent != StringRef::npos)
143 Column += Indent;
144 break;
145 }
146 }
147
148 return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(),
149 Error.getMessage(), LineStr, Error.getRanges(),
150 Error.getFixIts());
151}
152
Alex Lorenz2bdb4e12015-05-27 18:02:19 +0000153std::unique_ptr<Module> llvm::parseMIRFile(StringRef Filename,
154 SMDiagnostic &Error,
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>();
161 }
162 return parseMIR(std::move(FileOrErr.get()), Error, Context);
163}
164
165std::unique_ptr<Module> llvm::parseMIR(std::unique_ptr<MemoryBuffer> Contents,
166 SMDiagnostic &Error,
167 LLVMContext &Context) {
168 auto Filename = Contents->getBufferIdentifier();
169 MIRParserImpl Parser(std::move(Contents), Filename, Context);
Alex Lorenz78d78312015-05-28 22:41:12 +0000170 return Parser.parse(Error);
Alex Lorenz2bdb4e12015-05-27 18:02:19 +0000171}