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