xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp (revision 1342eb5a832fa10e689a29faab3acb6054e4778c)
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:
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 
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
50 LLVMInitializeLoongArchDisassembler() {
51   // Register the disassembler for each target.
52   TargetRegistry::RegisterMCDisassembler(getTheLoongArch32Target(),
53                                          createLoongArchDisassembler);
54   TargetRegistry::RegisterMCDisassembler(getTheLoongArch64Target(),
55                                          createLoongArchDisassembler);
56 }
57 
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
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 
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 
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 
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 
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 
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 
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 
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>
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>
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 
160 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