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 } 172