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