]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / WebAssembly / Disassembler / WebAssemblyDisassembler.cpp
1 //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==//
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 /// \file
11 /// This file is part of the WebAssembly Disassembler.
12 ///
13 /// It contains code to translate the data produced by the decoder into
14 /// MCInsts.
15 ///
16 //===----------------------------------------------------------------------===//
17
18 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
21 #include "llvm/MC/MCFixedLenDisassembler.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/MC/MCSymbol.h"
26 #include "llvm/Support/Endian.h"
27 #include "llvm/Support/LEB128.h"
28 #include "llvm/Support/TargetRegistry.h"
29
30 using namespace llvm;
31
32 #define DEBUG_TYPE "wasm-disassembler"
33
34 using DecodeStatus = MCDisassembler::DecodeStatus;
35
36 #include "WebAssemblyGenDisassemblerTables.inc"
37
38 namespace {
39 static constexpr int WebAssemblyInstructionTableSize = 256;
40
41 class WebAssemblyDisassembler final : public MCDisassembler {
42   std::unique_ptr<const MCInstrInfo> MCII;
43
44   DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
45                               ArrayRef<uint8_t> Bytes, uint64_t Address,
46                               raw_ostream &VStream,
47                               raw_ostream &CStream) const override;
48
49 public:
50   WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
51                           std::unique_ptr<const MCInstrInfo> MCII)
52       : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
53 };
54 } // end anonymous namespace
55
56 static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
57                                                      const MCSubtargetInfo &STI,
58                                                      MCContext &Ctx) {
59   std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
60   return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
61 }
62
63 extern "C" void LLVMInitializeWebAssemblyDisassembler() {
64   // Register the disassembler for each target.
65   TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
66                                          createWebAssemblyDisassembler);
67   TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
68                                          createWebAssemblyDisassembler);
69 }
70
71 static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
72   if (Size >= Bytes.size())
73     return -1;
74   auto V = Bytes[Size];
75   Size++;
76   return V;
77 }
78
79 static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
80                     bool Signed = false) {
81   unsigned N = 0;
82   const char *Error = nullptr;
83   Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
84                                Bytes.data() + Bytes.size(), &Error)
85                : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,
86                                                     Bytes.data() + Bytes.size(),
87                                                     &Error));
88   if (Error)
89     return false;
90   Size += N;
91   return true;
92 }
93
94 static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
95                               ArrayRef<uint8_t> Bytes, bool Signed) {
96   int64_t Val;
97   if (!nextLEB(Val, Bytes, Size, Signed))
98     return false;
99   MI.addOperand(MCOperand::createImm(Val));
100   return true;
101 }
102
103 template <typename T>
104 bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
105   if (Size + sizeof(T) > Bytes.size())
106     return false;
107   T Val;
108   memcpy(&Val, Bytes.data() + Size, sizeof(T));
109   support::endian::byte_swap<T, support::endianness::little>(Val);
110   Size += sizeof(T);
111   if (std::is_floating_point<T>::value) {
112     MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
113   } else {
114     MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
115   }
116   return true;
117 }
118
119 MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
120     MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
121     raw_ostream & /*OS*/, raw_ostream &CS) const {
122   CommentStream = &CS;
123   Size = 0;
124   int Opc = nextByte(Bytes, Size);
125   if (Opc < 0)
126     return MCDisassembler::Fail;
127   const auto *WasmInst = &InstructionTable0[Opc];
128   // If this is a prefix byte, indirect to another table.
129   if (WasmInst->ET == ET_Prefix) {
130     WasmInst = nullptr;
131     // Linear search, so far only 2 entries.
132     for (auto PT = PrefixTable; PT->Table; PT++) {
133       if (PT->Prefix == Opc) {
134         WasmInst = PT->Table;
135         break;
136       }
137     }
138     if (!WasmInst)
139       return MCDisassembler::Fail;
140     int64_t PrefixedOpc;
141     if (!nextLEB(PrefixedOpc, Bytes, Size))
142       return MCDisassembler::Fail;
143     if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
144       return MCDisassembler::Fail;
145     WasmInst += PrefixedOpc;
146   }
147   if (WasmInst->ET == ET_Unused)
148     return MCDisassembler::Fail;
149   // At this point we must have a valid instruction to decode.
150   assert(WasmInst->ET == ET_Instruction);
151   MI.setOpcode(WasmInst->Opcode);
152   // Parse any operands.
153   for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
154     auto OT = OperandTable[WasmInst->OperandStart + OPI];
155     switch (OT) {
156     // ULEB operands:
157     case WebAssembly::OPERAND_BASIC_BLOCK:
158     case WebAssembly::OPERAND_LOCAL:
159     case WebAssembly::OPERAND_GLOBAL:
160     case WebAssembly::OPERAND_FUNCTION32:
161     case WebAssembly::OPERAND_OFFSET32:
162     case WebAssembly::OPERAND_P2ALIGN:
163     case WebAssembly::OPERAND_TYPEINDEX:
164     case MCOI::OPERAND_IMMEDIATE: {
165       if (!parseLEBImmediate(MI, Size, Bytes, false))
166         return MCDisassembler::Fail;
167       break;
168     }
169     // SLEB operands:
170     case WebAssembly::OPERAND_I32IMM:
171     case WebAssembly::OPERAND_I64IMM: {
172       if (!parseLEBImmediate(MI, Size, Bytes, true))
173         return MCDisassembler::Fail;
174       break;
175     }
176     // block_type operands (uint8_t).
177     case WebAssembly::OPERAND_SIGNATURE: {
178       if (!parseImmediate<uint8_t>(MI, Size, Bytes))
179         return MCDisassembler::Fail;
180       break;
181     }
182     // FP operands.
183     case WebAssembly::OPERAND_F32IMM: {
184       if (!parseImmediate<float>(MI, Size, Bytes))
185         return MCDisassembler::Fail;
186       break;
187     }
188     case WebAssembly::OPERAND_F64IMM: {
189       if (!parseImmediate<double>(MI, Size, Bytes))
190         return MCDisassembler::Fail;
191       break;
192     }
193     // Vector lane operands (not LEB encoded).
194     case WebAssembly::OPERAND_VEC_I8IMM: {
195       if (!parseImmediate<uint8_t>(MI, Size, Bytes))
196         return MCDisassembler::Fail;
197       break;
198     }
199     case WebAssembly::OPERAND_VEC_I16IMM: {
200       if (!parseImmediate<uint16_t>(MI, Size, Bytes))
201         return MCDisassembler::Fail;
202       break;
203     }
204     case WebAssembly::OPERAND_VEC_I32IMM: {
205       if (!parseImmediate<uint32_t>(MI, Size, Bytes))
206         return MCDisassembler::Fail;
207       break;
208     }
209     case WebAssembly::OPERAND_VEC_I64IMM: {
210       if (!parseImmediate<uint64_t>(MI, Size, Bytes))
211         return MCDisassembler::Fail;
212       break;
213     }
214     case WebAssembly::OPERAND_BRLIST: {
215       int64_t TargetTableLen;
216       if (!nextLEB(TargetTableLen, Bytes, Size, false))
217         return MCDisassembler::Fail;
218       for (int64_t I = 0; I < TargetTableLen; I++) {
219         if (!parseLEBImmediate(MI, Size, Bytes, false))
220           return MCDisassembler::Fail;
221       }
222       // Default case.
223       if (!parseLEBImmediate(MI, Size, Bytes, false))
224         return MCDisassembler::Fail;
225       break;
226     }
227     case MCOI::OPERAND_REGISTER:
228       // The tablegen header currently does not have any register operands since
229       // we use only the stack (_S) instructions.
230       // If you hit this that probably means a bad instruction definition in
231       // tablegen.
232       llvm_unreachable("Register operand in WebAssemblyDisassembler");
233     default:
234       llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
235     }
236   }
237   return MCDisassembler::Success;
238 }