1*1a427287SDan Gohman //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==//
2*1a427287SDan Gohman //
3*1a427287SDan Gohman //                     The LLVM Compiler Infrastructure
4*1a427287SDan Gohman //
5*1a427287SDan Gohman // This file is distributed under the University of Illinois Open Source
6*1a427287SDan Gohman // License. See LICENSE.TXT for details.
7*1a427287SDan Gohman //
8*1a427287SDan Gohman //===----------------------------------------------------------------------===//
9*1a427287SDan Gohman ///
10*1a427287SDan Gohman /// \file
11*1a427287SDan Gohman /// \brief This file is part of the WebAssembly Disassembler.
12*1a427287SDan Gohman ///
13*1a427287SDan Gohman /// It contains code to translate the data produced by the decoder into
14*1a427287SDan Gohman /// MCInsts.
15*1a427287SDan Gohman ///
16*1a427287SDan Gohman //===----------------------------------------------------------------------===//
17*1a427287SDan Gohman 
18*1a427287SDan Gohman #include "WebAssembly.h"
19*1a427287SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20*1a427287SDan Gohman #include "llvm/MC/MCContext.h"
21*1a427287SDan Gohman #include "llvm/MC/MCDisassembler.h"
22*1a427287SDan Gohman #include "llvm/MC/MCInst.h"
23*1a427287SDan Gohman #include "llvm/MC/MCInstrInfo.h"
24*1a427287SDan Gohman #include "llvm/MC/MCSubtargetInfo.h"
25*1a427287SDan Gohman #include "llvm/MC/MCSymbol.h"
26*1a427287SDan Gohman #include "llvm/Support/Endian.h"
27*1a427287SDan Gohman #include "llvm/Support/TargetRegistry.h"
28*1a427287SDan Gohman using namespace llvm;
29*1a427287SDan Gohman 
30*1a427287SDan Gohman #define DEBUG_TYPE "wasm-disassembler"
31*1a427287SDan Gohman 
32*1a427287SDan Gohman namespace {
33*1a427287SDan Gohman class WebAssemblyDisassembler final : public MCDisassembler {
34*1a427287SDan Gohman   std::unique_ptr<const MCInstrInfo> MCII;
35*1a427287SDan Gohman 
36*1a427287SDan Gohman   DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
37*1a427287SDan Gohman                               ArrayRef<uint8_t> Bytes, uint64_t Address,
38*1a427287SDan Gohman                               raw_ostream &VStream,
39*1a427287SDan Gohman                               raw_ostream &CStream) const override;
40*1a427287SDan Gohman 
41*1a427287SDan Gohman public:
42*1a427287SDan Gohman   WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
43*1a427287SDan Gohman                           std::unique_ptr<const MCInstrInfo> MCII)
44*1a427287SDan Gohman       : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
45*1a427287SDan Gohman };
46*1a427287SDan Gohman } // end anonymous namespace
47*1a427287SDan Gohman 
48*1a427287SDan Gohman static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
49*1a427287SDan Gohman                                                      const MCSubtargetInfo &STI,
50*1a427287SDan Gohman                                                      MCContext &Ctx) {
51*1a427287SDan Gohman   std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
52*1a427287SDan Gohman   return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
53*1a427287SDan Gohman }
54*1a427287SDan Gohman 
55*1a427287SDan Gohman extern "C" void LLVMInitializeWebAssemblyDisassembler() {
56*1a427287SDan Gohman   // Register the disassembler for each target.
57*1a427287SDan Gohman   TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget32,
58*1a427287SDan Gohman                                          createWebAssemblyDisassembler);
59*1a427287SDan Gohman   TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget64,
60*1a427287SDan Gohman                                          createWebAssemblyDisassembler);
61*1a427287SDan Gohman }
62*1a427287SDan Gohman 
63*1a427287SDan Gohman MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
64*1a427287SDan Gohman     MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
65*1a427287SDan Gohman     raw_ostream &OS, raw_ostream &CS) const {
66*1a427287SDan Gohman   Size = 0;
67*1a427287SDan Gohman   uint64_t Pos = 0;
68*1a427287SDan Gohman 
69*1a427287SDan Gohman   // Read the opcode.
70*1a427287SDan Gohman   if (Pos + sizeof(uint64_t) > Bytes.size())
71*1a427287SDan Gohman     return MCDisassembler::Fail;
72*1a427287SDan Gohman   uint64_t Opcode = support::endian::read64le(Bytes.data() + Pos);
73*1a427287SDan Gohman   Pos += sizeof(uint64_t);
74*1a427287SDan Gohman 
75*1a427287SDan Gohman   if (Opcode >= WebAssembly::INSTRUCTION_LIST_END)
76*1a427287SDan Gohman     return MCDisassembler::Fail;
77*1a427287SDan Gohman 
78*1a427287SDan Gohman   MI.setOpcode(Opcode);
79*1a427287SDan Gohman   const MCInstrDesc &Desc = MCII->get(Opcode);
80*1a427287SDan Gohman   unsigned NumFixedOperands = Desc.NumOperands;
81*1a427287SDan Gohman 
82*1a427287SDan Gohman   // If it's variadic, read the number of extra operands.
83*1a427287SDan Gohman   unsigned NumExtraOperands = 0;
84*1a427287SDan Gohman   if (Desc.isVariadic()) {
85*1a427287SDan Gohman     if (Pos + sizeof(uint64_t) > Bytes.size())
86*1a427287SDan Gohman       return MCDisassembler::Fail;
87*1a427287SDan Gohman     NumExtraOperands = support::endian::read64le(Bytes.data() + Pos);
88*1a427287SDan Gohman     Pos += sizeof(uint64_t);
89*1a427287SDan Gohman   }
90*1a427287SDan Gohman 
91*1a427287SDan Gohman   // Read the fixed operands. These are described by the MCInstrDesc.
92*1a427287SDan Gohman   for (unsigned i = 0; i < NumFixedOperands; ++i) {
93*1a427287SDan Gohman     const MCOperandInfo &Info = Desc.OpInfo[i];
94*1a427287SDan Gohman     switch (Info.OperandType) {
95*1a427287SDan Gohman     case MCOI::OPERAND_IMMEDIATE:
96*1a427287SDan Gohman     case WebAssembly::OPERAND_BASIC_BLOCK: {
97*1a427287SDan Gohman       if (Pos + sizeof(uint64_t) > Bytes.size())
98*1a427287SDan Gohman         return MCDisassembler::Fail;
99*1a427287SDan Gohman       uint64_t Imm = support::endian::read64le(Bytes.data() + Pos);
100*1a427287SDan Gohman       Pos += sizeof(uint64_t);
101*1a427287SDan Gohman       MI.addOperand(MCOperand::createImm(Imm));
102*1a427287SDan Gohman       break;
103*1a427287SDan Gohman     }
104*1a427287SDan Gohman     case MCOI::OPERAND_REGISTER: {
105*1a427287SDan Gohman       if (Pos + sizeof(uint64_t) > Bytes.size())
106*1a427287SDan Gohman         return MCDisassembler::Fail;
107*1a427287SDan Gohman       uint64_t Reg = support::endian::read64le(Bytes.data() + Pos);
108*1a427287SDan Gohman       Pos += sizeof(uint64_t);
109*1a427287SDan Gohman       MI.addOperand(MCOperand::createReg(Reg));
110*1a427287SDan Gohman       break;
111*1a427287SDan Gohman     }
112*1a427287SDan Gohman     case WebAssembly::OPERAND_FPIMM: {
113*1a427287SDan Gohman       // TODO: MC converts all floating point immediate operands to double.
114*1a427287SDan Gohman       // This is fine for numeric values, but may cause NaNs to change bits.
115*1a427287SDan Gohman       if (Pos + sizeof(uint64_t) > Bytes.size())
116*1a427287SDan Gohman         return MCDisassembler::Fail;
117*1a427287SDan Gohman       uint64_t Bits = support::endian::read64le(Bytes.data() + Pos);
118*1a427287SDan Gohman       Pos += sizeof(uint64_t);
119*1a427287SDan Gohman       double Imm;
120*1a427287SDan Gohman       memcpy(&Imm, &Bits, sizeof(Imm));
121*1a427287SDan Gohman       MI.addOperand(MCOperand::createFPImm(Imm));
122*1a427287SDan Gohman       break;
123*1a427287SDan Gohman     }
124*1a427287SDan Gohman     default:
125*1a427287SDan Gohman       llvm_unreachable("unimplemented operand kind");
126*1a427287SDan Gohman     }
127*1a427287SDan Gohman   }
128*1a427287SDan Gohman 
129*1a427287SDan Gohman   // Read the extra operands.
130*1a427287SDan Gohman   assert(NumExtraOperands == 0 || Desc.isVariadic());
131*1a427287SDan Gohman   for (unsigned i = 0; i < NumExtraOperands; ++i) {
132*1a427287SDan Gohman     if (Pos + sizeof(uint64_t) > Bytes.size())
133*1a427287SDan Gohman       return MCDisassembler::Fail;
134*1a427287SDan Gohman     if (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate) {
135*1a427287SDan Gohman       // Decode extra immediate operands.
136*1a427287SDan Gohman       uint64_t Imm = support::endian::read64le(Bytes.data() + Pos);
137*1a427287SDan Gohman       MI.addOperand(MCOperand::createImm(Imm));
138*1a427287SDan Gohman     } else {
139*1a427287SDan Gohman       // Decode extra register operands.
140*1a427287SDan Gohman       uint64_t Reg = support::endian::read64le(Bytes.data() + Pos);
141*1a427287SDan Gohman       MI.addOperand(MCOperand::createReg(Reg));
142*1a427287SDan Gohman     }
143*1a427287SDan Gohman     Pos += sizeof(uint64_t);
144*1a427287SDan Gohman   }
145*1a427287SDan Gohman 
146*1a427287SDan Gohman   Size = Pos;
147*1a427287SDan Gohman   return MCDisassembler::Success;
148*1a427287SDan Gohman }
149