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 DecodeCCRU6Instruction(MCInst &, uint64_t, uint64_t,
111                                            const void *);
112 
113 static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t, uint64_t,
114                                               const void *);
115 
116 static const uint16_t GPR32DecoderTable[] = {
117     ARC::R0,  ARC::R1,    ARC::R2,  ARC::R3,   ARC::R4,  ARC::R5,  ARC::R6,
118     ARC::R7,  ARC::R8,    ARC::R9,  ARC::R10,  ARC::R11, ARC::R12, ARC::R13,
119     ARC::R14, ARC::R15,   ARC::R16, ARC::R17,  ARC::R18, ARC::R19, ARC::R20,
120     ARC::R21, ARC::R22,   ARC::R23, ARC::R24,  ARC::R25, ARC::GP,  ARC::FP,
121     ARC::SP,  ARC::ILINK, ARC::R30, ARC::BLINK};
122 
123 static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
124                                              uint64_t Address,
125                                              const void *Decoder) {
126   if (RegNo >= 32) {
127     LLVM_DEBUG(dbgs() << "Not a GPR32 register.");
128     return MCDisassembler::Fail;
129   }
130 
131   unsigned Reg = GPR32DecoderTable[RegNo];
132   Inst.addOperand(MCOperand::createReg(Reg));
133   return MCDisassembler::Success;
134 }
135 
136 static DecodeStatus DecodeGBR32ShortRegister(MCInst &Inst, unsigned RegNo,
137                                                uint64_t Address,
138                                                const void *Decoder) {
139   // Enumerates registers from ranges [r0-r3],[r12-r15].
140   if (RegNo > 3)
141     RegNo += 8; // 4 for r12, etc...
142 
143   return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder);
144 }
145 
146 #include "ARCGenDisassemblerTables.inc"
147 
148 static unsigned decodeCField(unsigned Insn) {
149   return fieldFromInstruction(Insn, 6, 6);
150 }
151 
152 static unsigned decodeBField(unsigned Insn) {
153   return (fieldFromInstruction(Insn, 12, 3) << 3) |
154          fieldFromInstruction(Insn, 24, 3);
155 }
156 
157 static unsigned decodeAField(unsigned Insn) {
158   return fieldFromInstruction(Insn, 0, 6);
159 }
160 
161 static DecodeStatus DecodeMEMrs9(MCInst &Inst, unsigned Insn, uint64_t Address,
162                                  const void *Dec) {
163   // We have the 9-bit immediate in the low bits, 6-bit register in high bits.
164   unsigned S9 = Insn & 0x1ff;
165   unsigned R = (Insn & (0x7fff & ~0x1ff)) >> 9;
166   DecodeGPR32RegisterClass(Inst, R, Address, Dec);
167   Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S9)));
168   return MCDisassembler::Success;
169 }
170 
171 static bool DecodeSymbolicOperand(MCInst &Inst, uint64_t Address,
172                                   uint64_t Value, const void *Decoder) {
173   static const uint64_t AtLeast = 2;
174   // TODO: Try to force emitter to use MCDisassembler* instead of void*.
175   auto Disassembler = static_cast<const MCDisassembler *>(Decoder);
176   return (nullptr != Disassembler &&
177           Disassembler->tryAddingSymbolicOperand(Inst, Value, Address, true, 0,
178                                                  AtLeast));
179 }
180 
181 static void DecodeSymbolicOperandOff(MCInst &Inst, uint64_t Address,
182                                      uint64_t Offset, const void *Decoder) {
183   uint64_t NextAddress = Address + Offset;
184 
185   if (!DecodeSymbolicOperand(Inst, Address, NextAddress, Decoder))
186     Inst.addOperand(MCOperand::createImm(Offset));
187 }
188 
189 template <unsigned B>
190 static DecodeStatus DecodeBranchTargetS(MCInst &Inst, unsigned InsnS,
191                                         uint64_t Address, const void *Decoder) {
192 
193   static_assert(B > 0, "field is empty");
194   DecodeSymbolicOperandOff(Inst, Address, SignExtend32<B>(InsnS), Decoder);
195   return MCDisassembler::Success;
196 }
197 
198 template <unsigned B>
199 static DecodeStatus DecodeSignedOperand(MCInst &Inst, unsigned InsnS,
200                                         uint64_t /*Address*/,
201                                         const void * /*Decoder*/) {
202 
203   static_assert(B > 0, "field is empty");
204   Inst.addOperand(MCOperand::createImm(
205       SignExtend32<B>(maskTrailingOnes<decltype(InsnS)>(B) & InsnS)));
206   return MCDisassembler::Success;
207 }
208 
209 template <unsigned B>
210 static DecodeStatus DecodeFromCyclicRange(MCInst &Inst, unsigned InsnS,
211                                           uint64_t /*Address*/,
212                                           const void * /*Decoder*/) {
213 
214   static_assert(B > 0, "field is empty");
215   const unsigned max = (1u << B) - 1;
216   Inst.addOperand(
217       MCOperand::createImm(InsnS < max ? static_cast<int>(InsnS) : -1));
218   return MCDisassembler::Success;
219 }
220 
221 static DecodeStatus DecodeStLImmInstruction(MCInst &Inst, uint64_t Insn,
222                                             uint64_t Address,
223                                             const void *Decoder) {
224   unsigned SrcC, DstB, LImm;
225   DstB = decodeBField(Insn);
226   if (DstB != 62) {
227     LLVM_DEBUG(dbgs() << "Decoding StLImm found non-limm register.");
228     return MCDisassembler::Fail;
229   }
230   SrcC = decodeCField(Insn);
231   DecodeGPR32RegisterClass(Inst, SrcC, Address, Decoder);
232   LImm = (Insn >> 32);
233   Inst.addOperand(MCOperand::createImm(LImm));
234   Inst.addOperand(MCOperand::createImm(0));
235   return MCDisassembler::Success;
236 }
237 
238 static DecodeStatus DecodeLdLImmInstruction(MCInst &Inst, uint64_t Insn,
239                                             uint64_t Address,
240                                             const void *Decoder) {
241   unsigned DstA, SrcB, LImm;
242   LLVM_DEBUG(dbgs() << "Decoding LdLImm:\n");
243   SrcB = decodeBField(Insn);
244   if (SrcB != 62) {
245     LLVM_DEBUG(dbgs() << "Decoding LdLImm found non-limm register.");
246     return MCDisassembler::Fail;
247   }
248   DstA = decodeAField(Insn);
249   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
250   LImm = (Insn >> 32);
251   Inst.addOperand(MCOperand::createImm(LImm));
252   Inst.addOperand(MCOperand::createImm(0));
253   return MCDisassembler::Success;
254 }
255 
256 static DecodeStatus DecodeLdRLImmInstruction(MCInst &Inst, uint64_t Insn,
257                                              uint64_t Address,
258                                              const void *Decoder) {
259   unsigned DstA, SrcB;
260   LLVM_DEBUG(dbgs() << "Decoding LdRLimm\n");
261   DstA = decodeAField(Insn);
262   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
263   SrcB = decodeBField(Insn);
264   DecodeGPR32RegisterClass(Inst, SrcB, Address, Decoder);
265   if (decodeCField(Insn) != 62) {
266     LLVM_DEBUG(dbgs() << "Decoding LdRLimm found non-limm register.");
267     return MCDisassembler::Fail;
268   }
269   Inst.addOperand(MCOperand::createImm((uint32_t)(Insn >> 32)));
270   return MCDisassembler::Success;
271 }
272 
273 static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t Insn,
274                                               uint64_t Address,
275                                               const void *Decoder) {
276   LLVM_DEBUG(dbgs() << "Decoding MOV_S h-register\n");
277   using Field = decltype(Insn);
278   Field H = fieldFromInstruction(Insn, 5, 3) |
279             (fieldFromInstruction(Insn, 0, 2) << 3);
280   Field G = fieldFromInstruction(Insn, 8, 3) |
281             (fieldFromInstruction(Insn, 3, 2) << 3);
282 
283   auto DecodeRegisterOrImm = [&Inst, Address, Decoder](Field RegNum,
284                                                        Field Value) {
285     if (30 == RegNum) {
286       Inst.addOperand(MCOperand::createImm(Value));
287       return MCDisassembler::Success;
288     }
289 
290     return DecodeGPR32RegisterClass(Inst, RegNum, Address, Decoder);
291   };
292 
293   if (MCDisassembler::Success != DecodeRegisterOrImm(G, 0))
294     return MCDisassembler::Fail;
295 
296   return DecodeRegisterOrImm(H, Insn >> 16u);
297 }
298 
299 static DecodeStatus DecodeCCRU6Instruction(MCInst &Inst, uint64_t Insn,
300                                            uint64_t Address,
301                                            const void *Decoder) {
302   unsigned DstB;
303   LLVM_DEBUG(dbgs() << "Decoding CCRU6 instruction:\n");
304   DstB = decodeBField(Insn);
305   DecodeGPR32RegisterClass(Inst, DstB, Address, Decoder);
306   using Field = decltype(Insn);
307   Field U6Field = fieldFromInstruction(Insn, 6, 11);
308   Inst.addOperand(MCOperand::createImm(U6Field));
309   Field CCField = fieldFromInstruction(Insn, 0, 4);
310   Inst.addOperand(MCOperand::createImm(CCField));
311   return MCDisassembler::Success;
312 }
313 
314 DecodeStatus ARCDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
315                                              ArrayRef<uint8_t> Bytes,
316                                              uint64_t Address,
317                                              raw_ostream &cStream) const {
318   MCDisassembler::DecodeStatus Result;
319   if (Bytes.size() < 2) {
320     Size = 0;
321     return Fail;
322   }
323   uint8_t DecodeByte = (Bytes[1] & 0xF7) >> 3;
324   // 0x00 -> 0x07 are 32-bit instructions.
325   // 0x08 -> 0x1F are 16-bit instructions.
326   if (DecodeByte < 0x08) {
327     // 32-bit instruction.
328     if (Bytes.size() < 4) {
329       // Did we decode garbage?
330       Size = 0;
331       return Fail;
332     }
333     if (Bytes.size() >= 8) {
334       // Attempt to decode 64-bit instruction.
335       uint64_t Insn64;
336       if (!readInstruction64(Bytes, Address, Size, Insn64))
337         return Fail;
338       Result =
339           decodeInstruction(DecoderTable64, Instr, Insn64, Address, this, STI);
340       if (Success == Result) {
341         LLVM_DEBUG(dbgs() << "Successfully decoded 64-bit instruction.");
342         return Result;
343       }
344       LLVM_DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit.");
345     }
346     uint32_t Insn32;
347     if (!readInstruction32(Bytes, Address, Size, Insn32)) {
348       return Fail;
349     }
350     // Calling the auto-generated decoder function.
351     return decodeInstruction(DecoderTable32, Instr, Insn32, Address, this, STI);
352   } else {
353     if (Bytes.size() >= 6) {
354       // Attempt to treat as instr. with limm data.
355       uint64_t Insn48;
356       if (!readInstruction48(Bytes, Address, Size, Insn48))
357         return Fail;
358       Result =
359           decodeInstruction(DecoderTable48, Instr, Insn48, Address, this, STI);
360       if (Success == Result) {
361         LLVM_DEBUG(
362             dbgs() << "Successfully decoded 16-bit instruction with limm.");
363         return Result;
364       }
365       LLVM_DEBUG(
366           dbgs() << "Not a 16-bit instruction with limm, try without it.");
367     }
368 
369     uint32_t Insn16;
370     if (!readInstruction16(Bytes, Address, Size, Insn16))
371       return Fail;
372 
373     // Calling the auto-generated decoder function.
374     return decodeInstruction(DecoderTable16, Instr, Insn16, Address, this, STI);
375   }
376 }
377 
378 static MCDisassembler *createARCDisassembler(const Target &T,
379                                              const MCSubtargetInfo &STI,
380                                              MCContext &Ctx) {
381   return new ARCDisassembler(STI, Ctx, T.createMCInstrInfo());
382 }
383 
384 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARCDisassembler() {
385   // Register the disassembler.
386   TargetRegistry::RegisterMCDisassembler(getTheARCTarget(),
387                                          createARCDisassembler);
388 }
389