xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp (revision 95eb4b873b6a8b527c5bd78d7191975dfca38998)
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 {
42     return STI.hasFeature(Xtensa::FeatureDensity);
43   }
44 
45   DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
46                               ArrayRef<uint8_t> Bytes, uint64_t Address,
47                               raw_ostream &CStream) const override;
48 };
49 } // end anonymous namespace
50 
51 static MCDisassembler *createXtensaDisassembler(const Target &T,
52                                                 const MCSubtargetInfo &STI,
53                                                 MCContext &Ctx) {
54   return new XtensaDisassembler(STI, Ctx, true);
55 }
56 
57 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaDisassembler() {
58   TargetRegistry::RegisterMCDisassembler(getTheXtensaTarget(),
59                                          createXtensaDisassembler);
60 }
61 
62 static const unsigned ARDecoderTable[] = {
63     Xtensa::A0,  Xtensa::SP,  Xtensa::A2,  Xtensa::A3, Xtensa::A4,  Xtensa::A5,
64     Xtensa::A6,  Xtensa::A7,  Xtensa::A8,  Xtensa::A9, Xtensa::A10, Xtensa::A11,
65     Xtensa::A12, Xtensa::A13, Xtensa::A14, Xtensa::A15};
66 
67 static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo,
68                                           uint64_t Address,
69                                           const void *Decoder) {
70   if (RegNo >= std::size(ARDecoderTable))
71     return MCDisassembler::Fail;
72 
73   unsigned Reg = ARDecoderTable[RegNo];
74   Inst.addOperand(MCOperand::createReg(Reg));
75   return MCDisassembler::Success;
76 }
77 
78 static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3};
79 
80 static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo,
81                                           uint64_t Address,
82                                           const void *Decoder) {
83   if (RegNo > 255)
84     return MCDisassembler::Fail;
85 
86   for (unsigned i = 0; i < std::size(SRDecoderTable); i += 2) {
87     if (SRDecoderTable[i + 1] == RegNo) {
88       unsigned Reg = SRDecoderTable[i];
89       Inst.addOperand(MCOperand::createReg(Reg));
90       return MCDisassembler::Success;
91     }
92   }
93 
94   return MCDisassembler::Fail;
95 }
96 
97 static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
98                                      uint64_t Address, uint64_t Offset,
99                                      uint64_t InstSize, MCInst &MI,
100                                      const void *Decoder) {
101   const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder);
102   return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch, Offset, /*OpSize=*/0,
103                                        InstSize);
104 }
105 
106 static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm,
107                                       int64_t Address, const void *Decoder) {
108   assert(isUInt<18>(Imm) && "Invalid immediate");
109   Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Imm << 2)));
110   return MCDisassembler::Success;
111 }
112 
113 static DecodeStatus decodeJumpOperand(MCInst &Inst, uint64_t Imm,
114                                       int64_t Address, const void *Decoder) {
115   assert(isUInt<18>(Imm) && "Invalid immediate");
116   Inst.addOperand(MCOperand::createImm(SignExtend64<18>(Imm)));
117   return MCDisassembler::Success;
118 }
119 
120 static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm,
121                                         int64_t Address, const void *Decoder) {
122   switch (Inst.getOpcode()) {
123   case Xtensa::BEQZ:
124   case Xtensa::BGEZ:
125   case Xtensa::BLTZ:
126   case Xtensa::BNEZ:
127     assert(isUInt<12>(Imm) && "Invalid immediate");
128     if (!tryAddingSymbolicOperand(SignExtend64<12>(Imm) + 4 + Address, true,
129                                   Address, 0, 3, Inst, Decoder))
130       Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm)));
131     break;
132   default:
133     assert(isUInt<8>(Imm) && "Invalid immediate");
134     if (!tryAddingSymbolicOperand(SignExtend64<8>(Imm) + 4 + Address, true,
135                                   Address, 0, 3, Inst, Decoder))
136       Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm)));
137   }
138   return MCDisassembler::Success;
139 }
140 
141 static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm,
142                                       int64_t Address, const void *Decoder) {
143 
144   assert(isUInt<16>(Imm) && "Invalid immediate");
145   Inst.addOperand(MCOperand::createImm(
146       SignExtend64<17>((Imm << 2) + 0x40000 + (Address & 0x3))));
147   return MCDisassembler::Success;
148 }
149 
150 static DecodeStatus decodeImm8Operand(MCInst &Inst, uint64_t Imm,
151                                       int64_t Address, const void *Decoder) {
152   assert(isUInt<8>(Imm) && "Invalid immediate");
153   Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm)));
154   return MCDisassembler::Success;
155 }
156 
157 static DecodeStatus decodeImm8_sh8Operand(MCInst &Inst, uint64_t Imm,
158                                           int64_t Address,
159                                           const void *Decoder) {
160   assert(isUInt<8>(Imm) && "Invalid immediate");
161   Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 8)));
162   return MCDisassembler::Success;
163 }
164 
165 static DecodeStatus decodeImm12Operand(MCInst &Inst, uint64_t Imm,
166                                        int64_t Address, const void *Decoder) {
167   assert(isUInt<12>(Imm) && "Invalid immediate");
168   Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm)));
169   return MCDisassembler::Success;
170 }
171 
172 static DecodeStatus decodeUimm4Operand(MCInst &Inst, uint64_t Imm,
173                                        int64_t Address, const void *Decoder) {
174   assert(isUInt<4>(Imm) && "Invalid immediate");
175   Inst.addOperand(MCOperand::createImm(Imm));
176   return MCDisassembler::Success;
177 }
178 
179 static DecodeStatus decodeUimm5Operand(MCInst &Inst, uint64_t Imm,
180                                        int64_t Address, const void *Decoder) {
181   assert(isUInt<5>(Imm) && "Invalid immediate");
182   Inst.addOperand(MCOperand::createImm(Imm));
183   return MCDisassembler::Success;
184 }
185 
186 static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm,
187                                          int64_t Address, const void *Decoder) {
188   assert(isUInt<4>(Imm) && "Invalid immediate");
189   Inst.addOperand(MCOperand::createImm(Imm + 1));
190   return MCDisassembler::Success;
191 }
192 
193 static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm,
194                                            int64_t Address,
195                                            const void *Decoder) {
196   assert(isUInt<5>(Imm) && "Invalid immediate");
197   Inst.addOperand(MCOperand::createImm(32 - Imm));
198   return MCDisassembler::Success;
199 }
200 
201 static int64_t TableB4const[16] = {-1, 1,  2,  3,  4,  5,  6,   7,
202                                    8,  10, 12, 16, 32, 64, 128, 256};
203 static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm,
204                                          int64_t Address, const void *Decoder) {
205   assert(isUInt<4>(Imm) && "Invalid immediate");
206 
207   Inst.addOperand(MCOperand::createImm(TableB4const[Imm]));
208   return MCDisassembler::Success;
209 }
210 
211 static int64_t TableB4constu[16] = {32768, 65536, 2,  3,  4,  5,  6,   7,
212                                     8,     10,    12, 16, 32, 64, 128, 256};
213 static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm,
214                                           int64_t Address,
215                                           const void *Decoder) {
216   assert(isUInt<4>(Imm) && "Invalid immediate");
217 
218   Inst.addOperand(MCOperand::createImm(TableB4constu[Imm]));
219   return MCDisassembler::Success;
220 }
221 
222 static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm,
223                                       int64_t Address, const void *Decoder) {
224   assert(isUInt<12>(Imm) && "Invalid immediate");
225   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
226   Inst.addOperand(MCOperand::createImm((Imm >> 4) & 0xff));
227   return MCDisassembler::Success;
228 }
229 
230 static DecodeStatus decodeMem16Operand(MCInst &Inst, uint64_t Imm,
231                                        int64_t Address, const void *Decoder) {
232   assert(isUInt<12>(Imm) && "Invalid immediate");
233   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
234   Inst.addOperand(MCOperand::createImm((Imm >> 3) & 0x1fe));
235   return MCDisassembler::Success;
236 }
237 
238 static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm,
239                                        int64_t Address, const void *Decoder) {
240   assert(isUInt<12>(Imm) && "Invalid immediate");
241   DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
242   Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3fc));
243   return MCDisassembler::Success;
244 }
245 
246 /// Read three bytes from the ArrayRef and return 24 bit data
247 static DecodeStatus readInstruction24(ArrayRef<uint8_t> Bytes, uint64_t Address,
248                                       uint64_t &Size, uint32_t &Insn,
249                                       bool IsLittleEndian) {
250   // We want to read exactly 3 Bytes of data.
251   if (Bytes.size() < 3) {
252     Size = 0;
253     return MCDisassembler::Fail;
254   }
255 
256   if (!IsLittleEndian) {
257     report_fatal_error("Big-endian mode currently is not supported!");
258   } else {
259     Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
260   }
261 
262   Size = 3;
263   return MCDisassembler::Success;
264 }
265 
266 #include "XtensaGenDisassemblerTables.inc"
267 
268 DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
269                                                 ArrayRef<uint8_t> Bytes,
270                                                 uint64_t Address,
271                                                 raw_ostream &CS) const {
272   uint32_t Insn;
273   DecodeStatus Result;
274 
275   Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian);
276   if (Result == MCDisassembler::Fail)
277     return MCDisassembler::Fail;
278   LLVM_DEBUG(dbgs() << "Trying Xtensa 24-bit instruction table :\n");
279   Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI);
280   return Result;
281 }
282