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
27namespace llvm {
28
29namespace {
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//
50class InstrRegInfoHolder {
51  typedef StringMap<unsigned, BumpPtrAllocator> EnumValByNameTy;
52  EnumValByNameTy InstEnumValueByName;
53  EnumValByNameTy RegEnumValueByName;
54
55public:
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
85namespace MCModuleYAML {
86
87LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum)
88
89struct Operand {
90  MCOperand MCOp;
91};
92
93struct Inst {
94  OpcodeEnum Opcode;
95  std::vector<Operand> Operands;
96  uint64_t Size;
97};
98
99struct 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
108struct BasicBlock {
109  yaml::Hex64 Address;
110  std::vector<yaml::Hex64> Preds;
111  std::vector<yaml::Hex64> Succs;
112};
113
114struct Function {
115  StringRef Name;
116  std::vector<BasicBlock> BasicBlocks;
117};
118
119struct Module {
120  std::vector<Atom> Atoms;
121  std::vector<Function> Functions;
122};
123
124} // end namespace MCModuleYAML
125} // end namespace llvm
126
127LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
128LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::MCModuleYAML::Operand)
129LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Inst)
130LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Atom)
131LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::BasicBlock)
132LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Function)
133
134namespace llvm {
135
136namespace yaml {
137
138template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> {
139  static void enumeration(IO &IO, MCAtom::AtomKind &Kind);
140};
141
142template <> struct MappingTraits<MCModuleYAML::Atom> {
143  static void mapping(IO &IO, MCModuleYAML::Atom &A);
144};
145
146template <> struct MappingTraits<MCModuleYAML::Inst> {
147  static void mapping(IO &IO, MCModuleYAML::Inst &I);
148};
149
150template <> struct MappingTraits<MCModuleYAML::BasicBlock> {
151  static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB);
152};
153
154template <> struct MappingTraits<MCModuleYAML::Function> {
155  static void mapping(IO &IO, MCModuleYAML::Function &Fn);
156};
157
158template <> struct MappingTraits<MCModuleYAML::Module> {
159  static void mapping(IO &IO, MCModuleYAML::Module &M);
160};
161
162template <> 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
169template <> 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
176void 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
182void 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
192void 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
198void
199MappingTraits<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
206void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO,
207                                                    MCModuleYAML::Function &F) {
208  IO.mapRequired("Name", F.Name);
209  IO.mapRequired("BasicBlocks", F.BasicBlocks);
210}
211
212void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO,
213                                                  MCModuleYAML::Module &M) {
214  IO.mapRequired("Atoms", M.Atoms);
215  IO.mapOptional("Functions", M.Functions);
216}
217
218void
219ScalarTraits<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
232StringRef
233ScalarTraits<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
257void 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
263StringRef
264ScalarTraits<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
276namespace {
277
278class 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
285public:
286  MCModule2YAML(const MCModule &MCM);
287  MCModuleYAML::Module &getYAMLModule();
288};
289
290class YAML2MCModule {
291  MCModule &MCM;
292
293public:
294  YAML2MCModule(MCModule &MCM);
295  StringRef parse(const MCModuleYAML::Module &YAMLModule);
296};
297
298} // end unnamed namespace
299
300MCModule2YAML::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
309void 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
334void 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
355MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; }
356
357YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {}
358
359StringRef 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
439StringRef 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
448StringRef 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