YAMLIO: Allow scalars to dictate quotation rules
[oota-llvm.git] / lib / MC / 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 //===----------------------------------------------------------------------===//
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
26 namespace llvm {
27
28 namespace {
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 //
49 class InstrRegInfoHolder {
50   typedef StringMap<unsigned, BumpPtrAllocator> EnumValByNameTy;
51   EnumValByNameTy InstEnumValueByName;
52   EnumValByNameTy RegEnumValueByName;
53
54 public:
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
84 namespace MCModuleYAML {
85
86 LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum)
87
88 struct Operand {
89   MCOperand MCOp;
90 };
91
92 struct Inst {
93   OpcodeEnum Opcode;
94   std::vector<Operand> Operands;
95   uint64_t Size;
96 };
97
98 struct 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
107 struct BasicBlock {
108   yaml::Hex64 Address;
109   std::vector<yaml::Hex64> Preds;
110   std::vector<yaml::Hex64> Succs;
111 };
112
113 struct Function {
114   StringRef Name;
115   std::vector<BasicBlock> BasicBlocks;
116 };
117
118 struct Module {
119   std::vector<Atom> Atoms;
120   std::vector<Function> Functions;
121 };
122
123 } // end namespace MCModuleYAML
124 } // end namespace llvm
125
126 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
127 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::MCModuleYAML::Operand)
128 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Inst)
129 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Atom)
130 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::BasicBlock)
131 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Function)
132
133 namespace llvm {
134
135 namespace yaml {
136
137 template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> {
138   static void enumeration(IO &IO, MCAtom::AtomKind &Kind);
139 };
140
141 template <> struct MappingTraits<MCModuleYAML::Atom> {
142   static void mapping(IO &IO, MCModuleYAML::Atom &A);
143 };
144
145 template <> struct MappingTraits<MCModuleYAML::Inst> {
146   static void mapping(IO &IO, MCModuleYAML::Inst &I);
147 };
148
149 template <> struct MappingTraits<MCModuleYAML::BasicBlock> {
150   static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB);
151 };
152
153 template <> struct MappingTraits<MCModuleYAML::Function> {
154   static void mapping(IO &IO, MCModuleYAML::Function &Fn);
155 };
156
157 template <> struct MappingTraits<MCModuleYAML::Module> {
158   static void mapping(IO &IO, MCModuleYAML::Module &M);
159 };
160
161 template <> 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   static bool mustQuote(StringRef) { return false; }
166 };
167
168 template <> struct ScalarTraits<MCModuleYAML::OpcodeEnum> {
169   static void output(const MCModuleYAML::OpcodeEnum &, void *,
170                      llvm::raw_ostream &);
171   static StringRef input(StringRef, void *, MCModuleYAML::OpcodeEnum &);
172   static bool mustQuote(StringRef) { return false; }
173 };
174
175 void ScalarEnumerationTraits<MCAtom::AtomKind>::enumeration(
176     IO &IO, MCAtom::AtomKind &Value) {
177   IO.enumCase(Value, "Text", MCAtom::TextAtom);
178   IO.enumCase(Value, "Data", MCAtom::DataAtom);
179 }
180
181 void MappingTraits<MCModuleYAML::Atom>::mapping(IO &IO, MCModuleYAML::Atom &A) {
182   IO.mapRequired("StartAddress", A.StartAddress);
183   IO.mapRequired("Size", A.Size);
184   IO.mapRequired("Type", A.Type);
185   if (A.Type == MCAtom::TextAtom)
186     IO.mapRequired("Content", A.Insts);
187   else if (A.Type == MCAtom::DataAtom)
188     IO.mapRequired("Content", A.Data);
189 }
190
191 void MappingTraits<MCModuleYAML::Inst>::mapping(IO &IO, MCModuleYAML::Inst &I) {
192   IO.mapRequired("Inst", I.Opcode);
193   IO.mapRequired("Size", I.Size);
194   IO.mapRequired("Ops", I.Operands);
195 }
196
197 void
198 MappingTraits<MCModuleYAML::BasicBlock>::mapping(IO &IO,
199                                                  MCModuleYAML::BasicBlock &BB) {
200   IO.mapRequired("Address", BB.Address);
201   IO.mapRequired("Preds", BB.Preds);
202   IO.mapRequired("Succs", BB.Succs);
203 }
204
205 void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO,
206                                                     MCModuleYAML::Function &F) {
207   IO.mapRequired("Name", F.Name);
208   IO.mapRequired("BasicBlocks", F.BasicBlocks);
209 }
210
211 void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO,
212                                                   MCModuleYAML::Module &M) {
213   IO.mapRequired("Atoms", M.Atoms);
214   IO.mapOptional("Functions", M.Functions);
215 }
216
217 void
218 ScalarTraits<MCModuleYAML::Operand>::output(const MCModuleYAML::Operand &Val,
219                                             void *Ctx, raw_ostream &Out) {
220   InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx;
221
222   // FIXME: Doesn't support FPImm and expr/inst, but do these make sense?
223   if (Val.MCOp.isImm())
224     Out << "I" << Val.MCOp.getImm();
225   else if (Val.MCOp.isReg())
226     Out << "R" << IRI->MRI.getName(Val.MCOp.getReg());
227   else
228     llvm_unreachable("Trying to output invalid MCOperand!");
229 }
230
231 StringRef
232 ScalarTraits<MCModuleYAML::Operand>::input(StringRef Scalar, void *Ctx,
233                                            MCModuleYAML::Operand &Val) {
234   InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx;
235   char Type = 0;
236   if (Scalar.size() >= 1)
237     Type = Scalar.front();
238   if (Type != 'R' && Type != 'I')
239     return "Operand must start with 'R' (register) or 'I' (immediate).";
240   if (Type == 'R') {
241     unsigned Reg;
242     if (!IRI->matchRegister(Scalar.substr(1), Reg))
243       return "Invalid register name.";
244     Val.MCOp = MCOperand::CreateReg(Reg);
245   } else if (Type == 'I') {
246     int64_t RIVal;
247     if (Scalar.substr(1).getAsInteger(10, RIVal))
248       return "Invalid immediate value.";
249     Val.MCOp = MCOperand::CreateImm(RIVal);
250   } else {
251     Val.MCOp = MCOperand();
252   }
253   return StringRef();
254 }
255
256 void ScalarTraits<MCModuleYAML::OpcodeEnum>::output(
257     const MCModuleYAML::OpcodeEnum &Val, void *Ctx, raw_ostream &Out) {
258   InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx;
259   Out << IRI->MII.getName(Val);
260 }
261
262 StringRef
263 ScalarTraits<MCModuleYAML::OpcodeEnum>::input(StringRef Scalar, void *Ctx,
264                                               MCModuleYAML::OpcodeEnum &Val) {
265   InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx;
266   unsigned Opc;
267   if (!IRI->matchOpcode(Scalar, Opc))
268     return "Invalid instruction opcode.";
269   Val = Opc;
270   return "";
271 }
272
273 } // end namespace yaml
274
275 namespace {
276
277 class MCModule2YAML {
278   const MCModule &MCM;
279   MCModuleYAML::Module YAMLModule;
280   void dumpAtom(const MCAtom *MCA);
281   void dumpFunction(const MCFunction *MCF);
282   void dumpBasicBlock(const MCBasicBlock *MCBB);
283
284 public:
285   MCModule2YAML(const MCModule &MCM);
286   MCModuleYAML::Module &getYAMLModule();
287 };
288
289 class YAML2MCModule {
290   MCModule &MCM;
291
292 public:
293   YAML2MCModule(MCModule &MCM);
294   StringRef parse(const MCModuleYAML::Module &YAMLModule);
295 };
296
297 } // end unnamed namespace
298
299 MCModule2YAML::MCModule2YAML(const MCModule &MCM) : MCM(MCM), YAMLModule() {
300   for (MCModule::const_atom_iterator AI = MCM.atom_begin(), AE = MCM.atom_end();
301        AI != AE; ++AI)
302     dumpAtom(*AI);
303   for (MCModule::const_func_iterator FI = MCM.func_begin(), FE = MCM.func_end();
304        FI != FE; ++FI)
305     dumpFunction(*FI);
306 }
307
308 void MCModule2YAML::dumpAtom(const MCAtom *MCA) {
309   YAMLModule.Atoms.resize(YAMLModule.Atoms.size() + 1);
310   MCModuleYAML::Atom &A = YAMLModule.Atoms.back();
311   A.Type = MCA->getKind();
312   A.StartAddress = MCA->getBeginAddr();
313   A.Size = MCA->getEndAddr() - MCA->getBeginAddr() + 1;
314   if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(MCA)) {
315     const size_t InstCount = TA->size();
316     A.Insts.resize(InstCount);
317     for (size_t i = 0; i != InstCount; ++i) {
318       const MCDecodedInst &MCDI = TA->at(i);
319       A.Insts[i].Opcode = MCDI.Inst.getOpcode();
320       A.Insts[i].Size = MCDI.Size;
321       const unsigned OpCount = MCDI.Inst.getNumOperands();
322       A.Insts[i].Operands.resize(OpCount);
323       for (unsigned oi = 0; oi != OpCount; ++oi)
324         A.Insts[i].Operands[oi].MCOp = MCDI.Inst.getOperand(oi);
325     }
326   } else if (const MCDataAtom *DA = dyn_cast<MCDataAtom>(MCA)) {
327     A.Data = DA->getData();
328   } else {
329     llvm_unreachable("Unknown atom type.");
330   }
331 }
332
333 void MCModule2YAML::dumpFunction(const MCFunction *MCF) {
334   YAMLModule.Functions.resize(YAMLModule.Functions.size() + 1);
335   MCModuleYAML::Function &F = YAMLModule.Functions.back();
336   F.Name = MCF->getName();
337   for (MCFunction::const_iterator BBI = MCF->begin(), BBE = MCF->end();
338        BBI != BBE; ++BBI) {
339     const MCBasicBlock *MCBB = *BBI;
340     F.BasicBlocks.resize(F.BasicBlocks.size() + 1);
341     MCModuleYAML::BasicBlock &BB = F.BasicBlocks.back();
342     BB.Address = MCBB->getInsts()->getBeginAddr();
343     for (MCBasicBlock::pred_const_iterator PI = MCBB->pred_begin(),
344                                            PE = MCBB->pred_end();
345          PI != PE; ++PI)
346       BB.Preds.push_back((*PI)->getInsts()->getBeginAddr());
347     for (MCBasicBlock::succ_const_iterator SI = MCBB->succ_begin(),
348                                            SE = MCBB->succ_end();
349          SI != SE; ++SI)
350       BB.Succs.push_back((*SI)->getInsts()->getBeginAddr());
351   }
352 }
353
354 MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; }
355
356 YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {}
357
358 StringRef YAML2MCModule::parse(const MCModuleYAML::Module &YAMLModule) {
359   typedef std::vector<MCModuleYAML::Atom>::const_iterator AtomIt;
360   typedef std::vector<MCModuleYAML::Inst>::const_iterator InstIt;
361   typedef std::vector<MCModuleYAML::Operand>::const_iterator OpIt;
362
363   typedef DenseMap<uint64_t, MCTextAtom *> AddrToTextAtomTy;
364   AddrToTextAtomTy TAByAddr;
365
366   for (AtomIt AI = YAMLModule.Atoms.begin(), AE = YAMLModule.Atoms.end();
367        AI != AE; ++AI) {
368     uint64_t StartAddress = AI->StartAddress;
369     if (AI->Size == 0)
370       return "Atoms can't be empty!";
371     uint64_t EndAddress = StartAddress + AI->Size - 1;
372     switch (AI->Type) {
373     case MCAtom::TextAtom: {
374       MCTextAtom *TA = MCM.createTextAtom(StartAddress, EndAddress);
375       TAByAddr[StartAddress] = TA;
376       for (InstIt II = AI->Insts.begin(), IE = AI->Insts.end(); II != IE;
377            ++II) {
378         MCInst MI;
379         MI.setOpcode(II->Opcode);
380         for (OpIt OI = II->Operands.begin(), OE = II->Operands.end(); OI != OE;
381              ++OI)
382           MI.addOperand(OI->MCOp);
383         TA->addInst(MI, II->Size);
384       }
385       break;
386     }
387     case MCAtom::DataAtom: {
388       MCDataAtom *DA = MCM.createDataAtom(StartAddress, EndAddress);
389       SmallVector<char, 64> Data;
390       raw_svector_ostream OS(Data);
391       AI->Data.writeAsBinary(OS);
392       OS.flush();
393       for (size_t i = 0, e = Data.size(); i != e; ++i)
394         DA->addData((uint8_t)Data[i]);
395       break;
396     }
397     }
398   }
399
400   typedef std::vector<MCModuleYAML::Function>::const_iterator FuncIt;
401   typedef std::vector<MCModuleYAML::BasicBlock>::const_iterator BBIt;
402   typedef std::vector<yaml::Hex64>::const_iterator AddrIt;
403   for (FuncIt FI = YAMLModule.Functions.begin(),
404               FE = YAMLModule.Functions.end();
405        FI != FE; ++FI) {
406     MCFunction *MCFN = MCM.createFunction(FI->Name);
407     for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end();
408          BBI != BBE; ++BBI) {
409       AddrToTextAtomTy::const_iterator It = TAByAddr.find(BBI->Address);
410       if (It == TAByAddr.end())
411         return "Basic block start address doesn't match any text atom!";
412       MCFN->createBlock(*It->second);
413     }
414     for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end();
415          BBI != BBE; ++BBI) {
416       MCBasicBlock *MCBB = MCFN->find(BBI->Address);
417       if (!MCBB)
418         return "Couldn't find matching basic block in function.";
419       for (AddrIt PI = BBI->Preds.begin(), PE = BBI->Preds.end(); PI != PE;
420            ++PI) {
421         MCBasicBlock *Pred = MCFN->find(*PI);
422         if (!Pred)
423           return "Couldn't find predecessor basic block.";
424         MCBB->addPredecessor(Pred);
425       }
426       for (AddrIt SI = BBI->Succs.begin(), SE = BBI->Succs.end(); SI != SE;
427            ++SI) {
428         MCBasicBlock *Succ = MCFN->find(*SI);
429         if (!Succ)
430           return "Couldn't find predecessor basic block.";
431         MCBB->addSuccessor(Succ);
432       }
433     }
434   }
435   return "";
436 }
437
438 StringRef mcmodule2yaml(raw_ostream &OS, const MCModule &MCM,
439                         const MCInstrInfo &MII, const MCRegisterInfo &MRI) {
440   MCModule2YAML Dumper(MCM);
441   InstrRegInfoHolder IRI(MII, MRI);
442   yaml::Output YOut(OS, (void *)&IRI);
443   YOut << Dumper.getYAMLModule();
444   return "";
445 }
446
447 StringRef yaml2mcmodule(std::unique_ptr<MCModule> &MCM, StringRef YamlContent,
448                         const MCInstrInfo &MII, const MCRegisterInfo &MRI) {
449   MCM.reset(new MCModule);
450   YAML2MCModule Parser(*MCM);
451   MCModuleYAML::Module YAMLModule;
452   InstrRegInfoHolder IRI(MII, MRI);
453   yaml::Input YIn(YamlContent, (void *)&IRI);
454   YIn >> YAMLModule;
455   if (error_code ec = YIn.error())
456     return ec.message();
457   StringRef err = Parser.parse(YAMLModule);
458   if (!err.empty())
459     return err;
460   return "";
461 }
462
463 } // end namespace llvm