1 //===-- LoongArchDisassembler.cpp - Disassembler for LoongArch ------------===//
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 // This file implements the LoongArchDisassembler class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
14 #include "TargetInfo/LoongArchTargetInfo.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCDecoderOps.h"
17 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstrInfo.h"
20 #include "llvm/MC/MCSubtargetInfo.h"
21 #include "llvm/MC/TargetRegistry.h"
22 #include "llvm/Support/Compiler.h"
23 #include "llvm/Support/Endian.h"
24
25 using namespace llvm;
26
27 #define DEBUG_TYPE "loongarch-disassembler"
28
29 typedef MCDisassembler::DecodeStatus DecodeStatus;
30
31 namespace {
32 class LoongArchDisassembler : public MCDisassembler {
33 public:
LoongArchDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx)34 LoongArchDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
35 : MCDisassembler(STI, Ctx) {}
36
37 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
38 ArrayRef<uint8_t> Bytes, uint64_t Address,
39 raw_ostream &CStream) const override;
40 };
41 } // end namespace
42
createLoongArchDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)43 static MCDisassembler *createLoongArchDisassembler(const Target &T,
44 const MCSubtargetInfo &STI,
45 MCContext &Ctx) {
46 return new LoongArchDisassembler(STI, Ctx);
47 }
48
49 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeLoongArchDisassembler()50 LLVMInitializeLoongArchDisassembler() {
51 // Register the disassembler for each target.
52 TargetRegistry::RegisterMCDisassembler(getTheLoongArch32Target(),
53 createLoongArchDisassembler);
54 TargetRegistry::RegisterMCDisassembler(getTheLoongArch64Target(),
55 createLoongArchDisassembler);
56 }
57
DecodeGPRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)58 static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
59 uint64_t Address,
60 const MCDisassembler *Decoder) {
61 if (RegNo >= 32)
62 return MCDisassembler::Fail;
63 Inst.addOperand(MCOperand::createReg(LoongArch::R0 + RegNo));
64 return MCDisassembler::Success;
65 }
66
67 static DecodeStatus
DecodeGPRNoR0R1RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)68 DecodeGPRNoR0R1RegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address,
69 const MCDisassembler *Decoder) {
70 if (RegNo <= 1)
71 return MCDisassembler::Fail;
72 return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
73 }
74
DecodeFPR32RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)75 static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo,
76 uint64_t Address,
77 const MCDisassembler *Decoder) {
78 if (RegNo >= 32)
79 return MCDisassembler::Fail;
80 Inst.addOperand(MCOperand::createReg(LoongArch::F0 + RegNo));
81 return MCDisassembler::Success;
82 }
83
DecodeFPR64RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)84 static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo,
85 uint64_t Address,
86 const MCDisassembler *Decoder) {
87 if (RegNo >= 32)
88 return MCDisassembler::Fail;
89 Inst.addOperand(MCOperand::createReg(LoongArch::F0_64 + RegNo));
90 return MCDisassembler::Success;
91 }
92
DecodeCFRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)93 static DecodeStatus DecodeCFRRegisterClass(MCInst &Inst, uint64_t RegNo,
94 uint64_t Address,
95 const MCDisassembler *Decoder) {
96 if (RegNo >= 8)
97 return MCDisassembler::Fail;
98 Inst.addOperand(MCOperand::createReg(LoongArch::FCC0 + RegNo));
99 return MCDisassembler::Success;
100 }
101
DecodeFCSRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)102 static DecodeStatus DecodeFCSRRegisterClass(MCInst &Inst, uint64_t RegNo,
103 uint64_t Address,
104 const MCDisassembler *Decoder) {
105 if (RegNo >= 4)
106 return MCDisassembler::Fail;
107 Inst.addOperand(MCOperand::createReg(LoongArch::FCSR0 + RegNo));
108 return MCDisassembler::Success;
109 }
110
DecodeLSX128RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)111 static DecodeStatus DecodeLSX128RegisterClass(MCInst &Inst, uint64_t RegNo,
112 uint64_t Address,
113 const MCDisassembler *Decoder) {
114 if (RegNo >= 32)
115 return MCDisassembler::Fail;
116 Inst.addOperand(MCOperand::createReg(LoongArch::VR0 + RegNo));
117 return MCDisassembler::Success;
118 }
119
DecodeLASX256RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)120 static DecodeStatus DecodeLASX256RegisterClass(MCInst &Inst, uint64_t RegNo,
121 uint64_t Address,
122 const MCDisassembler *Decoder) {
123 if (RegNo >= 32)
124 return MCDisassembler::Fail;
125 Inst.addOperand(MCOperand::createReg(LoongArch::XR0 + RegNo));
126 return MCDisassembler::Success;
127 }
128
DecodeSCRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)129 static DecodeStatus DecodeSCRRegisterClass(MCInst &Inst, uint64_t RegNo,
130 uint64_t Address,
131 const MCDisassembler *Decoder) {
132 if (RegNo >= 4)
133 return MCDisassembler::Fail;
134 Inst.addOperand(MCOperand::createReg(LoongArch::SCR0 + RegNo));
135 return MCDisassembler::Success;
136 }
137
138 template <unsigned N, int P = 0>
decodeUImmOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const MCDisassembler * Decoder)139 static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
140 int64_t Address,
141 const MCDisassembler *Decoder) {
142 assert(isUInt<N>(Imm) && "Invalid immediate");
143 Inst.addOperand(MCOperand::createImm(Imm + P));
144 return MCDisassembler::Success;
145 }
146
147 template <unsigned N, unsigned S = 0>
decodeSImmOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const MCDisassembler * Decoder)148 static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
149 int64_t Address,
150 const MCDisassembler *Decoder) {
151 assert(isUInt<N>(Imm) && "Invalid immediate");
152 // Shift left Imm <S> bits, then sign-extend the number in the bottom <N+S>
153 // bits.
154 Inst.addOperand(MCOperand::createImm(SignExtend64<N + S>(Imm << S)));
155 return MCDisassembler::Success;
156 }
157
158 #include "LoongArchGenDisassemblerTables.inc"
159
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CS) const160 DecodeStatus LoongArchDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
161 ArrayRef<uint8_t> Bytes,
162 uint64_t Address,
163 raw_ostream &CS) const {
164 uint32_t Insn;
165 DecodeStatus Result;
166
167 // We want to read exactly 4 bytes of data because all LoongArch instructions
168 // are fixed 32 bits.
169 if (Bytes.size() < 4) {
170 Size = 0;
171 return MCDisassembler::Fail;
172 }
173
174 Insn = support::endian::read32le(Bytes.data());
175 // Calling the auto-generated decoder function.
176 Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI);
177 Size = 4;
178
179 return Result;
180 }
181