blob: 93180b918d2c588d43d0b742debe3ef907e5ab5d [file] [log] [blame]
Ahmed Bougacha17926472013-08-21 07:29:02 +00001//===- 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
26namespace llvm {
27
28namespace {
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//
49class InstrRegInfoHolder {
50 typedef StringMap<unsigned, BumpPtrAllocator> EnumValByNameTy;
51 EnumValByNameTy InstEnumValueByName;
52 EnumValByNameTy RegEnumValueByName;
53
54public:
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
84namespace MCModuleYAML {
85
86LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum)
87
88struct Operand {
89 MCOperand MCOp;
90};
91
92struct Inst {
93 OpcodeEnum Opcode;
94 std::vector<Operand> Operands;
95 uint64_t Size;
96};
97
98struct 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
107struct BasicBlock {
108 yaml::Hex64 Address;
109 std::vector<yaml::Hex64> Preds;
110 std::vector<yaml::Hex64> Succs;
111};
112
113struct Function {
114 StringRef Name;
115 std::vector<BasicBlock> BasicBlocks;
116};
117
118struct Module {
119 std::vector<Atom> Atoms;
120 std::vector<Function> Functions;
121};
122
123} // end namespace MCModuleYAML
124} // end namespace llvm
125
126LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
127LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::MCModuleYAML::Operand)
128LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Inst)
129LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Atom)
130LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::BasicBlock)
131LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Function)
132
133namespace llvm {
134
135namespace yaml {
136
137template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> {
138 static void enumeration(IO &IO, MCAtom::AtomKind &Kind);
139};
140
141template <> struct MappingTraits<MCModuleYAML::Atom> {
142 static void mapping(IO &IO, MCModuleYAML::Atom &A);
143};
144
145template <> struct MappingTraits<MCModuleYAML::Inst> {
146 static void mapping(IO &IO, MCModuleYAML::Inst &I);
147};
148
149template <> struct MappingTraits<MCModuleYAML::BasicBlock> {
150 static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB);
151};
152
153template <> struct MappingTraits<MCModuleYAML::Function> {
154 static void mapping(IO &IO, MCModuleYAML::Function &Fn);
155};
156
157template <> struct MappingTraits<MCModuleYAML::Module> {
158 static void mapping(IO &IO, MCModuleYAML::Module &M);
159};
160
161template <> struct ScalarTraits<MCModuleYAML::Operand> {
162 static void output(const MCModuleYAML::Operand &, void *,
163 llvm::raw_ostream &);
164 static StringRef input(StringRef, void *, MCModuleYAML::Operand &);
David Majnemer77880332014-04-10 07:37:33 +0000165 static bool mustQuote(StringRef) { return false; }
Ahmed Bougacha17926472013-08-21 07:29:02 +0000166};
167
168template <> struct ScalarTraits<MCModuleYAML::OpcodeEnum> {
169 static void output(const MCModuleYAML::OpcodeEnum &, void *,
170 llvm::raw_ostream &);
171 static StringRef input(StringRef, void *, MCModuleYAML::OpcodeEnum &);
David Majnemer77880332014-04-10 07:37:33 +0000172 static bool mustQuote(StringRef) { return false; }
Ahmed Bougacha17926472013-08-21 07:29:02 +0000173};
174
175void 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
181void 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
191void 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
197void
198MappingTraits<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
205void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO,
206 MCModuleYAML::Function &F) {
207 IO.mapRequired("Name", F.Name);
208 IO.mapRequired("BasicBlocks", F.BasicBlocks);
209}
210
211void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO,
212 MCModuleYAML::Module &M) {
213 IO.mapRequired("Atoms", M.Atoms);
214 IO.mapOptional("Functions", M.Functions);
215}
216
217void
218ScalarTraits<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
231StringRef
232ScalarTraits<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
256void 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
262StringRef
263ScalarTraits<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
275namespace {
276
277class MCModule2YAML {
278 const MCModule &MCM;
279 MCModuleYAML::Module YAMLModule;
280 void dumpAtom(const MCAtom *MCA);
David Blaikiebb97e1b2014-04-15 05:15:19 +0000281 void dumpFunction(const MCFunction &MCF);
Ahmed Bougacha17926472013-08-21 07:29:02 +0000282 void dumpBasicBlock(const MCBasicBlock *MCBB);
283
284public:
285 MCModule2YAML(const MCModule &MCM);
286 MCModuleYAML::Module &getYAMLModule();
287};
288
289class YAML2MCModule {
290 MCModule &MCM;
291
292public:
293 YAML2MCModule(MCModule &MCM);
294 StringRef parse(const MCModuleYAML::Module &YAMLModule);
295};
296
297} // end unnamed namespace
298
299MCModule2YAML::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)
David Blaikiebb97e1b2014-04-15 05:15:19 +0000305 dumpFunction(**FI);
Ahmed Bougacha17926472013-08-21 07:29:02 +0000306}
307
308void 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
David Blaikiebb97e1b2014-04-15 05:15:19 +0000333void MCModule2YAML::dumpFunction(const MCFunction &MCF) {
Ahmed Bougacha17926472013-08-21 07:29:02 +0000334 YAMLModule.Functions.resize(YAMLModule.Functions.size() + 1);
335 MCModuleYAML::Function &F = YAMLModule.Functions.back();
David Blaikiebb97e1b2014-04-15 05:15:19 +0000336 F.Name = MCF.getName();
337 for (MCFunction::const_iterator BBI = MCF.begin(), BBE = MCF.end();
Ahmed Bougacha17926472013-08-21 07:29:02 +0000338 BBI != BBE; ++BBI) {
David Blaikie4a7a0502014-04-15 04:56:29 +0000339 const MCBasicBlock &MCBB = **BBI;
Ahmed Bougacha17926472013-08-21 07:29:02 +0000340 F.BasicBlocks.resize(F.BasicBlocks.size() + 1);
341 MCModuleYAML::BasicBlock &BB = F.BasicBlocks.back();
David Blaikie4a7a0502014-04-15 04:56:29 +0000342 BB.Address = MCBB.getInsts()->getBeginAddr();
343 for (MCBasicBlock::pred_const_iterator PI = MCBB.pred_begin(),
344 PE = MCBB.pred_end();
Ahmed Bougacha17926472013-08-21 07:29:02 +0000345 PI != PE; ++PI)
346 BB.Preds.push_back((*PI)->getInsts()->getBeginAddr());
David Blaikie4a7a0502014-04-15 04:56:29 +0000347 for (MCBasicBlock::succ_const_iterator SI = MCBB.succ_begin(),
348 SE = MCBB.succ_end();
Ahmed Bougacha17926472013-08-21 07:29:02 +0000349 SI != SE; ++SI)
350 BB.Succs.push_back((*SI)->getInsts()->getBeginAddr());
351 }
352}
353
354MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; }
355
356YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {}
357
358StringRef 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
438StringRef 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
Ahmed Charles56440fd2014-03-06 05:51:42 +0000447StringRef yaml2mcmodule(std::unique_ptr<MCModule> &MCM, StringRef YamlContent,
Ahmed Bougacha17926472013-08-21 07:29:02 +0000448 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