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