1 //===- ARCDisassembler.cpp - Disassembler for ARC ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file is part of the ARC Disassembler.
12 //===----------------------------------------------------------------------===//
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"
28 #define DEBUG_TYPE "arc-disassembler"
30 using DecodeStatus
= MCDisassembler::DecodeStatus
;
34 /// A disassembler class for ARC.
35 class ARCDisassembler
: public MCDisassembler
{
37 std::unique_ptr
<MCInstrInfo
const> const MCII
;
39 ARCDisassembler(const MCSubtargetInfo
&STI
, MCContext
&Ctx
,
40 MCInstrInfo
const *MCII
)
41 : MCDisassembler(STI
, Ctx
), MCII(MCII
) {}
43 DecodeStatus
getInstruction(MCInst
&Instr
, uint64_t &Size
,
44 ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
46 raw_ostream
&CStream
) const override
;
49 } // end anonymous namespace
51 static bool readInstruction32(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
52 uint64_t &Size
, uint32_t &Insn
) {
54 // Read 2 16-bit values, but swap hi/lo parts.
56 (Bytes
[0] << 16) | (Bytes
[1] << 24) | (Bytes
[2] << 0) | (Bytes
[3] << 8);
60 static bool readInstruction64(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
61 uint64_t &Size
, uint64_t &Insn
) {
63 Insn
= ((uint64_t)Bytes
[0] << 16) | ((uint64_t)Bytes
[1] << 24) |
64 ((uint64_t)Bytes
[2] << 0) | ((uint64_t)Bytes
[3] << 8) |
65 ((uint64_t)Bytes
[4] << 48) | ((uint64_t)Bytes
[5] << 56) |
66 ((uint64_t)Bytes
[6] << 32) | ((uint64_t)Bytes
[7] << 40);
70 static bool readInstruction48(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
71 uint64_t &Size
, uint64_t &Insn
) {
73 Insn
= ((uint64_t)Bytes
[0] << 0) | ((uint64_t)Bytes
[1] << 8) |
74 ((uint64_t)Bytes
[2] << 32) | ((uint64_t)Bytes
[3] << 40) |
75 ((uint64_t)Bytes
[4] << 16) | ((uint64_t)Bytes
[5] << 24);
79 static bool readInstruction16(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
80 uint64_t &Size
, uint32_t &Insn
) {
82 Insn
= (Bytes
[0] << 0) | (Bytes
[1] << 8);
87 static DecodeStatus
DecodeSignedOperand(MCInst
&Inst
, unsigned InsnS
,
89 const void *Decoder
= nullptr);
92 static DecodeStatus
DecodeFromCyclicRange(MCInst
&Inst
, unsigned InsnS
,
94 const void *Decoder
= nullptr);
97 static DecodeStatus
DecodeBranchTargetS(MCInst
&Inst
, unsigned InsnS
,
98 uint64_t Address
, const void *Decoder
);
100 static DecodeStatus
DecodeMEMrs9(MCInst
&, unsigned, uint64_t, const void *);
102 static DecodeStatus
DecodeLdLImmInstruction(MCInst
&, uint64_t, uint64_t,
105 static DecodeStatus
DecodeStLImmInstruction(MCInst
&, uint64_t, uint64_t,
108 static DecodeStatus
DecodeLdRLImmInstruction(MCInst
&, uint64_t, uint64_t,
111 static DecodeStatus
DecodeMoveHRegInstruction(MCInst
&Inst
, uint64_t, uint64_t,
114 static const uint16_t GPR32DecoderTable
[] = {
115 ARC::R0
, ARC::R1
, ARC::R2
, ARC::R3
, ARC::R4
, ARC::R5
, ARC::R6
,
116 ARC::R7
, ARC::R8
, ARC::R9
, ARC::R10
, ARC::R11
, ARC::R12
, ARC::R13
,
117 ARC::R14
, ARC::R15
, ARC::R16
, ARC::R17
, ARC::R18
, ARC::R19
, ARC::R20
,
118 ARC::R21
, ARC::R22
, ARC::R23
, ARC::R24
, ARC::R25
, ARC::GP
, ARC::FP
,
119 ARC::SP
, ARC::ILINK
, ARC::R30
, ARC::BLINK
};
121 static DecodeStatus
DecodeGPR32RegisterClass(MCInst
&Inst
, unsigned RegNo
,
123 const void *Decoder
) {
125 LLVM_DEBUG(dbgs() << "Not a GPR32 register.");
126 return MCDisassembler::Fail
;
129 unsigned Reg
= GPR32DecoderTable
[RegNo
];
130 Inst
.addOperand(MCOperand::createReg(Reg
));
131 return MCDisassembler::Success
;
134 static DecodeStatus
DecodeGBR32ShortRegister(MCInst
&Inst
, unsigned RegNo
,
136 const void *Decoder
) {
137 // Enumerates registers from ranges [r0-r3],[r12-r15].
139 RegNo
+= 8; // 4 for r12, etc...
141 return DecodeGPR32RegisterClass(Inst
, RegNo
, Address
, Decoder
);
144 #include "ARCGenDisassemblerTables.inc"
146 static unsigned decodeCField(unsigned Insn
) {
147 return fieldFromInstruction(Insn
, 6, 6);
150 static unsigned decodeBField(unsigned Insn
) {
151 return (fieldFromInstruction(Insn
, 12, 3) << 3) |
152 fieldFromInstruction(Insn
, 24, 3);
155 static unsigned decodeAField(unsigned Insn
) {
156 return fieldFromInstruction(Insn
, 0, 6);
159 static DecodeStatus
DecodeMEMrs9(MCInst
&Inst
, unsigned Insn
, uint64_t Address
,
161 // We have the 9-bit immediate in the low bits, 6-bit register in high bits.
162 unsigned S9
= Insn
& 0x1ff;
163 unsigned R
= (Insn
& (0x7fff & ~0x1ff)) >> 9;
164 DecodeGPR32RegisterClass(Inst
, R
, Address
, Dec
);
165 Inst
.addOperand(MCOperand::createImm(SignExtend32
<9>(S9
)));
166 return MCDisassembler::Success
;
169 static bool DecodeSymbolicOperand(MCInst
&Inst
, uint64_t Address
,
170 uint64_t Value
, const void *Decoder
) {
171 static const uint64_t atLeast
= 2;
172 // TODO: Try to force emitter to use MCDisassembler* instead of void*.
173 auto Disassembler
= static_cast<const MCDisassembler
*>(Decoder
);
174 return (nullptr != Disassembler
&&
175 Disassembler
->tryAddingSymbolicOperand(Inst
, Value
, Address
, true, 0,
179 static void DecodeSymbolicOperandOff(MCInst
&Inst
, uint64_t Address
,
180 uint64_t Offset
, const void *Decoder
) {
181 uint64_t nextAddress
= Address
+ Offset
;
183 if (!DecodeSymbolicOperand(Inst
, Address
, nextAddress
, Decoder
))
184 Inst
.addOperand(MCOperand::createImm(Offset
));
187 template <unsigned B
>
188 static DecodeStatus
DecodeBranchTargetS(MCInst
&Inst
, unsigned InsnS
,
189 uint64_t Address
, const void *Decoder
) {
191 static_assert(B
> 0, "field is empty");
192 DecodeSymbolicOperandOff(Inst
, Address
, SignExtend32
<B
>(InsnS
), Decoder
);
193 return MCDisassembler::Success
;
196 template <unsigned B
>
197 static DecodeStatus
DecodeSignedOperand(MCInst
&Inst
, unsigned InsnS
,
198 uint64_t /*Address*/,
199 const void * /*Decoder*/) {
201 static_assert(B
> 0, "field is empty");
202 Inst
.addOperand(MCOperand::createImm(
203 SignExtend32
<B
>(maskTrailingOnes
<decltype(InsnS
)>(B
) & InsnS
)));
204 return MCDisassembler::Success
;
207 template <unsigned B
>
208 static DecodeStatus
DecodeFromCyclicRange(MCInst
&Inst
, unsigned InsnS
,
209 uint64_t /*Address*/,
210 const void * /*Decoder*/) {
212 static_assert(B
> 0, "field is empty");
213 const unsigned max
= (1u << B
) - 1;
215 MCOperand::createImm(InsnS
< max
? static_cast<int>(InsnS
) : -1));
216 return MCDisassembler::Success
;
219 static DecodeStatus
DecodeStLImmInstruction(MCInst
&Inst
, uint64_t Insn
,
221 const void *Decoder
) {
222 unsigned SrcC
, DstB
, LImm
;
223 DstB
= decodeBField(Insn
);
225 LLVM_DEBUG(dbgs() << "Decoding StLImm found non-limm register.");
226 return MCDisassembler::Fail
;
228 SrcC
= decodeCField(Insn
);
229 DecodeGPR32RegisterClass(Inst
, SrcC
, Address
, Decoder
);
231 Inst
.addOperand(MCOperand::createImm(LImm
));
232 Inst
.addOperand(MCOperand::createImm(0));
233 return MCDisassembler::Success
;
236 static DecodeStatus
DecodeLdLImmInstruction(MCInst
&Inst
, uint64_t Insn
,
238 const void *Decoder
) {
239 unsigned DstA
, SrcB
, LImm
;
240 LLVM_DEBUG(dbgs() << "Decoding LdLImm:\n");
241 SrcB
= decodeBField(Insn
);
243 LLVM_DEBUG(dbgs() << "Decoding LdLImm found non-limm register.");
244 return MCDisassembler::Fail
;
246 DstA
= decodeAField(Insn
);
247 DecodeGPR32RegisterClass(Inst
, DstA
, Address
, Decoder
);
249 Inst
.addOperand(MCOperand::createImm(LImm
));
250 Inst
.addOperand(MCOperand::createImm(0));
251 return MCDisassembler::Success
;
254 static DecodeStatus
DecodeLdRLImmInstruction(MCInst
&Inst
, uint64_t Insn
,
256 const void *Decoder
) {
258 LLVM_DEBUG(dbgs() << "Decoding LdRLimm\n");
259 DstA
= decodeAField(Insn
);
260 DecodeGPR32RegisterClass(Inst
, DstA
, Address
, Decoder
);
261 SrcB
= decodeBField(Insn
);
262 DecodeGPR32RegisterClass(Inst
, SrcB
, Address
, Decoder
);
263 if (decodeCField(Insn
) != 62) {
264 LLVM_DEBUG(dbgs() << "Decoding LdRLimm found non-limm register.");
265 return MCDisassembler::Fail
;
267 Inst
.addOperand(MCOperand::createImm((uint32_t)(Insn
>> 32)));
268 return MCDisassembler::Success
;
271 static DecodeStatus
DecodeMoveHRegInstruction(MCInst
&Inst
, uint64_t Insn
,
273 const void *Decoder
) {
274 LLVM_DEBUG(dbgs() << "Decoding MOV_S h-register\n");
275 using Field
= decltype(Insn
);
276 Field h
= fieldFromInstruction(Insn
, 5, 3) |
277 (fieldFromInstruction(Insn
, 0, 2) << 3);
278 Field g
= fieldFromInstruction(Insn
, 8, 3) |
279 (fieldFromInstruction(Insn
, 3, 2) << 3);
281 auto DecodeRegisterOrImm
= [&Inst
, Address
, Decoder
](Field RegNum
,
284 Inst
.addOperand(MCOperand::createImm(Value
));
285 return MCDisassembler::Success
;
288 return DecodeGPR32RegisterClass(Inst
, RegNum
, Address
, Decoder
);
291 if (MCDisassembler::Success
!= DecodeRegisterOrImm(g
, 0))
292 return MCDisassembler::Fail
;
294 return DecodeRegisterOrImm(h
, Insn
>> 16u);
297 DecodeStatus
ARCDisassembler::getInstruction(MCInst
&Instr
, uint64_t &Size
,
298 ArrayRef
<uint8_t> Bytes
,
300 raw_ostream
&vStream
,
301 raw_ostream
&cStream
) const {
302 MCDisassembler::DecodeStatus Result
;
303 if (Bytes
.size() < 2) {
307 uint8_t DecodeByte
= (Bytes
[1] & 0xF7) >> 3;
308 // 0x00 -> 0x07 are 32-bit instructions.
309 // 0x08 -> 0x1F are 16-bit instructions.
310 if (DecodeByte
< 0x08) {
311 // 32-bit instruction.
312 if (Bytes
.size() < 4) {
313 // Did we decode garbage?
317 if (Bytes
.size() >= 8) {
318 // Attempt to decode 64-bit instruction.
320 if (!readInstruction64(Bytes
, Address
, Size
, Insn64
))
323 decodeInstruction(DecoderTable64
, Instr
, Insn64
, Address
, this, STI
);
324 if (Success
== Result
) {
325 LLVM_DEBUG(dbgs() << "Successfully decoded 64-bit instruction.");
328 LLVM_DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit.");
331 if (!readInstruction32(Bytes
, Address
, Size
, Insn32
)) {
334 // Calling the auto-generated decoder function.
335 return decodeInstruction(DecoderTable32
, Instr
, Insn32
, Address
, this, STI
);
337 if (Bytes
.size() >= 6) {
338 // Attempt to treat as instr. with limm data.
340 if (!readInstruction48(Bytes
, Address
, Size
, Insn48
))
343 decodeInstruction(DecoderTable48
, Instr
, Insn48
, Address
, this, STI
);
344 if (Success
== Result
) {
346 dbgs() << "Successfully decoded 16-bit instruction with limm.");
350 dbgs() << "Not a 16-bit instruction with limm, try without it.");
354 if (!readInstruction16(Bytes
, Address
, Size
, Insn16
))
357 // Calling the auto-generated decoder function.
358 return decodeInstruction(DecoderTable16
, Instr
, Insn16
, Address
, this, STI
);
362 static MCDisassembler
*createARCDisassembler(const Target
&T
,
363 const MCSubtargetInfo
&STI
,
365 return new ARCDisassembler(STI
, Ctx
, T
.createMCInstrInfo());
368 extern "C" void LLVMInitializeARCDisassembler() {
369 // Register the disassembler.
370 TargetRegistry::RegisterMCDisassembler(getTheARCTarget(),
371 createARCDisassembler
);