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