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:
XtensaDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx,bool isLE)38 XtensaDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool isLE)
39 : MCDisassembler(STI, Ctx), IsLittleEndian(isLE) {}
40
hasDensity() const41 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
createXtensaDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)51 static MCDisassembler *createXtensaDisassembler(const Target &T,
52 const MCSubtargetInfo &STI,
53 MCContext &Ctx) {
54 return new XtensaDisassembler(STI, Ctx, true);
55 }
56
LLVMInitializeXtensaDisassembler()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
DecodeARRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const void * Decoder)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
DecodeSRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const void * Decoder)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
tryAddingSymbolicOperand(int64_t Value,bool isBranch,uint64_t Address,uint64_t Offset,uint64_t InstSize,MCInst & MI,const void * Decoder)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
decodeCallOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeJumpOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeBranchOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeL32ROperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeImm8Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeImm8_sh8Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeImm12Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeUimm4Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeUimm5Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeImm1_16Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeShimm1_31Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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};
decodeB4constOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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};
decodeB4constuOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeMem8Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeMem16Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
decodeMem32Operand(MCInst & Inst,uint64_t Imm,int64_t Address,const void * Decoder)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
readInstruction24(ArrayRef<uint8_t> Bytes,uint64_t Address,uint64_t & Size,uint32_t & Insn,bool IsLittleEndian)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
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CS) const268 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