xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp (revision 5fb307d29b364982acbde82cbf77db3cae486f8c)
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:
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 
44 static MCDisassembler *createLoongArchDisassembler(const Target &T,
45                                                    const MCSubtargetInfo &STI,
46                                                    MCContext &Ctx) {
47   return new LoongArchDisassembler(STI, Ctx);
48 }
49 
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 
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 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 
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 
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 
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 
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 
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 
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>
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>
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 
152 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