]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - opencl/llvm.git/blob - lib/MC/MCAnalysis/MCModuleYAML.cpp
Move CFG building code to a new lib/MC/MCAnalysis library.
[opencl/llvm.git] / lib / MC / MCAnalysis / MCModuleYAML.cpp
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 //===----------------------------------------------------------------------===//
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/Object/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>
27 namespace llvm {
29 namespace {
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;
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   }
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 };
83 } // end unnamed namespace
85 namespace MCModuleYAML {
87 LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum)
89 struct Operand {
90   MCOperand MCOp;
91 };
93 struct Inst {
94   OpcodeEnum Opcode;
95   std::vector<Operand> Operands;
96   uint64_t Size;
97 };
99 struct Atom {
100   MCAtom::AtomKind Type;
101   yaml::Hex64 StartAddress;
102   uint64_t Size;
104   std::vector<Inst> Insts;
105   object::yaml::BinaryRef Data;
106 };
108 struct BasicBlock {
109   yaml::Hex64 Address;
110   std::vector<yaml::Hex64> Preds;
111   std::vector<yaml::Hex64> Succs;
112 };
114 struct Function {
115   StringRef Name;
116   std::vector<BasicBlock> BasicBlocks;
117 };
119 struct Module {
120   std::vector<Atom> Atoms;
121   std::vector<Function> Functions;
122 };
124 } // end namespace MCModuleYAML
125 } // end namespace llvm
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)
134 namespace llvm {
136 namespace yaml {
138 template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> {
139   static void enumeration(IO &IO, MCAtom::AtomKind &Kind);
140 };
142 template <> struct MappingTraits<MCModuleYAML::Atom> {
143   static void mapping(IO &IO, MCModuleYAML::Atom &A);
144 };
146 template <> struct MappingTraits<MCModuleYAML::Inst> {
147   static void mapping(IO &IO, MCModuleYAML::Inst &I);
148 };
150 template <> struct MappingTraits<MCModuleYAML::BasicBlock> {
151   static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB);
152 };
154 template <> struct MappingTraits<MCModuleYAML::Function> {
155   static void mapping(IO &IO, MCModuleYAML::Function &Fn);
156 };
158 template <> struct MappingTraits<MCModuleYAML::Module> {
159   static void mapping(IO &IO, MCModuleYAML::Module &M);
160 };
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 };
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 };
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);
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);
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);
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);
206 void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO,
207                                                     MCModuleYAML::Function &F) {
208   IO.mapRequired("Name", F.Name);
209   IO.mapRequired("BasicBlocks", F.BasicBlocks);
212 void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO,
213                                                   MCModuleYAML::Module &M) {
214   IO.mapRequired("Atoms", M.Atoms);
215   IO.mapOptional("Functions", M.Functions);
218 void
219 ScalarTraits<MCModuleYAML::Operand>::output(const MCModuleYAML::Operand &Val,
220                                             void *Ctx, raw_ostream &Out) {
221   InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx;
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!");
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();
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);
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 "";
274 } // end namespace yaml
276 namespace {
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);
285 public:
286   MCModule2YAML(const MCModule &MCM);
287   MCModuleYAML::Module &getYAMLModule();
288 };
290 class YAML2MCModule {
291   MCModule &MCM;
293 public:
294   YAML2MCModule(MCModule &MCM);
295   StringRef parse(const MCModuleYAML::Module &YAMLModule);
296 };
298 } // end unnamed namespace
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);
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   }
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   }
355 MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; }
357 YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {}
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;
364   typedef DenseMap<uint64_t, MCTextAtom *> AddrToTextAtomTy;
365   AddrToTextAtomTy TAByAddr;
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   }
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 "";
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 "";
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 "";
464 } // end namespace llvm