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