1//===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- C++ -*-===//
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 is part of the Lanai Disassembler.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LanaiDisassembler.h"
14
15#include "LanaiAluCode.h"
16#include "LanaiCondCode.h"
17#include "LanaiInstrInfo.h"
18#include "TargetInfo/LanaiTargetInfo.h"
19#include "llvm/MC/MCDecoderOps.h"
20#include "llvm/MC/MCInst.h"
21#include "llvm/MC/MCSubtargetInfo.h"
22#include "llvm/MC/TargetRegistry.h"
23#include "llvm/Support/MathExtras.h"
24
25using namespace llvm;
26
27typedef MCDisassembler::DecodeStatus DecodeStatus;
28
29static MCDisassembler *createLanaiDisassembler(const Target & /*T*/,
30 const MCSubtargetInfo &STI,
31 MCContext &Ctx) {
32 return new LanaiDisassembler(STI, Ctx);
33}
34
35extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLanaiDisassembler() {
36 // Register the disassembler
37 TargetRegistry::RegisterMCDisassembler(T&: getTheLanaiTarget(),
38 Fn: createLanaiDisassembler);
39}
40
41LanaiDisassembler::LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
42 : MCDisassembler(STI, Ctx) {}
43
44// Forward declare because the autogenerated code will reference this.
45// Definition is further down.
46static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
47 uint64_t Address,
48 const MCDisassembler *Decoder);
49
50static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
51 uint64_t Address,
52 const MCDisassembler *Decoder);
53
54static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
55 uint64_t Address,
56 const MCDisassembler *Decoder);
57
58static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
59 uint64_t Address,
60 const MCDisassembler *Decoder);
61
62static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address,
63 const MCDisassembler *Decoder);
64
65static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
66 uint64_t Address,
67 const MCDisassembler *Decoder);
68
69static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
70 uint64_t Address,
71 const MCDisassembler *Decoder);
72
73#include "LanaiGenDisassemblerTables.inc"
74
75static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t &Size,
76 uint32_t &Insn) {
77 // We want to read exactly 4 bytes of data.
78 if (Bytes.size() < 4) {
79 Size = 0;
80 return MCDisassembler::Fail;
81 }
82
83 // Encoded as big-endian 32-bit word in the stream.
84 Insn =
85 (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | (Bytes[3] << 0);
86
87 return MCDisassembler::Success;
88}
89
90static void PostOperandDecodeAdjust(MCInst &Instr, uint32_t Insn) {
91 unsigned AluOp = LPAC::ADD;
92 // Fix up for pre and post operations.
93 int PqShift = -1;
94 if (isRMOpcode(Opcode: Instr.getOpcode()))
95 PqShift = 16;
96 else if (isSPLSOpcode(Opcode: Instr.getOpcode()))
97 PqShift = 10;
98 else if (isRRMOpcode(Opcode: Instr.getOpcode())) {
99 PqShift = 16;
100 // Determine RRM ALU op.
101 AluOp = (Insn >> 8) & 0x7;
102 if (AluOp == 7)
103 // Handle JJJJJ
104 // 0b10000 or 0b11000
105 AluOp |= 0x20 | (((Insn >> 3) & 0xf) << 1);
106 }
107
108 if (PqShift != -1) {
109 unsigned PQ = (Insn >> PqShift) & 0x3;
110 switch (PQ) {
111 case 0x0:
112 if (Instr.getOperand(i: 2).isReg()) {
113 Instr.getOperand(i: 2).setReg(Lanai::R0);
114 }
115 if (Instr.getOperand(i: 2).isImm())
116 Instr.getOperand(i: 2).setImm(0);
117 break;
118 case 0x1:
119 AluOp = LPAC::makePostOp(AluOp);
120 break;
121 case 0x2:
122 break;
123 case 0x3:
124 AluOp = LPAC::makePreOp(AluOp);
125 break;
126 }
127 Instr.addOperand(Op: MCOperand::createImm(Val: AluOp));
128 }
129}
130
131DecodeStatus
132LanaiDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
133 ArrayRef<uint8_t> Bytes, uint64_t Address,
134 raw_ostream & /*CStream*/) const {
135 uint32_t Insn;
136
137 DecodeStatus Result = readInstruction32(Bytes, Size, Insn);
138
139 if (Result == MCDisassembler::Fail)
140 return MCDisassembler::Fail;
141
142 // Call auto-generated decoder function
143 Result =
144 decodeInstruction(DecodeTable: DecoderTableLanai32, MI&: Instr, insn: Insn, Address, DisAsm: this, STI);
145
146 if (Result != MCDisassembler::Fail) {
147 PostOperandDecodeAdjust(Instr, Insn);
148 Size = 4;
149 return Result;
150 }
151
152 return MCDisassembler::Fail;
153}
154
155static const unsigned GPRDecoderTable[] = {
156 Lanai::R0, Lanai::R1, Lanai::PC, Lanai::R3, Lanai::SP, Lanai::FP,
157 Lanai::R6, Lanai::R7, Lanai::RV, Lanai::R9, Lanai::RR1, Lanai::RR2,
158 Lanai::R12, Lanai::R13, Lanai::R14, Lanai::RCA, Lanai::R16, Lanai::R17,
159 Lanai::R18, Lanai::R19, Lanai::R20, Lanai::R21, Lanai::R22, Lanai::R23,
160 Lanai::R24, Lanai::R25, Lanai::R26, Lanai::R27, Lanai::R28, Lanai::R29,
161 Lanai::R30, Lanai::R31};
162
163DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
164 uint64_t /*Address*/,
165 const MCDisassembler * /*Decoder*/) {
166 if (RegNo > 31)
167 return MCDisassembler::Fail;
168
169 unsigned Reg = GPRDecoderTable[RegNo];
170 Inst.addOperand(Op: MCOperand::createReg(Reg));
171 return MCDisassembler::Success;
172}
173
174static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
175 uint64_t Address,
176 const MCDisassembler *Decoder) {
177 // RI memory values encoded using 23 bits:
178 // 5 bit register, 16 bit constant
179 unsigned Register = (Insn >> 18) & 0x1f;
180 Inst.addOperand(Op: MCOperand::createReg(Reg: GPRDecoderTable[Register]));
181 unsigned Offset = (Insn & 0xffff);
182 Inst.addOperand(Op: MCOperand::createImm(Val: SignExtend32<16>(X: Offset)));
183
184 return MCDisassembler::Success;
185}
186
187static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
188 uint64_t Address,
189 const MCDisassembler *Decoder) {
190 // RR memory values encoded using 20 bits:
191 // 5 bit register, 5 bit register, 2 bit PQ, 3 bit ALU operator, 5 bit JJJJJ
192 unsigned Register = (Insn >> 15) & 0x1f;
193 Inst.addOperand(Op: MCOperand::createReg(Reg: GPRDecoderTable[Register]));
194 Register = (Insn >> 10) & 0x1f;
195 Inst.addOperand(Op: MCOperand::createReg(Reg: GPRDecoderTable[Register]));
196
197 return MCDisassembler::Success;
198}
199
200static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
201 uint64_t Address,
202 const MCDisassembler *Decoder) {
203 // RI memory values encoded using 17 bits:
204 // 5 bit register, 10 bit constant
205 unsigned Register = (Insn >> 12) & 0x1f;
206 Inst.addOperand(Op: MCOperand::createReg(Reg: GPRDecoderTable[Register]));
207 unsigned Offset = (Insn & 0x3ff);
208 Inst.addOperand(Op: MCOperand::createImm(Val: SignExtend32<10>(X: Offset)));
209
210 return MCDisassembler::Success;
211}
212
213static bool tryAddingSymbolicOperand(int64_t Value, bool IsBranch,
214 uint64_t Address, uint64_t Offset,
215 uint64_t Width, MCInst &MI,
216 const MCDisassembler *Decoder) {
217 return Decoder->tryAddingSymbolicOperand(Inst&: MI, Value, Address, IsBranch, Offset,
218 OpSize: Width, /*InstSize=*/0);
219}
220
221static DecodeStatus decodeBranch(MCInst &MI, unsigned Insn, uint64_t Address,
222 const MCDisassembler *Decoder) {
223 if (!tryAddingSymbolicOperand(Value: Insn + Address, IsBranch: false, Address, Offset: 2, Width: 23, MI,
224 Decoder))
225 MI.addOperand(Op: MCOperand::createImm(Val: Insn));
226 return MCDisassembler::Success;
227}
228
229static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
230 uint64_t Address,
231 const MCDisassembler *Decoder) {
232 unsigned Offset = (Insn & 0xffff);
233 Inst.addOperand(Op: MCOperand::createImm(Val: SignExtend32<16>(X: Offset)));
234
235 return MCDisassembler::Success;
236}
237
238static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
239 uint64_t Address,
240 const MCDisassembler *Decoder) {
241 if (Val >= LPCC::UNKNOWN)
242 return MCDisassembler::Fail;
243 Inst.addOperand(Op: MCOperand::createImm(Val));
244 return MCDisassembler::Success;
245}
246