MIR Serialization: use correct line and column numbers for LLVM IR errors.
[oota-llvm.git] / lib / CodeGen / MIRParser / MIRParser.cpp
1 //===- 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"
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"
26 #include <memory>
27
28 using namespace llvm;
29
30 namespace {
31
32 /// This class implements the parsing of LLVM IR that's embedded inside a MIR
33 /// file.
34 class MIRParserImpl {
35   SourceMgr SM;
36   StringRef Filename;
37   LLVMContext &Context;
38
39 public:
40   MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename,
41                 LLVMContext &Context);
42
43   /// Try to parse the optional LLVM module and the machine functions in the MIR
44   /// file.
45   ///
46   /// 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);
53
54 private:
55   /// Return a MIR diagnostic converted from an LLVM assembly diagnostic.
56   SMDiagnostic diagFromLLVMAssemblyDiag(const SMDiagnostic &Error,
57                                         SMRange SourceRange);
58 };
59
60 } // end anonymous namespace
61
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());
66 }
67
68 static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) {
69   *reinterpret_cast<SMDiagnostic *>(Context) = Diag;
70 }
71
72 std::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);
81   }
82
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.
86   if (const auto *BSN =
87           dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
88     M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
89                       Context);
90     if (!M) {
91       Error = diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange());
92       return M;
93     }
94     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
112 bool 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;
120 }
121
122 SMDiagnostic 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
153 std::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
165 std::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);
170   return Parser.parse(Error);
171 }