xref: /llvm-project/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp (revision d064d3fc2cf8841963151f428988475aab09ff56)
1 //===-- XtensaDisassembler.cpp - Disassembler for Xtensa ------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // This file implements the XtensaDisassembler class.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "MCTargetDesc/XtensaMCTargetDesc.h"
16 #include "TargetInfo/XtensaTargetInfo.h"
17 #include "llvm/MC/MCContext.h"
18 #include "llvm/MC/MCDecoderOps.h"
19 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
20 #include "llvm/MC/MCInst.h"
21 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/MC/TargetRegistry.h"
24 #include "llvm/Support/Endian.h"
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "Xtensa-disassembler"
29 
30 using DecodeStatus = MCDisassembler::DecodeStatus;
31 
32 namespace {
33 
34 class XtensaDisassembler : public MCDisassembler {
35   bool IsLittleEndian;
36 
37 public:
38   XtensaDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool isLE)
39       : MCDisassembler(STI, Ctx), IsLittleEndian(isLE) {}
40 
41   bool hasDensity() const { return STI.hasFeature(Xtensa::FeatureDensity); }
42 
43   DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
44                               ArrayRef<uint8_t> Bytes, uint64_t Address,
45                               raw_ostream &CStream) const override;
46 };
47 } // end anonymous namespace
48 
49 static MCDisassembler *createXtensaDisassembler(const Target &T,
50                                                 const MCSubtargetInfo &STI,
51                                                 MCContext &Ctx) {
52   return new XtensaDisassembler(STI, Ctx, true);
53 }
54 
55 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaDisassembler() {
56   TargetRegistry::RegisterMCDisassembler(getTheXtensaTarget(),
57                                          createXtensaDisassembler);
58 }
59 
60 static const unsigned ARDecoderTable[] = {
61     Xtensa::A0,  Xtensa::SP,  Xtensa::A2,  Xtensa::A3, Xtensa::A4,  Xtensa::A5,
62     Xtensa::A6,  Xtensa::A7,  Xtensa::A8,  Xtensa::A9, Xtensa::A10, Xtensa::A11,
63     Xtensa::A12, Xtensa::A13, Xtensa::A14, Xtensa::A15};
64 
65 static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo,
66                                           uint64_t Address,
67                                           const void *Decoder) {
68   if (RegNo >= std::size(ARDecoderTable))
69     return MCDisassembler::Fail;
70 
71   unsigned Reg = ARDecoderTable[RegNo];
72   Inst.addOperand(MCOperand::createReg(Reg));
73   return MCDisassembler::Success;
74 }
75 
76 static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3};
77 
78 static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo,
79                                           uint64_t Address,
80                                           const void *Decoder) {
81   if (RegNo > 255)
82     return MCDisassembler::Fail;
83 
84   for (unsigned i = 0; i < std::size(SRDecoderTable); i += 2) {
85     if (SRDecoderTable[i + 1] == RegNo) {
86       unsigned Reg = SRDecoderTable[i];
87       Inst.addOperand(MCOperand::createReg(Reg));
88       return MCDisassembler::Success;
89     }
90   }
91 
92   return MCDisassembler::Fail;
93 }
94 
95 static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
96                                      uint64_t Address, uint64_t Offset,
97                                      uint64_t InstSize, MCInst &MI,
98                                      const void *Decoder) {
99   const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder);
100   return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch, Offset,
101                                        /*OpSize=*/0, InstSize);
102 }
103 
104 static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm,
105                                       int64_t Address, const void *Decoder) {
106   assert(isUInt<18>(Imm) && "Invalid immediate");
107   Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Imm << 2)));
108   return MCDisassembler::Success;
109 }
110 
111 static DecodeStatus decodeJumpOperand(MCInst &Inst, uint64_t Imm,
112                                       int64_t Address, const void *Decoder) {
113   assert(isUInt<18>(Imm) && "Invalid immediate");
114   Inst.addOperand(MCOperand::createImm(SignExtend64<18>(Imm)));
115   return MCDisassembler::Success;
116 }
117 
118 static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm,
119                                         int64_t Address, const void *Decoder) {
120   switch (Inst.getOpcode()) {
121   case Xtensa::BEQZ:
122   case Xtensa::BGEZ:
123   case Xtensa::BLTZ:
124   case Xtensa::BNEZ:
125     assert(isUInt<12>(Imm) && "Invalid immediate");
126     if (!tryAddingSymbolicOperand(SignExtend64<12>(Imm) + 4 + Address, true,
127                                   Address, 0, 3, Inst, Decoder))
128       Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm)));
129     break;
130   default:
131     assert(isUInt<8>(Imm) && "Invalid immediate");
132     if (!tryAddingSymbolicOperand(SignExtend64<8>(Imm) + 4 + Address, true,
133                                   Address, 0, 3, Inst, Decoder))
134       Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm)));
135   }
136   return MCDisassembler::Success;
137 }
138 
139 static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm,
140                                       int64_t Address, const void *Decoder) {
141 
142   assert(isUInt<16>(Imm) && "Invalid immediate");
143   Inst.addOperand(MCOperand::createImm(
144       SignExtend64<17>((Imm << 2) + 0x40000 + (Address & 0x3))));
145   return MCDisassembler::Success;
146 }
147 
148 static DecodeStatus decodeImm8Operand(MCInst &Inst, uint64_t Imm,
149                                       int64_t Address, const void *Decoder) {
150   assert(isUInt<8>(Imm) && "Invalid immediate");
151   Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm)));
152   return MCDisassembler::Success;
153 }
154 
155 static DecodeStatus decodeImm8_sh8Operand(MCInst &Inst, uint64_t Imm,
156                                           int64_t Address,
157                                           const void *Decoder) {
158   assert(isUInt<8>(Imm) && "Invalid immediate");
159   Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 8)));
160   return MCDisassembler::Success;
161 }
162 
163 static DecodeStatus decodeImm12Operand(MCInst &Inst, uint64_t Imm,
164                                        int64_t Address, const void *Decoder) {
165   assert(isUInt<12>(Imm) && "Invalid immediate");
166   Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm)));
167   return MCDisassembler::Success;
168 }
169 
170 static DecodeStatus decodeUimm4Operand(MCInst &Inst, uint64_t Imm,
171                                        int64_t Address, const void *Decoder) {
172   assert(isUInt<4>(Imm) && "Invalid immediate");
173   Inst.addOperand(MCOperand::createImm(Imm));
174   return MCDisassembler::Success;
175 }
176 
177 static DecodeStatus decodeUimm5Operand(MCInst &Inst, uint64_t Imm,
178                                        int64_t Address, const void *Decoder) {
179   assert(isUInt<5>(Imm) && "Invalid immediate");
180   Inst.addOperand(MCOperand::createImm(Imm));
181   return MCDisassembler::Success;
182 }
183 
184 static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm,
185                                          int64_t Address, const void *Decoder) {
186   assert(isUInt<4>(Imm) && "Invalid immediate");
187   Inst.addOperand(MCOperand::createImm(Imm + 1));
188   return MCDisassembler::Success;
189 }
190 
191 static DecodeStatus decodeImm1n_15Operand(MCInst &Inst, uint64_t Imm,
192                                           int64_t Address,
193                                           const void *Decoder) {
194   assert(isUInt<4>(Imm) && "Invalid immediate");
195   if (!Imm)
196     Inst.addOperand(MCOperand::createImm(-1));
197   else
198     Inst.addOperand(MCOperand::createImm(Imm));
199   return MCDisassembler::Success;
200 }
201 
202 static DecodeStatus decodeImm32n_95Operand(MCInst &Inst, uint64_t Imm,
203                                            int64_t Address,
204                                            const void *Decoder) {
205   assert(isUInt<7>(Imm) && "Invalid immediate");
206   if ((Imm & 0x60) == 0x60)
207     Inst.addOperand(MCOperand::createImm((~0x1f) | Imm));
208   else
209     Inst.addOperand(MCOperand::createImm(Imm));
210   return MCDisassembler::Success;
211 }
212 
213 static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm,
214                                            int64_t Address,
215                                            const void *Decoder) {
216   assert(isUInt<5>(Imm) && "Invalid immediate");
217   Inst.addOperand(MCOperand::createImm(32 - Imm));
218   return MCDisassembler::Success;
219 }
220 
221 static int64_t TableB4const[16] = {-1, 1,  2,  3,  4,  5,  6,   7,
222                                    8,  10, 12, 16, 32, 64, 128, 256};
223 static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm,
224                                          int64_t Address, const void *Decoder) {
225   assert(isUInt<4>(Imm) && "Invalid immediate");
226 
227   Inst.addOperand(MCOperand::createImm(TableB4const[Imm]));
228   return MCDisassembler::Success;
229 }
230 
231 static int64_t TableB4constu[16] = {32768, 65536, 2,  3,  4,  5,  6,   7,
232                                     8,     10,    12, 16, 32, 64, 128, 256};
233 static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm,
234                                           int64_t Address,
235                                           const void *Decoder) {
236   assert(isUInt<4>(Imm) && "Invalid immediate");
237 
238   Inst.addOperand(MCOperand::createImm(TableB4constu[Imm]));
239   return MCDisassembler::Success;
240 }
241 
242 static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm,
243                                       int64_t Address, const void *Decoder) {
244   assert(isUInt<12>(Imm) && "Invalid immediate");
245   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
246   Inst.addOperand(MCOperand::createImm((Imm >> 4) & 0xff));
247   return MCDisassembler::Success;
248 }
249 
250 static DecodeStatus decodeMem16Operand(MCInst &Inst, uint64_t Imm,
251                                        int64_t Address, const void *Decoder) {
252   assert(isUInt<12>(Imm) && "Invalid immediate");
253   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
254   Inst.addOperand(MCOperand::createImm((Imm >> 3) & 0x1fe));
255   return MCDisassembler::Success;
256 }
257 
258 static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm,
259                                        int64_t Address, const void *Decoder) {
260   assert(isUInt<12>(Imm) && "Invalid immediate");
261   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
262   Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3fc));
263   return MCDisassembler::Success;
264 }
265 
266 static DecodeStatus decodeMem32nOperand(MCInst &Inst, uint64_t Imm,
267                                         int64_t Address, const void *Decoder) {
268   assert(isUInt<8>(Imm) && "Invalid immediate");
269   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
270   Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3c));
271   return MCDisassembler::Success;
272 }
273 
274 /// Read two bytes from the ArrayRef and return 16 bit data sorted
275 /// according to the given endianness.
276 static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
277                                       uint64_t &Size, uint64_t &Insn,
278                                       bool IsLittleEndian) {
279   // We want to read exactly 2 Bytes of data.
280   if (Bytes.size() < 2) {
281     Size = 0;
282     return MCDisassembler::Fail;
283   }
284 
285   if (!IsLittleEndian) {
286     report_fatal_error("Big-endian mode currently is not supported!");
287   } else {
288     Insn = (Bytes[1] << 8) | Bytes[0];
289   }
290 
291   return MCDisassembler::Success;
292 }
293 
294 /// Read three bytes from the ArrayRef and return 24 bit data
295 static DecodeStatus readInstruction24(ArrayRef<uint8_t> Bytes, uint64_t Address,
296                                       uint64_t &Size, uint64_t &Insn,
297                                       bool IsLittleEndian) {
298   // We want to read exactly 3 Bytes of data.
299   if (Bytes.size() < 3) {
300     Size = 0;
301     return MCDisassembler::Fail;
302   }
303 
304   if (!IsLittleEndian) {
305     report_fatal_error("Big-endian mode currently is not supported!");
306   } else {
307     Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
308   }
309 
310   return MCDisassembler::Success;
311 }
312 
313 #include "XtensaGenDisassemblerTables.inc"
314 
315 DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
316                                                 ArrayRef<uint8_t> Bytes,
317                                                 uint64_t Address,
318                                                 raw_ostream &CS) const {
319   uint64_t Insn;
320   DecodeStatus Result;
321 
322   // Parse 16-bit instructions
323   if (hasDensity()) {
324     Result = readInstruction16(Bytes, Address, Size, Insn, IsLittleEndian);
325     if (Result == MCDisassembler::Fail)
326       return MCDisassembler::Fail;
327     LLVM_DEBUG(dbgs() << "Trying Xtensa 16-bit instruction table :\n");
328     Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI);
329     if (Result != MCDisassembler::Fail) {
330       Size = 2;
331       return Result;
332     }
333   }
334 
335   // Parse Core 24-bit instructions
336   Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian);
337   if (Result == MCDisassembler::Fail)
338     return MCDisassembler::Fail;
339   LLVM_DEBUG(dbgs() << "Trying Xtensa 24-bit instruction table :\n");
340   Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI);
341   if (Result != MCDisassembler::Fail) {
342     Size = 3;
343     return Result;
344   }
345   return Result;
346 }
347