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/StringMap.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/AsmParser/Parser.h" 20 #include "llvm/CodeGen/MachineFunction.h" 21 #include "llvm/CodeGen/MIRYamlMapping.h" 22 #include "llvm/IR/BasicBlock.h" 23 #include "llvm/IR/DiagnosticInfo.h" 24 #include "llvm/IR/Instructions.h" 25 #include "llvm/IR/LLVMContext.h" 26 #include "llvm/IR/Module.h" 27 #include "llvm/IR/ValueSymbolTable.h" 28 #include "llvm/Support/LineIterator.h" 29 #include "llvm/Support/SMLoc.h" 30 #include "llvm/Support/SourceMgr.h" 31 #include "llvm/Support/MemoryBuffer.h" 32 #include "llvm/Support/YAMLTraits.h" 33 #include <memory> 34 35 using namespace llvm; 36 37 namespace llvm { 38 39 /// This class implements the parsing of LLVM IR that's embedded inside a MIR 40 /// file. 41 class MIRParserImpl { 42 SourceMgr SM; 43 StringRef Filename; 44 LLVMContext &Context; 45 StringMap<std::unique_ptr<yaml::MachineFunction>> Functions; 46 47 public: 48 MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename, 49 LLVMContext &Context); 50 51 void reportDiagnostic(const SMDiagnostic &Diag); 52 53 /// Report an error with the given message at unknown location. 54 /// 55 /// Always returns true. 56 bool error(const Twine &Message); 57 58 /// Try to parse the optional LLVM module and the machine functions in the MIR 59 /// file. 60 /// 61 /// Return null if an error occurred. 62 std::unique_ptr<Module> parse(); 63 64 /// Parse the machine function in the current YAML document. 65 /// 66 /// \param NoLLVMIR - set to true when the MIR file doesn't have LLVM IR. 67 /// A dummy IR function is created and inserted into the given module when 68 /// this parameter is true. 69 /// 70 /// Return true if an error occurred. 71 bool parseMachineFunction(yaml::Input &In, Module &M, bool NoLLVMIR); 72 73 /// Initialize the machine function to the state that's described in the MIR 74 /// file. 75 /// 76 /// Return true if error occurred. 77 bool initializeMachineFunction(MachineFunction &MF); 78 79 /// Initialize the machine basic block using it's YAML representation. 80 /// 81 /// Return true if an error occurred. 82 bool initializeMachineBasicBlock(MachineBasicBlock &MBB, 83 const yaml::MachineBasicBlock &YamlMBB); 84 85 private: 86 /// Return a MIR diagnostic converted from an LLVM assembly diagnostic. 87 SMDiagnostic diagFromLLVMAssemblyDiag(const SMDiagnostic &Error, 88 SMRange SourceRange); 89 90 /// Create an empty function with the given name. 91 void createDummyFunction(StringRef Name, Module &M); 92 }; 93 94 } // end namespace llvm 95 96 MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, 97 StringRef Filename, LLVMContext &Context) 98 : SM(), Filename(Filename), Context(Context) { 99 SM.AddNewSourceBuffer(std::move(Contents), SMLoc()); 100 } 101 102 bool MIRParserImpl::error(const Twine &Message) { 103 Context.diagnose(DiagnosticInfoMIRParser( 104 DS_Error, SMDiagnostic(Filename, SourceMgr::DK_Error, Message.str()))); 105 return true; 106 } 107 108 void MIRParserImpl::reportDiagnostic(const SMDiagnostic &Diag) { 109 DiagnosticSeverity Kind; 110 switch (Diag.getKind()) { 111 case SourceMgr::DK_Error: 112 Kind = DS_Error; 113 break; 114 case SourceMgr::DK_Warning: 115 Kind = DS_Warning; 116 break; 117 case SourceMgr::DK_Note: 118 Kind = DS_Note; 119 break; 120 } 121 Context.diagnose(DiagnosticInfoMIRParser(Kind, Diag)); 122 } 123 124 static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) { 125 reinterpret_cast<MIRParserImpl *>(Context)->reportDiagnostic(Diag); 126 } 127 128 std::unique_ptr<Module> MIRParserImpl::parse() { 129 yaml::Input In(SM.getMemoryBuffer(SM.getMainFileID())->getBuffer(), 130 /*Ctxt=*/nullptr, handleYAMLDiag, this); 131 132 if (!In.setCurrentDocument()) { 133 if (In.error()) 134 return nullptr; 135 // Create an empty module when the MIR file is empty. 136 return llvm::make_unique<Module>(Filename, Context); 137 } 138 139 std::unique_ptr<Module> M; 140 bool NoLLVMIR = false; 141 // Parse the block scalar manually so that we can return unique pointer 142 // without having to go trough YAML traits. 143 if (const auto *BSN = 144 dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) { 145 SMDiagnostic Error; 146 M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, 147 Context); 148 if (!M) { 149 reportDiagnostic(diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange())); 150 return M; 151 } 152 In.nextDocument(); 153 if (!In.setCurrentDocument()) 154 return M; 155 } else { 156 // Create an new, empty module. 157 M = llvm::make_unique<Module>(Filename, Context); 158 NoLLVMIR = true; 159 } 160 161 // Parse the machine functions. 162 do { 163 if (parseMachineFunction(In, *M, NoLLVMIR)) 164 return nullptr; 165 In.nextDocument(); 166 } while (In.setCurrentDocument()); 167 168 return M; 169 } 170 171 bool MIRParserImpl::parseMachineFunction(yaml::Input &In, Module &M, 172 bool NoLLVMIR) { 173 auto MF = llvm::make_unique<yaml::MachineFunction>(); 174 yaml::yamlize(In, *MF, false); 175 if (In.error()) 176 return true; 177 auto FunctionName = MF->Name; 178 if (Functions.find(FunctionName) != Functions.end()) 179 return error(Twine("redefinition of machine function '") + FunctionName + 180 "'"); 181 Functions.insert(std::make_pair(FunctionName, std::move(MF))); 182 if (NoLLVMIR) 183 createDummyFunction(FunctionName, M); 184 else if (!M.getFunction(FunctionName)) 185 return error(Twine("function '") + FunctionName + 186 "' isn't defined in the provided LLVM IR"); 187 return false; 188 } 189 190 void MIRParserImpl::createDummyFunction(StringRef Name, Module &M) { 191 auto &Context = M.getContext(); 192 Function *F = cast<Function>(M.getOrInsertFunction( 193 Name, FunctionType::get(Type::getVoidTy(Context), false))); 194 BasicBlock *BB = BasicBlock::Create(Context, "entry", F); 195 new UnreachableInst(Context, BB); 196 } 197 198 bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { 199 auto It = Functions.find(MF.getName()); 200 if (It == Functions.end()) 201 return error(Twine("no machine function information for function '") + 202 MF.getName() + "' in the MIR file"); 203 // TODO: Recreate the machine function. 204 const yaml::MachineFunction &YamlMF = *It->getValue(); 205 if (YamlMF.Alignment) 206 MF.setAlignment(YamlMF.Alignment); 207 MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); 208 MF.setHasInlineAsm(YamlMF.HasInlineAsm); 209 const auto &F = *MF.getFunction(); 210 for (const auto &YamlMBB : YamlMF.BasicBlocks) { 211 const BasicBlock *BB = nullptr; 212 if (!YamlMBB.Name.empty()) { 213 BB = dyn_cast_or_null<BasicBlock>( 214 F.getValueSymbolTable().lookup(YamlMBB.Name)); 215 if (!BB) 216 return error(Twine("basic block '") + YamlMBB.Name + 217 "' is not defined in the function '" + MF.getName() + "'"); 218 } 219 auto *MBB = MF.CreateMachineBasicBlock(BB); 220 MF.insert(MF.end(), MBB); 221 if (initializeMachineBasicBlock(*MBB, YamlMBB)) 222 return true; 223 } 224 return false; 225 } 226 227 bool MIRParserImpl::initializeMachineBasicBlock( 228 MachineBasicBlock &MBB, const yaml::MachineBasicBlock &YamlMBB) { 229 MBB.setAlignment(YamlMBB.Alignment); 230 if (YamlMBB.AddressTaken) 231 MBB.setHasAddressTaken(); 232 MBB.setIsLandingPad(YamlMBB.IsLandingPad); 233 return false; 234 } 235 236 SMDiagnostic MIRParserImpl::diagFromLLVMAssemblyDiag(const SMDiagnostic &Error, 237 SMRange SourceRange) { 238 assert(SourceRange.isValid()); 239 240 // Translate the location of the error from the location in the llvm IR string 241 // to the corresponding location in the MIR file. 242 auto LineAndColumn = SM.getLineAndColumn(SourceRange.Start); 243 unsigned Line = LineAndColumn.first + Error.getLineNo() - 1; 244 unsigned Column = Error.getColumnNo(); 245 StringRef LineStr = Error.getLineContents(); 246 SMLoc Loc = Error.getLoc(); 247 248 // Get the full line and adjust the column number by taking the indentation of 249 // LLVM IR into account. 250 for (line_iterator L(*SM.getMemoryBuffer(SM.getMainFileID()), false), E; 251 L != E; ++L) { 252 if (L.line_number() == Line) { 253 LineStr = *L; 254 Loc = SMLoc::getFromPointer(LineStr.data()); 255 auto Indent = LineStr.find(Error.getLineContents()); 256 if (Indent != StringRef::npos) 257 Column += Indent; 258 break; 259 } 260 } 261 262 return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(), 263 Error.getMessage(), LineStr, Error.getRanges(), 264 Error.getFixIts()); 265 } 266 267 MIRParser::MIRParser(std::unique_ptr<MIRParserImpl> Impl) 268 : Impl(std::move(Impl)) {} 269 270 MIRParser::~MIRParser() {} 271 272 std::unique_ptr<Module> MIRParser::parseLLVMModule() { return Impl->parse(); } 273 274 bool MIRParser::initializeMachineFunction(MachineFunction &MF) { 275 return Impl->initializeMachineFunction(MF); 276 } 277 278 std::unique_ptr<MIRParser> llvm::createMIRParserFromFile(StringRef Filename, 279 SMDiagnostic &Error, 280 LLVMContext &Context) { 281 auto FileOrErr = MemoryBuffer::getFile(Filename); 282 if (std::error_code EC = FileOrErr.getError()) { 283 Error = SMDiagnostic(Filename, SourceMgr::DK_Error, 284 "Could not open input file: " + EC.message()); 285 return nullptr; 286 } 287 return createMIRParser(std::move(FileOrErr.get()), Context); 288 } 289 290 std::unique_ptr<MIRParser> 291 llvm::createMIRParser(std::unique_ptr<MemoryBuffer> Contents, 292 LLVMContext &Context) { 293 auto Filename = Contents->getBufferIdentifier(); 294 return llvm::make_unique<MIRParser>( 295 llvm::make_unique<MIRParserImpl>(std::move(Contents), Filename, Context)); 296 } 297