xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1 //===- ARCDisassembler.cpp - Disassembler for ARC ---------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file is part of the ARC Disassembler.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "ARC.h"
15 #include "ARCRegisterInfo.h"
16 #include "MCTargetDesc/ARCMCTargetDesc.h"
17 #include "TargetInfo/ARCTargetInfo.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
20 #include "llvm/MC/MCFixedLenDisassembler.h"
21 #include "llvm/MC/MCInst.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCSubtargetInfo.h"
24 #include "llvm/Support/TargetRegistry.h"
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "arc-disassembler"
29 
30 using DecodeStatus = MCDisassembler::DecodeStatus;
31 
32 namespace {
33 
34 /// A disassembler class for ARC.
35 class ARCDisassembler : public MCDisassembler {
36 public:
37   std::unique_ptr<MCInstrInfo const> const MCII;
38 
39   ARCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
40                   MCInstrInfo const *MCII)
41       : MCDisassembler(STI, Ctx), MCII(MCII) {}
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 
48 } // end anonymous namespace
49 
50 static bool readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
51                               uint64_t &Size, uint32_t &Insn) {
52   Size = 4;
53   // Read 2 16-bit values, but swap hi/lo parts.
54   Insn =
55       (Bytes[0] << 16) | (Bytes[1] << 24) | (Bytes[2] << 0) | (Bytes[3] << 8);
56   return true;
57 }
58 
59 static bool readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
60                               uint64_t &Size, uint64_t &Insn) {
61   Size = 8;
62   Insn = ((uint64_t)Bytes[0] << 16) | ((uint64_t)Bytes[1] << 24) |
63          ((uint64_t)Bytes[2] << 0) | ((uint64_t)Bytes[3] << 8) |
64          ((uint64_t)Bytes[4] << 48) | ((uint64_t)Bytes[5] << 56) |
65          ((uint64_t)Bytes[6] << 32) | ((uint64_t)Bytes[7] << 40);
66   return true;
67 }
68 
69 static bool readInstruction48(ArrayRef<uint8_t> Bytes, uint64_t Address,
70                               uint64_t &Size, uint64_t &Insn) {
71   Size = 6;
72   Insn = ((uint64_t)Bytes[0] << 0) | ((uint64_t)Bytes[1] << 8) |
73          ((uint64_t)Bytes[2] << 32) | ((uint64_t)Bytes[3] << 40) |
74          ((uint64_t)Bytes[4] << 16) | ((uint64_t)Bytes[5] << 24);
75   return true;
76 }
77 
78 static bool readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
79                               uint64_t &Size, uint32_t &Insn) {
80   Size = 2;
81   Insn = (Bytes[0] << 0) | (Bytes[1] << 8);
82   return true;
83 }
84 
85 template <unsigned B>
86 static DecodeStatus DecodeSignedOperand(MCInst &Inst, unsigned InsnS,
87                                         uint64_t Address = 0,
88                                         const void *Decoder = nullptr);
89 
90 template <unsigned B>
91 static DecodeStatus DecodeFromCyclicRange(MCInst &Inst, unsigned InsnS,
92                                         uint64_t Address = 0,
93                                         const void *Decoder = nullptr);
94 
95 template <unsigned B>
96 static DecodeStatus DecodeBranchTargetS(MCInst &Inst, unsigned InsnS,
97                                         uint64_t Address, const void *Decoder);
98 
99 static DecodeStatus DecodeMEMrs9(MCInst &, unsigned, uint64_t, const void *);
100 
101 static DecodeStatus DecodeLdLImmInstruction(MCInst &, uint64_t, uint64_t,
102                                             const void *);
103 
104 static DecodeStatus DecodeStLImmInstruction(MCInst &, uint64_t, uint64_t,
105                                             const void *);
106 
107 static DecodeStatus DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t,
108                                              const void *);
109 
110 static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t, uint64_t,
111                                               const void *);
112 
113 static const uint16_t GPR32DecoderTable[] = {
114     ARC::R0,  ARC::R1,    ARC::R2,  ARC::R3,   ARC::R4,  ARC::R5,  ARC::R6,
115     ARC::R7,  ARC::R8,    ARC::R9,  ARC::R10,  ARC::R11, ARC::R12, ARC::R13,
116     ARC::R14, ARC::R15,   ARC::R16, ARC::R17,  ARC::R18, ARC::R19, ARC::R20,
117     ARC::R21, ARC::R22,   ARC::R23, ARC::R24,  ARC::R25, ARC::GP,  ARC::FP,
118     ARC::SP,  ARC::ILINK, ARC::R30, ARC::BLINK};
119 
120 static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
121                                              uint64_t Address,
122                                              const void *Decoder) {
123   if (RegNo >= 32) {
124     LLVM_DEBUG(dbgs() << "Not a GPR32 register.");
125     return MCDisassembler::Fail;
126   }
127 
128   unsigned Reg = GPR32DecoderTable[RegNo];
129   Inst.addOperand(MCOperand::createReg(Reg));
130   return MCDisassembler::Success;
131 }
132 
133 static DecodeStatus DecodeGBR32ShortRegister(MCInst &Inst, unsigned RegNo,
134                                                uint64_t Address,
135                                                const void *Decoder) {
136   // Enumerates registers from ranges [r0-r3],[r12-r15].
137   if (RegNo > 3)
138     RegNo += 8; // 4 for r12, etc...
139 
140   return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder);
141 }
142 
143 #include "ARCGenDisassemblerTables.inc"
144 
145 static unsigned decodeCField(unsigned Insn) {
146   return fieldFromInstruction(Insn, 6, 6);
147 }
148 
149 static unsigned decodeBField(unsigned Insn) {
150   return (fieldFromInstruction(Insn, 12, 3) << 3) |
151          fieldFromInstruction(Insn, 24, 3);
152 }
153 
154 static unsigned decodeAField(unsigned Insn) {
155   return fieldFromInstruction(Insn, 0, 6);
156 }
157 
158 static DecodeStatus DecodeMEMrs9(MCInst &Inst, unsigned Insn, uint64_t Address,
159                                  const void *Dec) {
160   // We have the 9-bit immediate in the low bits, 6-bit register in high bits.
161   unsigned S9 = Insn & 0x1ff;
162   unsigned R = (Insn & (0x7fff & ~0x1ff)) >> 9;
163   DecodeGPR32RegisterClass(Inst, R, Address, Dec);
164   Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S9)));
165   return MCDisassembler::Success;
166 }
167 
168 static bool DecodeSymbolicOperand(MCInst &Inst, uint64_t Address,
169                                   uint64_t Value, const void *Decoder) {
170   static const uint64_t atLeast = 2;
171   // TODO: Try to force emitter to use MCDisassembler* instead of void*.
172   auto Disassembler = static_cast<const MCDisassembler *>(Decoder);
173   return (nullptr != Disassembler &&
174           Disassembler->tryAddingSymbolicOperand(Inst, Value, Address, true, 0,
175                                                  atLeast));
176 }
177 
178 static void DecodeSymbolicOperandOff(MCInst &Inst, uint64_t Address,
179                                      uint64_t Offset, const void *Decoder) {
180   uint64_t nextAddress = Address + Offset;
181 
182   if (!DecodeSymbolicOperand(Inst, Address, nextAddress, Decoder))
183     Inst.addOperand(MCOperand::createImm(Offset));
184 }
185 
186 template <unsigned B>
187 static DecodeStatus DecodeBranchTargetS(MCInst &Inst, unsigned InsnS,
188                                         uint64_t Address, const void *Decoder) {
189 
190   static_assert(B > 0, "field is empty");
191   DecodeSymbolicOperandOff(Inst, Address, SignExtend32<B>(InsnS), Decoder);
192   return MCDisassembler::Success;
193 }
194 
195 template <unsigned B>
196 static DecodeStatus DecodeSignedOperand(MCInst &Inst, unsigned InsnS,
197                                         uint64_t /*Address*/,
198                                         const void * /*Decoder*/) {
199 
200   static_assert(B > 0, "field is empty");
201   Inst.addOperand(MCOperand::createImm(
202       SignExtend32<B>(maskTrailingOnes<decltype(InsnS)>(B) & InsnS)));
203   return MCDisassembler::Success;
204 }
205 
206 template <unsigned B>
207 static DecodeStatus DecodeFromCyclicRange(MCInst &Inst, unsigned InsnS,
208                                           uint64_t /*Address*/,
209                                           const void * /*Decoder*/) {
210 
211   static_assert(B > 0, "field is empty");
212   const unsigned max = (1u << B) - 1;
213   Inst.addOperand(
214       MCOperand::createImm(InsnS < max ? static_cast<int>(InsnS) : -1));
215   return MCDisassembler::Success;
216 }
217 
218 static DecodeStatus DecodeStLImmInstruction(MCInst &Inst, uint64_t Insn,
219                                             uint64_t Address,
220                                             const void *Decoder) {
221   unsigned SrcC, DstB, LImm;
222   DstB = decodeBField(Insn);
223   if (DstB != 62) {
224     LLVM_DEBUG(dbgs() << "Decoding StLImm found non-limm register.");
225     return MCDisassembler::Fail;
226   }
227   SrcC = decodeCField(Insn);
228   DecodeGPR32RegisterClass(Inst, SrcC, Address, Decoder);
229   LImm = (Insn >> 32);
230   Inst.addOperand(MCOperand::createImm(LImm));
231   Inst.addOperand(MCOperand::createImm(0));
232   return MCDisassembler::Success;
233 }
234 
235 static DecodeStatus DecodeLdLImmInstruction(MCInst &Inst, uint64_t Insn,
236                                             uint64_t Address,
237                                             const void *Decoder) {
238   unsigned DstA, SrcB, LImm;
239   LLVM_DEBUG(dbgs() << "Decoding LdLImm:\n");
240   SrcB = decodeBField(Insn);
241   if (SrcB != 62) {
242     LLVM_DEBUG(dbgs() << "Decoding LdLImm found non-limm register.");
243     return MCDisassembler::Fail;
244   }
245   DstA = decodeAField(Insn);
246   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
247   LImm = (Insn >> 32);
248   Inst.addOperand(MCOperand::createImm(LImm));
249   Inst.addOperand(MCOperand::createImm(0));
250   return MCDisassembler::Success;
251 }
252 
253 static DecodeStatus DecodeLdRLImmInstruction(MCInst &Inst, uint64_t Insn,
254                                              uint64_t Address,
255                                              const void *Decoder) {
256   unsigned DstA, SrcB;
257   LLVM_DEBUG(dbgs() << "Decoding LdRLimm\n");
258   DstA = decodeAField(Insn);
259   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
260   SrcB = decodeBField(Insn);
261   DecodeGPR32RegisterClass(Inst, SrcB, Address, Decoder);
262   if (decodeCField(Insn) != 62) {
263     LLVM_DEBUG(dbgs() << "Decoding LdRLimm found non-limm register.");
264     return MCDisassembler::Fail;
265   }
266   Inst.addOperand(MCOperand::createImm((uint32_t)(Insn >> 32)));
267   return MCDisassembler::Success;
268 }
269 
270 static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t Insn,
271                                               uint64_t Address,
272                                               const void *Decoder) {
273   LLVM_DEBUG(dbgs() << "Decoding MOV_S h-register\n");
274   using Field = decltype(Insn);
275   Field h = fieldFromInstruction(Insn, 5, 3) |
276             (fieldFromInstruction(Insn, 0, 2) << 3);
277   Field g = fieldFromInstruction(Insn, 8, 3) |
278             (fieldFromInstruction(Insn, 3, 2) << 3);
279 
280   auto DecodeRegisterOrImm = [&Inst, Address, Decoder](Field RegNum,
281                                                        Field Value) {
282     if (30 == RegNum) {
283       Inst.addOperand(MCOperand::createImm(Value));
284       return MCDisassembler::Success;
285     }
286 
287     return DecodeGPR32RegisterClass(Inst, RegNum, Address, Decoder);
288   };
289 
290   if (MCDisassembler::Success != DecodeRegisterOrImm(g, 0))
291     return MCDisassembler::Fail;
292 
293   return DecodeRegisterOrImm(h, Insn >> 16u);
294 }
295 
296 DecodeStatus ARCDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
297                                              ArrayRef<uint8_t> Bytes,
298                                              uint64_t Address,
299                                              raw_ostream &cStream) const {
300   MCDisassembler::DecodeStatus Result;
301   if (Bytes.size() < 2) {
302     Size = 0;
303     return Fail;
304   }
305   uint8_t DecodeByte = (Bytes[1] & 0xF7) >> 3;
306   // 0x00 -> 0x07 are 32-bit instructions.
307   // 0x08 -> 0x1F are 16-bit instructions.
308   if (DecodeByte < 0x08) {
309     // 32-bit instruction.
310     if (Bytes.size() < 4) {
311       // Did we decode garbage?
312       Size = 0;
313       return Fail;
314     }
315     if (Bytes.size() >= 8) {
316       // Attempt to decode 64-bit instruction.
317       uint64_t Insn64;
318       if (!readInstruction64(Bytes, Address, Size, Insn64))
319         return Fail;
320       Result =
321           decodeInstruction(DecoderTable64, Instr, Insn64, Address, this, STI);
322       if (Success == Result) {
323         LLVM_DEBUG(dbgs() << "Successfully decoded 64-bit instruction.");
324         return Result;
325       }
326       LLVM_DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit.");
327     }
328     uint32_t Insn32;
329     if (!readInstruction32(Bytes, Address, Size, Insn32)) {
330       return Fail;
331     }
332     // Calling the auto-generated decoder function.
333     return decodeInstruction(DecoderTable32, Instr, Insn32, Address, this, STI);
334   } else {
335     if (Bytes.size() >= 6) {
336       // Attempt to treat as instr. with limm data.
337       uint64_t Insn48;
338       if (!readInstruction48(Bytes, Address, Size, Insn48))
339         return Fail;
340       Result =
341           decodeInstruction(DecoderTable48, Instr, Insn48, Address, this, STI);
342       if (Success == Result) {
343         LLVM_DEBUG(
344             dbgs() << "Successfully decoded 16-bit instruction with limm.");
345         return Result;
346       }
347       LLVM_DEBUG(
348           dbgs() << "Not a 16-bit instruction with limm, try without it.");
349     }
350 
351     uint32_t Insn16;
352     if (!readInstruction16(Bytes, Address, Size, Insn16))
353       return Fail;
354 
355     // Calling the auto-generated decoder function.
356     return decodeInstruction(DecoderTable16, Instr, Insn16, Address, this, STI);
357   }
358 }
359 
360 static MCDisassembler *createARCDisassembler(const Target &T,
361                                              const MCSubtargetInfo &STI,
362                                              MCContext &Ctx) {
363   return new ARCDisassembler(STI, Ctx, T.createMCInstrInfo());
364 }
365 
366 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARCDisassembler() {
367   // Register the disassembler.
368   TargetRegistry::RegisterMCDisassembler(getTheARCTarget(),
369                                          createARCDisassembler);
370 }
371