Home | History | Annotate | Download | only in MCAnalysis
      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