1 //===- MCModuleYAML.cpp - MCModule YAMLIO 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 defines classes for handling the YAML representation of MCModule. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/MC/MCAnalysis/MCModuleYAML.h" 15 #include "llvm/ADT/StringMap.h" 16 #include "llvm/MC/MCAnalysis/MCAtom.h" 17 #include "llvm/MC/MCAnalysis/MCFunction.h" 18 #include "llvm/MC/MCInstrInfo.h" 19 #include "llvm/MC/MCRegisterInfo.h" 20 #include "llvm/MC/YAML.h" 21 #include "llvm/Support/Allocator.h" 22 #include "llvm/Support/Casting.h" 23 #include "llvm/Support/MathExtras.h" 24 #include "llvm/Support/YAMLTraits.h" 25 #include <vector> 26 27 namespace llvm { 28 29 namespace { 30 31 // This class is used to map opcode and register names to enum values. 32 // 33 // There are at least 3 obvious ways to do this: 34 // 1- Generate an MII/MRI method using a tablegen StringMatcher 35 // 2- Write an MII/MRI method using std::lower_bound and the assumption that 36 // the enums are sorted (starting at a fixed value). 37 // 3- Do the matching manually as is done here. 38 // 39 // Why 3? 40 // 1- A StringMatcher function for thousands of entries would incur 41 // a non-negligible binary size overhead. 42 // 2- The lower_bound comparators would be somewhat involved and aren't 43 // obviously reusable (see LessRecordRegister in llvm/TableGen/Record.h) 44 // 3- This isn't actually something useful outside tests (but the same argument 45 // can be made against having {MII,MRI}::getName). 46 // 47 // If this becomes useful outside this specific situation, feel free to do 48 // the Right Thing (tm) and move the functionality to MII/MRI. 49 // 50 class InstrRegInfoHolder { 51 typedef StringMap<unsigned, BumpPtrAllocator> EnumValByNameTy; 52 EnumValByNameTy InstEnumValueByName; 53 EnumValByNameTy RegEnumValueByName; 54 55 public: 56 const MCInstrInfo &MII; 57 const MCRegisterInfo &MRI; 58 InstrRegInfoHolder(const MCInstrInfo &MII, const MCRegisterInfo &MRI) 59 : InstEnumValueByName(NextPowerOf2(MII.getNumOpcodes())), 60 RegEnumValueByName(NextPowerOf2(MRI.getNumRegs())), MII(MII), MRI(MRI) { 61 for (int i = 0, e = MII.getNumOpcodes(); i != e; ++i) 62 InstEnumValueByName[MII.getName(i)] = i; 63 for (int i = 0, e = MRI.getNumRegs(); i != e; ++i) 64 RegEnumValueByName[MRI.getName(i)] = i; 65 } 66 67 bool matchRegister(StringRef Name, unsigned &Reg) { 68 EnumValByNameTy::const_iterator It = RegEnumValueByName.find(Name); 69 if (It == RegEnumValueByName.end()) 70 return false; 71 Reg = It->getValue(); 72 return true; 73 } 74 bool matchOpcode(StringRef Name, unsigned &Opc) { 75 EnumValByNameTy::const_iterator It = InstEnumValueByName.find(Name); 76 if (It == InstEnumValueByName.end()) 77 return false; 78 Opc = It->getValue(); 79 return true; 80 } 81 }; 82 83 } // end unnamed namespace 84 85 namespace MCModuleYAML { 86 87 LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum) 88 89 struct Operand { 90 MCOperand MCOp; 91 }; 92 93 struct Inst { 94 OpcodeEnum Opcode; 95 std::vector<Operand> Operands; 96 uint64_t Size; 97 }; 98 99 struct Atom { 100 MCAtom::AtomKind Type; 101 yaml::Hex64 StartAddress; 102 uint64_t Size; 103 104 std::vector<Inst> Insts; 105 yaml::BinaryRef Data; 106 }; 107 108 struct BasicBlock { 109 yaml::Hex64 Address; 110 std::vector<yaml::Hex64> Preds; 111 std::vector<yaml::Hex64> Succs; 112 }; 113 114 struct Function { 115 StringRef Name; 116 std::vector<BasicBlock> BasicBlocks; 117 }; 118 119 struct Module { 120 std::vector<Atom> Atoms; 121 std::vector<Function> Functions; 122 }; 123 124 } // end namespace MCModuleYAML 125 } // end namespace llvm 126 127 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) 128 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::MCModuleYAML::Operand) 129 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Inst) 130 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Atom) 131 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::BasicBlock) 132 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Function) 133 134 namespace llvm { 135 136 namespace yaml { 137 138 template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> { 139 static void enumeration(IO &IO, MCAtom::AtomKind &Kind); 140 }; 141 142 template <> struct MappingTraits<MCModuleYAML::Atom> { 143 static void mapping(IO &IO, MCModuleYAML::Atom &A); 144 }; 145 146 template <> struct MappingTraits<MCModuleYAML::Inst> { 147 static void mapping(IO &IO, MCModuleYAML::Inst &I); 148 }; 149 150 template <> struct MappingTraits<MCModuleYAML::BasicBlock> { 151 static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB); 152 }; 153 154 template <> struct MappingTraits<MCModuleYAML::Function> { 155 static void mapping(IO &IO, MCModuleYAML::Function &Fn); 156 }; 157 158 template <> struct MappingTraits<MCModuleYAML::Module> { 159 static void mapping(IO &IO, MCModuleYAML::Module &M); 160 }; 161 162 template <> struct ScalarTraits<MCModuleYAML::Operand> { 163 static void output(const MCModuleYAML::Operand &, void *, 164 llvm::raw_ostream &); 165 static StringRef input(StringRef, void *, MCModuleYAML::Operand &); 166 static bool mustQuote(StringRef) { return false; } 167 }; 168 169 template <> struct ScalarTraits<MCModuleYAML::OpcodeEnum> { 170 static void output(const MCModuleYAML::OpcodeEnum &, void *, 171 llvm::raw_ostream &); 172 static StringRef input(StringRef, void *, MCModuleYAML::OpcodeEnum &); 173 static bool mustQuote(StringRef) { return false; } 174 }; 175 176 void ScalarEnumerationTraits<MCAtom::AtomKind>::enumeration( 177 IO &IO, MCAtom::AtomKind &Value) { 178 IO.enumCase(Value, "Text", MCAtom::TextAtom); 179 IO.enumCase(Value, "Data", MCAtom::DataAtom); 180 } 181 182 void MappingTraits<MCModuleYAML::Atom>::mapping(IO &IO, MCModuleYAML::Atom &A) { 183 IO.mapRequired("StartAddress", A.StartAddress); 184 IO.mapRequired("Size", A.Size); 185 IO.mapRequired("Type", A.Type); 186 if (A.Type == MCAtom::TextAtom) 187 IO.mapRequired("Content", A.Insts); 188 else if (A.Type == MCAtom::DataAtom) 189 IO.mapRequired("Content", A.Data); 190 } 191 192 void MappingTraits<MCModuleYAML::Inst>::mapping(IO &IO, MCModuleYAML::Inst &I) { 193 IO.mapRequired("Inst", I.Opcode); 194 IO.mapRequired("Size", I.Size); 195 IO.mapRequired("Ops", I.Operands); 196 } 197 198 void 199 MappingTraits<MCModuleYAML::BasicBlock>::mapping(IO &IO, 200 MCModuleYAML::BasicBlock &BB) { 201 IO.mapRequired("Address", BB.Address); 202 IO.mapRequired("Preds", BB.Preds); 203 IO.mapRequired("Succs", BB.Succs); 204 } 205 206 void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO, 207 MCModuleYAML::Function &F) { 208 IO.mapRequired("Name", F.Name); 209 IO.mapRequired("BasicBlocks", F.BasicBlocks); 210 } 211 212 void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO, 213 MCModuleYAML::Module &M) { 214 IO.mapRequired("Atoms", M.Atoms); 215 IO.mapOptional("Functions", M.Functions); 216 } 217 218 void 219 ScalarTraits<MCModuleYAML::Operand>::output(const MCModuleYAML::Operand &Val, 220 void *Ctx, raw_ostream &Out) { 221 InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; 222 223 // FIXME: Doesn't support FPImm and expr/inst, but do these make sense? 224 if (Val.MCOp.isImm()) 225 Out << "I" << Val.MCOp.getImm(); 226 else if (Val.MCOp.isReg()) 227 Out << "R" << IRI->MRI.getName(Val.MCOp.getReg()); 228 else 229 llvm_unreachable("Trying to output invalid MCOperand!"); 230 } 231 232 StringRef 233 ScalarTraits<MCModuleYAML::Operand>::input(StringRef Scalar, void *Ctx, 234 MCModuleYAML::Operand &Val) { 235 InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; 236 char Type = 0; 237 if (Scalar.size() >= 1) 238 Type = Scalar.front(); 239 if (Type != 'R' && Type != 'I') 240 return "Operand must start with 'R' (register) or 'I' (immediate)."; 241 if (Type == 'R') { 242 unsigned Reg; 243 if (!IRI->matchRegister(Scalar.substr(1), Reg)) 244 return "Invalid register name."; 245 Val.MCOp = MCOperand::CreateReg(Reg); 246 } else if (Type == 'I') { 247 int64_t RIVal; 248 if (Scalar.substr(1).getAsInteger(10, RIVal)) 249 return "Invalid immediate value."; 250 Val.MCOp = MCOperand::CreateImm(RIVal); 251 } else { 252 Val.MCOp = MCOperand(); 253 } 254 return StringRef(); 255 } 256 257 void ScalarTraits<MCModuleYAML::OpcodeEnum>::output( 258 const MCModuleYAML::OpcodeEnum &Val, void *Ctx, raw_ostream &Out) { 259 InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; 260 Out << IRI->MII.getName(Val); 261 } 262 263 StringRef 264 ScalarTraits<MCModuleYAML::OpcodeEnum>::input(StringRef Scalar, void *Ctx, 265 MCModuleYAML::OpcodeEnum &Val) { 266 InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; 267 unsigned Opc; 268 if (!IRI->matchOpcode(Scalar, Opc)) 269 return "Invalid instruction opcode."; 270 Val = Opc; 271 return ""; 272 } 273 274 } // end namespace yaml 275 276 namespace { 277 278 class MCModule2YAML { 279 const MCModule &MCM; 280 MCModuleYAML::Module YAMLModule; 281 void dumpAtom(const MCAtom *MCA); 282 void dumpFunction(const MCFunction &MCF); 283 void dumpBasicBlock(const MCBasicBlock *MCBB); 284 285 public: 286 MCModule2YAML(const MCModule &MCM); 287 MCModuleYAML::Module &getYAMLModule(); 288 }; 289 290 class YAML2MCModule { 291 MCModule &MCM; 292 293 public: 294 YAML2MCModule(MCModule &MCM); 295 StringRef parse(const MCModuleYAML::Module &YAMLModule); 296 }; 297 298 } // end unnamed namespace 299 300 MCModule2YAML::MCModule2YAML(const MCModule &MCM) : MCM(MCM), YAMLModule() { 301 for (MCModule::const_atom_iterator AI = MCM.atom_begin(), AE = MCM.atom_end(); 302 AI != AE; ++AI) 303 dumpAtom(*AI); 304 for (MCModule::const_func_iterator FI = MCM.func_begin(), FE = MCM.func_end(); 305 FI != FE; ++FI) 306 dumpFunction(**FI); 307 } 308 309 void MCModule2YAML::dumpAtom(const MCAtom *MCA) { 310 YAMLModule.Atoms.resize(YAMLModule.Atoms.size() + 1); 311 MCModuleYAML::Atom &A = YAMLModule.Atoms.back(); 312 A.Type = MCA->getKind(); 313 A.StartAddress = MCA->getBeginAddr(); 314 A.Size = MCA->getEndAddr() - MCA->getBeginAddr() + 1; 315 if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(MCA)) { 316 const size_t InstCount = TA->size(); 317 A.Insts.resize(InstCount); 318 for (size_t i = 0; i != InstCount; ++i) { 319 const MCDecodedInst &MCDI = TA->at(i); 320 A.Insts[i].Opcode = MCDI.Inst.getOpcode(); 321 A.Insts[i].Size = MCDI.Size; 322 const unsigned OpCount = MCDI.Inst.getNumOperands(); 323 A.Insts[i].Operands.resize(OpCount); 324 for (unsigned oi = 0; oi != OpCount; ++oi) 325 A.Insts[i].Operands[oi].MCOp = MCDI.Inst.getOperand(oi); 326 } 327 } else if (const MCDataAtom *DA = dyn_cast<MCDataAtom>(MCA)) { 328 A.Data = DA->getData(); 329 } else { 330 llvm_unreachable("Unknown atom type."); 331 } 332 } 333 334 void MCModule2YAML::dumpFunction(const MCFunction &MCF) { 335 YAMLModule.Functions.resize(YAMLModule.Functions.size() + 1); 336 MCModuleYAML::Function &F = YAMLModule.Functions.back(); 337 F.Name = MCF.getName(); 338 for (MCFunction::const_iterator BBI = MCF.begin(), BBE = MCF.end(); 339 BBI != BBE; ++BBI) { 340 const MCBasicBlock &MCBB = **BBI; 341 F.BasicBlocks.resize(F.BasicBlocks.size() + 1); 342 MCModuleYAML::BasicBlock &BB = F.BasicBlocks.back(); 343 BB.Address = MCBB.getInsts()->getBeginAddr(); 344 for (MCBasicBlock::pred_const_iterator PI = MCBB.pred_begin(), 345 PE = MCBB.pred_end(); 346 PI != PE; ++PI) 347 BB.Preds.push_back((*PI)->getInsts()->getBeginAddr()); 348 for (MCBasicBlock::succ_const_iterator SI = MCBB.succ_begin(), 349 SE = MCBB.succ_end(); 350 SI != SE; ++SI) 351 BB.Succs.push_back((*SI)->getInsts()->getBeginAddr()); 352 } 353 } 354 355 MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; } 356 357 YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {} 358 359 StringRef YAML2MCModule::parse(const MCModuleYAML::Module &YAMLModule) { 360 typedef std::vector<MCModuleYAML::Atom>::const_iterator AtomIt; 361 typedef std::vector<MCModuleYAML::Inst>::const_iterator InstIt; 362 typedef std::vector<MCModuleYAML::Operand>::const_iterator OpIt; 363 364 typedef DenseMap<uint64_t, MCTextAtom *> AddrToTextAtomTy; 365 AddrToTextAtomTy TAByAddr; 366 367 for (AtomIt AI = YAMLModule.Atoms.begin(), AE = YAMLModule.Atoms.end(); 368 AI != AE; ++AI) { 369 uint64_t StartAddress = AI->StartAddress; 370 if (AI->Size == 0) 371 return "Atoms can't be empty!"; 372 uint64_t EndAddress = StartAddress + AI->Size - 1; 373 switch (AI->Type) { 374 case MCAtom::TextAtom: { 375 MCTextAtom *TA = MCM.createTextAtom(StartAddress, EndAddress); 376 TAByAddr[StartAddress] = TA; 377 for (InstIt II = AI->Insts.begin(), IE = AI->Insts.end(); II != IE; 378 ++II) { 379 MCInst MI; 380 MI.setOpcode(II->Opcode); 381 for (OpIt OI = II->Operands.begin(), OE = II->Operands.end(); OI != OE; 382 ++OI) 383 MI.addOperand(OI->MCOp); 384 TA->addInst(MI, II->Size); 385 } 386 break; 387 } 388 case MCAtom::DataAtom: { 389 MCDataAtom *DA = MCM.createDataAtom(StartAddress, EndAddress); 390 SmallVector<char, 64> Data; 391 raw_svector_ostream OS(Data); 392 AI->Data.writeAsBinary(OS); 393 OS.flush(); 394 for (size_t i = 0, e = Data.size(); i != e; ++i) 395 DA->addData((uint8_t)Data[i]); 396 break; 397 } 398 } 399 } 400 401 typedef std::vector<MCModuleYAML::Function>::const_iterator FuncIt; 402 typedef std::vector<MCModuleYAML::BasicBlock>::const_iterator BBIt; 403 typedef std::vector<yaml::Hex64>::const_iterator AddrIt; 404 for (FuncIt FI = YAMLModule.Functions.begin(), 405 FE = YAMLModule.Functions.end(); 406 FI != FE; ++FI) { 407 MCFunction *MCFN = MCM.createFunction(FI->Name); 408 for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end(); 409 BBI != BBE; ++BBI) { 410 AddrToTextAtomTy::const_iterator It = TAByAddr.find(BBI->Address); 411 if (It == TAByAddr.end()) 412 return "Basic block start address doesn't match any text atom!"; 413 MCFN->createBlock(*It->second); 414 } 415 for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end(); 416 BBI != BBE; ++BBI) { 417 MCBasicBlock *MCBB = MCFN->find(BBI->Address); 418 if (!MCBB) 419 return "Couldn't find matching basic block in function."; 420 for (AddrIt PI = BBI->Preds.begin(), PE = BBI->Preds.end(); PI != PE; 421 ++PI) { 422 MCBasicBlock *Pred = MCFN->find(*PI); 423 if (!Pred) 424 return "Couldn't find predecessor basic block."; 425 MCBB->addPredecessor(Pred); 426 } 427 for (AddrIt SI = BBI->Succs.begin(), SE = BBI->Succs.end(); SI != SE; 428 ++SI) { 429 MCBasicBlock *Succ = MCFN->find(*SI); 430 if (!Succ) 431 return "Couldn't find predecessor basic block."; 432 MCBB->addSuccessor(Succ); 433 } 434 } 435 } 436 return ""; 437 } 438 439 StringRef mcmodule2yaml(raw_ostream &OS, const MCModule &MCM, 440 const MCInstrInfo &MII, const MCRegisterInfo &MRI) { 441 MCModule2YAML Dumper(MCM); 442 InstrRegInfoHolder IRI(MII, MRI); 443 yaml::Output YOut(OS, (void *)&IRI); 444 YOut << Dumper.getYAMLModule(); 445 return ""; 446 } 447 448 StringRef yaml2mcmodule(std::unique_ptr<MCModule> &MCM, StringRef YamlContent, 449 const MCInstrInfo &MII, const MCRegisterInfo &MRI) { 450 MCM.reset(new MCModule); 451 YAML2MCModule Parser(*MCM); 452 MCModuleYAML::Module YAMLModule; 453 InstrRegInfoHolder IRI(MII, MRI); 454 yaml::Input YIn(YamlContent, (void *)&IRI); 455 YIn >> YAMLModule; 456 if (std::error_code ec = YIn.error()) 457 return ec.message(); 458 StringRef err = Parser.parse(YAMLModule); 459 if (!err.empty()) 460 return err; 461 return ""; 462 } 463 464 } // end namespace llvm 465