1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "disassembler_riscv64.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
20*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace art {
28*795d594fSAndroid Build Coastguard Worker namespace riscv64 {
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker class DisassemblerRiscv64::Printer {
31*795d594fSAndroid Build Coastguard Worker public:
Printer(DisassemblerRiscv64 * disassembler,std::ostream & os)32*795d594fSAndroid Build Coastguard Worker Printer(DisassemblerRiscv64* disassembler, std::ostream& os)
33*795d594fSAndroid Build Coastguard Worker : disassembler_(disassembler), os_(os) {}
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker void Dump32(const uint8_t* insn);
36*795d594fSAndroid Build Coastguard Worker void Dump16(const uint8_t* insn);
37*795d594fSAndroid Build Coastguard Worker void Dump2Byte(const uint8_t* data);
38*795d594fSAndroid Build Coastguard Worker void DumpByte(const uint8_t* data);
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard Worker private:
41*795d594fSAndroid Build Coastguard Worker // This enumeration should mirror the declarations in runtime/arch/riscv64/registers_riscv64.h.
42*795d594fSAndroid Build Coastguard Worker // We do not include that file to avoid a dependency on libart.
43*795d594fSAndroid Build Coastguard Worker enum {
44*795d594fSAndroid Build Coastguard Worker Zero = 0,
45*795d594fSAndroid Build Coastguard Worker RA = 1,
46*795d594fSAndroid Build Coastguard Worker FP = 8,
47*795d594fSAndroid Build Coastguard Worker TR = 9,
48*795d594fSAndroid Build Coastguard Worker };
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker enum class MemAddressMode : uint32_t {
51*795d594fSAndroid Build Coastguard Worker kUnitStride = 0b00,
52*795d594fSAndroid Build Coastguard Worker kIndexedUnordered = 0b01,
53*795d594fSAndroid Build Coastguard Worker kStrided = 0b10,
54*795d594fSAndroid Build Coastguard Worker kIndexedOrdered = 0b11,
55*795d594fSAndroid Build Coastguard Worker };
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker enum class Nf : uint32_t {
58*795d594fSAndroid Build Coastguard Worker k1 = 0b000,
59*795d594fSAndroid Build Coastguard Worker k2 = 0b001,
60*795d594fSAndroid Build Coastguard Worker k3 = 0b010,
61*795d594fSAndroid Build Coastguard Worker k4 = 0b011,
62*795d594fSAndroid Build Coastguard Worker k5 = 0b100,
63*795d594fSAndroid Build Coastguard Worker k6 = 0b101,
64*795d594fSAndroid Build Coastguard Worker k7 = 0b110,
65*795d594fSAndroid Build Coastguard Worker k8 = 0b111,
66*795d594fSAndroid Build Coastguard Worker };
67*795d594fSAndroid Build Coastguard Worker
68*795d594fSAndroid Build Coastguard Worker enum class VAIEncodings : uint32_t {
69*795d594fSAndroid Build Coastguard Worker kOpIVV = 0b000,
70*795d594fSAndroid Build Coastguard Worker kOpFVV = 0b001,
71*795d594fSAndroid Build Coastguard Worker kOpMVV = 0b010,
72*795d594fSAndroid Build Coastguard Worker kOpIVI = 0b011,
73*795d594fSAndroid Build Coastguard Worker kOpIVX = 0b100,
74*795d594fSAndroid Build Coastguard Worker kOpFVF = 0b101,
75*795d594fSAndroid Build Coastguard Worker kOpMVX = 0b110,
76*795d594fSAndroid Build Coastguard Worker kOpCFG = 0b111,
77*795d594fSAndroid Build Coastguard Worker };
78*795d594fSAndroid Build Coastguard Worker
79*795d594fSAndroid Build Coastguard Worker class ScopedNewLinePrinter {
80*795d594fSAndroid Build Coastguard Worker std::ostream& os_;
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker public:
ScopedNewLinePrinter(std::ostream & os)83*795d594fSAndroid Build Coastguard Worker explicit ScopedNewLinePrinter(std::ostream& os) : os_(os) {}
~ScopedNewLinePrinter()84*795d594fSAndroid Build Coastguard Worker ~ScopedNewLinePrinter() { os_ << '\n'; }
85*795d594fSAndroid Build Coastguard Worker };
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker static const char* XRegName(uint32_t regno);
88*795d594fSAndroid Build Coastguard Worker static const char* FRegName(uint32_t regno);
89*795d594fSAndroid Build Coastguard Worker static const char* VRegName(uint32_t regno);
90*795d594fSAndroid Build Coastguard Worker static const char* RoundingModeName(uint32_t rm);
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker // Regular instruction immediate utils
93*795d594fSAndroid Build Coastguard Worker
Decode32Imm12(uint32_t insn32)94*795d594fSAndroid Build Coastguard Worker static int32_t Decode32Imm12(uint32_t insn32) {
95*795d594fSAndroid Build Coastguard Worker uint32_t sign = (insn32 >> 31);
96*795d594fSAndroid Build Coastguard Worker uint32_t imm12 = (insn32 >> 20);
97*795d594fSAndroid Build Coastguard Worker return static_cast<int32_t>(imm12) - static_cast<int32_t>(sign << 12); // Sign-extend.
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker
Decode32UImm7(uint32_t insn32)100*795d594fSAndroid Build Coastguard Worker static uint32_t Decode32UImm7(uint32_t insn32) { return (insn32 >> 25) & 0x7Fu; }
101*795d594fSAndroid Build Coastguard Worker
Decode32UImm12(uint32_t insn32)102*795d594fSAndroid Build Coastguard Worker static uint32_t Decode32UImm12(uint32_t insn32) { return (insn32 >> 20) & 0xFFFu; }
103*795d594fSAndroid Build Coastguard Worker
Decode32StoreOffset(uint32_t insn32)104*795d594fSAndroid Build Coastguard Worker static int32_t Decode32StoreOffset(uint32_t insn32) {
105*795d594fSAndroid Build Coastguard Worker uint32_t bit11 = insn32 >> 31;
106*795d594fSAndroid Build Coastguard Worker uint32_t bits5_11 = insn32 >> 25;
107*795d594fSAndroid Build Coastguard Worker uint32_t bits0_4 = (insn32 >> 7) & 0x1fu;
108*795d594fSAndroid Build Coastguard Worker uint32_t imm = (bits5_11 << 5) + bits0_4;
109*795d594fSAndroid Build Coastguard Worker return static_cast<int32_t>(imm) - static_cast<int32_t>(bit11 << 12); // Sign-extend.
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker // Compressed instruction immediate utils
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker // Extracts the offset from a compressed instruction
115*795d594fSAndroid Build Coastguard Worker // where `offset[5:3]` is in bits `[12:10]` and `offset[2|6]` is in bits `[6:5]`
Decode16CMOffsetW(uint32_t insn16)116*795d594fSAndroid Build Coastguard Worker static uint32_t Decode16CMOffsetW(uint32_t insn16) {
117*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<16>(insn16));
118*795d594fSAndroid Build Coastguard Worker return BitFieldExtract(insn16, 5, 1) << 6 | BitFieldExtract(insn16, 10, 3) << 3 |
119*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 6, 1) << 2;
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker // Extracts the offset from a compressed instruction
123*795d594fSAndroid Build Coastguard Worker // where `offset[5:3]` is in bits `[12:10]` and `offset[7:6]` is in bits `[6:5]`
Decode16CMOffsetD(uint32_t insn16)124*795d594fSAndroid Build Coastguard Worker static uint32_t Decode16CMOffsetD(uint32_t insn16) {
125*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<16>(insn16));
126*795d594fSAndroid Build Coastguard Worker return BitFieldExtract(insn16, 5, 2) << 6 | BitFieldExtract(insn16, 10, 3) << 3;
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker // Re-orders raw immediatate into real value
130*795d594fSAndroid Build Coastguard Worker // where `imm[5:3]` is in bits `[5:3]` and `imm[8:6]` is in bits `[2:0]`
Uimm6ToOffsetD16(uint32_t uimm6)131*795d594fSAndroid Build Coastguard Worker static uint32_t Uimm6ToOffsetD16(uint32_t uimm6) {
132*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<6>(uimm6));
133*795d594fSAndroid Build Coastguard Worker return (BitFieldExtract(uimm6, 3, 3) << 3) | (BitFieldExtract(uimm6, 0, 3) << 6);
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker // Re-orders raw immediatate to form real value
137*795d594fSAndroid Build Coastguard Worker // where `imm[5:2]` is in bits `[5:2]` and `imm[7:6]` is in bits `[1:0]`
Uimm6ToOffsetW16(uint32_t uimm6)138*795d594fSAndroid Build Coastguard Worker static uint32_t Uimm6ToOffsetW16(uint32_t uimm6) {
139*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<6>(uimm6));
140*795d594fSAndroid Build Coastguard Worker return (BitFieldExtract(uimm6, 2, 4) << 2) | (BitFieldExtract(uimm6, 0, 2) << 6);
141*795d594fSAndroid Build Coastguard Worker }
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard Worker // Re-orders raw immediatate to form real value
144*795d594fSAndroid Build Coastguard Worker // where `imm[1]` is in bit `[0]` and `imm[0]` is in bit `[1]`
Uimm2ToOffset10(uint32_t uimm2)145*795d594fSAndroid Build Coastguard Worker static uint32_t Uimm2ToOffset10(uint32_t uimm2) {
146*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<2>(uimm2));
147*795d594fSAndroid Build Coastguard Worker return (uimm2 >> 1) | (uimm2 & 0x1u) << 1;
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker
150*795d594fSAndroid Build Coastguard Worker // Re-orders raw immediatate to form real value
151*795d594fSAndroid Build Coastguard Worker // where `imm[1]` is in bit `[0]` and `imm[0]` is `0`
Uimm2ToOffset1(uint32_t uimm2)152*795d594fSAndroid Build Coastguard Worker static uint32_t Uimm2ToOffset1(uint32_t uimm2) {
153*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<2>(uimm2));
154*795d594fSAndroid Build Coastguard Worker return (uimm2 & 0x1u) << 1;
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker
157*795d594fSAndroid Build Coastguard Worker template <size_t kWidth>
SignExtendBits(uint32_t bits)158*795d594fSAndroid Build Coastguard Worker static constexpr int32_t SignExtendBits(uint32_t bits) {
159*795d594fSAndroid Build Coastguard Worker static_assert(kWidth < BitSizeOf<uint32_t>());
160*795d594fSAndroid Build Coastguard Worker const uint32_t sign_bit = (bits >> kWidth) & 1u;
161*795d594fSAndroid Build Coastguard Worker return static_cast<int32_t>(bits) - static_cast<int32_t>(sign_bit << kWidth);
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker // Extracts the immediate from a compressed instruction
165*795d594fSAndroid Build Coastguard Worker // where `imm[5]` is in bit `[12]` and `imm[4:0]` is in bits `[6:2]`
166*795d594fSAndroid Build Coastguard Worker // and performs sign-extension if required
167*795d594fSAndroid Build Coastguard Worker template <typename T>
Decode16Imm6(uint32_t insn16)168*795d594fSAndroid Build Coastguard Worker static T Decode16Imm6(uint32_t insn16) {
169*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<16>(insn16));
170*795d594fSAndroid Build Coastguard Worker static_assert(std::is_integral_v<T>, "T must be integral");
171*795d594fSAndroid Build Coastguard Worker const T bits =
172*795d594fSAndroid Build Coastguard Worker BitFieldInsert(BitFieldExtract(insn16, 2, 5), BitFieldExtract(insn16, 12, 1), 5, 1);
173*795d594fSAndroid Build Coastguard Worker const T checked_bits = dchecked_integral_cast<T>(bits);
174*795d594fSAndroid Build Coastguard Worker if (std::is_unsigned_v<T>) {
175*795d594fSAndroid Build Coastguard Worker return checked_bits;
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker return SignExtendBits<6>(checked_bits);
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker
180*795d594fSAndroid Build Coastguard Worker // Regular instruction register utils
181*795d594fSAndroid Build Coastguard Worker
GetRd(uint32_t insn32)182*795d594fSAndroid Build Coastguard Worker static uint32_t GetRd(uint32_t insn32) { return (insn32 >> 7) & 0x1fu; }
GetRs1(uint32_t insn32)183*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs1(uint32_t insn32) { return (insn32 >> 15) & 0x1fu; }
GetRs2(uint32_t insn32)184*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs2(uint32_t insn32) { return (insn32 >> 20) & 0x1fu; }
GetRs3(uint32_t insn32)185*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs3(uint32_t insn32) { return insn32 >> 27; }
GetRoundingMode(uint32_t insn32)186*795d594fSAndroid Build Coastguard Worker static uint32_t GetRoundingMode(uint32_t insn32) { return (insn32 >> 12) & 7u; }
187*795d594fSAndroid Build Coastguard Worker
188*795d594fSAndroid Build Coastguard Worker // Compressed instruction register utils
189*795d594fSAndroid Build Coastguard Worker
GetRs1Short16(uint32_t insn16)190*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs1Short16(uint32_t insn16) { return BitFieldExtract(insn16, 7, 3) + 8u; }
GetRs2Short16(uint32_t insn16)191*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs2Short16(uint32_t insn16) { return BitFieldExtract(insn16, 2, 3) + 8u; }
GetRs1_16(uint32_t insn16)192*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs1_16(uint32_t insn16) { return BitFieldExtract(insn16, 7, 5); }
GetRs2_16(uint32_t insn16)193*795d594fSAndroid Build Coastguard Worker static uint32_t GetRs2_16(uint32_t insn16) { return BitFieldExtract(insn16, 2, 5); }
194*795d594fSAndroid Build Coastguard Worker
195*795d594fSAndroid Build Coastguard Worker void PrintBranchOffset(int32_t offset);
196*795d594fSAndroid Build Coastguard Worker void PrintLoadStoreAddress(uint32_t rs1, int32_t offset);
197*795d594fSAndroid Build Coastguard Worker
198*795d594fSAndroid Build Coastguard Worker void Print32Lui(uint32_t insn32);
199*795d594fSAndroid Build Coastguard Worker void Print32Auipc(const uint8_t* insn, uint32_t insn32);
200*795d594fSAndroid Build Coastguard Worker void Print32Jal(const uint8_t* insn, uint32_t insn32);
201*795d594fSAndroid Build Coastguard Worker void Print32Jalr(const uint8_t* insn, uint32_t insn32);
202*795d594fSAndroid Build Coastguard Worker void Print32BCond(const uint8_t* insn, uint32_t insn32);
203*795d594fSAndroid Build Coastguard Worker void Print32Load(uint32_t insn32);
204*795d594fSAndroid Build Coastguard Worker void Print32Store(uint32_t insn32);
205*795d594fSAndroid Build Coastguard Worker void Print32FLoad(uint32_t insn32);
206*795d594fSAndroid Build Coastguard Worker void Print32FStore(uint32_t insn32);
207*795d594fSAndroid Build Coastguard Worker void Print32BinOpImm(uint32_t insn32);
208*795d594fSAndroid Build Coastguard Worker void Print32BinOp(uint32_t insn32);
209*795d594fSAndroid Build Coastguard Worker void Print32Atomic(uint32_t insn32);
210*795d594fSAndroid Build Coastguard Worker void Print32FpOp(uint32_t insn32);
211*795d594fSAndroid Build Coastguard Worker void Print32RVVOp(uint32_t insn32);
212*795d594fSAndroid Build Coastguard Worker void Print32FpFma(uint32_t insn32);
213*795d594fSAndroid Build Coastguard Worker void Print32Zicsr(uint32_t insn32);
214*795d594fSAndroid Build Coastguard Worker void Print32Fence(uint32_t insn32);
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker void AppendVType(uint32_t zimm);
217*795d594fSAndroid Build Coastguard Worker static const char* DecodeRVVMemMnemonic(const uint32_t insn32,
218*795d594fSAndroid Build Coastguard Worker bool is_load,
219*795d594fSAndroid Build Coastguard Worker /*out*/ const char** rs2);
220*795d594fSAndroid Build Coastguard Worker
221*795d594fSAndroid Build Coastguard Worker DisassemblerRiscv64* const disassembler_;
222*795d594fSAndroid Build Coastguard Worker std::ostream& os_;
223*795d594fSAndroid Build Coastguard Worker };
224*795d594fSAndroid Build Coastguard Worker
XRegName(uint32_t regno)225*795d594fSAndroid Build Coastguard Worker const char* DisassemblerRiscv64::Printer::XRegName(uint32_t regno) {
226*795d594fSAndroid Build Coastguard Worker static const char* const kXRegisterNames[] = {
227*795d594fSAndroid Build Coastguard Worker "zero",
228*795d594fSAndroid Build Coastguard Worker "ra",
229*795d594fSAndroid Build Coastguard Worker "sp",
230*795d594fSAndroid Build Coastguard Worker "gp",
231*795d594fSAndroid Build Coastguard Worker "tp",
232*795d594fSAndroid Build Coastguard Worker "t0",
233*795d594fSAndroid Build Coastguard Worker "t1",
234*795d594fSAndroid Build Coastguard Worker "t2",
235*795d594fSAndroid Build Coastguard Worker "fp", // s0/fp
236*795d594fSAndroid Build Coastguard Worker "tr", // s1/tr - ART thread register
237*795d594fSAndroid Build Coastguard Worker "a0",
238*795d594fSAndroid Build Coastguard Worker "a1",
239*795d594fSAndroid Build Coastguard Worker "a2",
240*795d594fSAndroid Build Coastguard Worker "a3",
241*795d594fSAndroid Build Coastguard Worker "a4",
242*795d594fSAndroid Build Coastguard Worker "a5",
243*795d594fSAndroid Build Coastguard Worker "a6",
244*795d594fSAndroid Build Coastguard Worker "a7",
245*795d594fSAndroid Build Coastguard Worker "s2",
246*795d594fSAndroid Build Coastguard Worker "s3",
247*795d594fSAndroid Build Coastguard Worker "s4",
248*795d594fSAndroid Build Coastguard Worker "s5",
249*795d594fSAndroid Build Coastguard Worker "s6",
250*795d594fSAndroid Build Coastguard Worker "s7",
251*795d594fSAndroid Build Coastguard Worker "s8",
252*795d594fSAndroid Build Coastguard Worker "s9",
253*795d594fSAndroid Build Coastguard Worker "s10",
254*795d594fSAndroid Build Coastguard Worker "s11",
255*795d594fSAndroid Build Coastguard Worker "t3",
256*795d594fSAndroid Build Coastguard Worker "t4",
257*795d594fSAndroid Build Coastguard Worker "t5",
258*795d594fSAndroid Build Coastguard Worker "t6",
259*795d594fSAndroid Build Coastguard Worker };
260*795d594fSAndroid Build Coastguard Worker static_assert(std::size(kXRegisterNames) == 32);
261*795d594fSAndroid Build Coastguard Worker DCHECK_LT(regno, 32u);
262*795d594fSAndroid Build Coastguard Worker return kXRegisterNames[regno];
263*795d594fSAndroid Build Coastguard Worker }
264*795d594fSAndroid Build Coastguard Worker
FRegName(uint32_t regno)265*795d594fSAndroid Build Coastguard Worker const char* DisassemblerRiscv64::Printer::FRegName(uint32_t regno) {
266*795d594fSAndroid Build Coastguard Worker static const char* const kFRegisterNames[] = {
267*795d594fSAndroid Build Coastguard Worker "ft0",
268*795d594fSAndroid Build Coastguard Worker "ft1",
269*795d594fSAndroid Build Coastguard Worker "ft2",
270*795d594fSAndroid Build Coastguard Worker "ft3",
271*795d594fSAndroid Build Coastguard Worker "ft4",
272*795d594fSAndroid Build Coastguard Worker "ft5",
273*795d594fSAndroid Build Coastguard Worker "ft6",
274*795d594fSAndroid Build Coastguard Worker "ft7",
275*795d594fSAndroid Build Coastguard Worker "fs0",
276*795d594fSAndroid Build Coastguard Worker "fs1",
277*795d594fSAndroid Build Coastguard Worker "fa0",
278*795d594fSAndroid Build Coastguard Worker "fa1",
279*795d594fSAndroid Build Coastguard Worker "fa2",
280*795d594fSAndroid Build Coastguard Worker "fa3",
281*795d594fSAndroid Build Coastguard Worker "fa4",
282*795d594fSAndroid Build Coastguard Worker "fa5",
283*795d594fSAndroid Build Coastguard Worker "fa6",
284*795d594fSAndroid Build Coastguard Worker "fa7",
285*795d594fSAndroid Build Coastguard Worker "fs2",
286*795d594fSAndroid Build Coastguard Worker "fs3",
287*795d594fSAndroid Build Coastguard Worker "fs4",
288*795d594fSAndroid Build Coastguard Worker "fs5",
289*795d594fSAndroid Build Coastguard Worker "fs6",
290*795d594fSAndroid Build Coastguard Worker "fs7",
291*795d594fSAndroid Build Coastguard Worker "fs8",
292*795d594fSAndroid Build Coastguard Worker "fs9",
293*795d594fSAndroid Build Coastguard Worker "fs10",
294*795d594fSAndroid Build Coastguard Worker "fs11",
295*795d594fSAndroid Build Coastguard Worker "ft8",
296*795d594fSAndroid Build Coastguard Worker "ft9",
297*795d594fSAndroid Build Coastguard Worker "ft10",
298*795d594fSAndroid Build Coastguard Worker "ft11",
299*795d594fSAndroid Build Coastguard Worker };
300*795d594fSAndroid Build Coastguard Worker static_assert(std::size(kFRegisterNames) == 32);
301*795d594fSAndroid Build Coastguard Worker DCHECK_LT(regno, 32u);
302*795d594fSAndroid Build Coastguard Worker return kFRegisterNames[regno];
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker
VRegName(uint32_t regno)305*795d594fSAndroid Build Coastguard Worker const char* DisassemblerRiscv64::Printer::VRegName(uint32_t regno) {
306*795d594fSAndroid Build Coastguard Worker static const char* const kVRegisterNames[] = {
307*795d594fSAndroid Build Coastguard Worker "V0",
308*795d594fSAndroid Build Coastguard Worker "V1",
309*795d594fSAndroid Build Coastguard Worker "V2",
310*795d594fSAndroid Build Coastguard Worker "V3",
311*795d594fSAndroid Build Coastguard Worker "V4",
312*795d594fSAndroid Build Coastguard Worker "V5",
313*795d594fSAndroid Build Coastguard Worker "V6",
314*795d594fSAndroid Build Coastguard Worker "V7",
315*795d594fSAndroid Build Coastguard Worker "V8",
316*795d594fSAndroid Build Coastguard Worker "V9",
317*795d594fSAndroid Build Coastguard Worker "V10",
318*795d594fSAndroid Build Coastguard Worker "V11",
319*795d594fSAndroid Build Coastguard Worker "V12",
320*795d594fSAndroid Build Coastguard Worker "V13",
321*795d594fSAndroid Build Coastguard Worker "V14",
322*795d594fSAndroid Build Coastguard Worker "V15",
323*795d594fSAndroid Build Coastguard Worker "V16",
324*795d594fSAndroid Build Coastguard Worker "V17",
325*795d594fSAndroid Build Coastguard Worker "V18",
326*795d594fSAndroid Build Coastguard Worker "V19",
327*795d594fSAndroid Build Coastguard Worker "V20",
328*795d594fSAndroid Build Coastguard Worker "V21",
329*795d594fSAndroid Build Coastguard Worker "V22",
330*795d594fSAndroid Build Coastguard Worker "V23",
331*795d594fSAndroid Build Coastguard Worker "V24",
332*795d594fSAndroid Build Coastguard Worker "V25",
333*795d594fSAndroid Build Coastguard Worker "V26",
334*795d594fSAndroid Build Coastguard Worker "V27",
335*795d594fSAndroid Build Coastguard Worker "V28",
336*795d594fSAndroid Build Coastguard Worker "V29",
337*795d594fSAndroid Build Coastguard Worker "V30",
338*795d594fSAndroid Build Coastguard Worker "V31",
339*795d594fSAndroid Build Coastguard Worker };
340*795d594fSAndroid Build Coastguard Worker static_assert(std::size(kVRegisterNames) == 32);
341*795d594fSAndroid Build Coastguard Worker DCHECK_LT(regno, 32u);
342*795d594fSAndroid Build Coastguard Worker return kVRegisterNames[regno];
343*795d594fSAndroid Build Coastguard Worker }
344*795d594fSAndroid Build Coastguard Worker
RoundingModeName(uint32_t rm)345*795d594fSAndroid Build Coastguard Worker const char* DisassemblerRiscv64::Printer::RoundingModeName(uint32_t rm) {
346*795d594fSAndroid Build Coastguard Worker // Note: We do not print the rounding mode for DYN.
347*795d594fSAndroid Build Coastguard Worker static const char* const kRoundingModeNames[] = {
348*795d594fSAndroid Build Coastguard Worker ".rne", ".rtz", ".rdn", ".rup", ".rmm", ".<reserved-rm>", ".<reserved-rm>", /*DYN*/ ""
349*795d594fSAndroid Build Coastguard Worker };
350*795d594fSAndroid Build Coastguard Worker static_assert(std::size(kRoundingModeNames) == 8);
351*795d594fSAndroid Build Coastguard Worker DCHECK_LT(rm, 8u);
352*795d594fSAndroid Build Coastguard Worker return kRoundingModeNames[rm];
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker
PrintBranchOffset(int32_t offset)355*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::PrintBranchOffset(int32_t offset) {
356*795d594fSAndroid Build Coastguard Worker os_ << (offset >= 0 ? "+" : "") << offset;
357*795d594fSAndroid Build Coastguard Worker }
358*795d594fSAndroid Build Coastguard Worker
PrintLoadStoreAddress(uint32_t rs1,int32_t offset)359*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::PrintLoadStoreAddress(uint32_t rs1, int32_t offset) {
360*795d594fSAndroid Build Coastguard Worker if (offset != 0) {
361*795d594fSAndroid Build Coastguard Worker os_ << StringPrintf("%d", offset);
362*795d594fSAndroid Build Coastguard Worker }
363*795d594fSAndroid Build Coastguard Worker os_ << "(" << XRegName(rs1) << ")";
364*795d594fSAndroid Build Coastguard Worker
365*795d594fSAndroid Build Coastguard Worker if (rs1 == TR && offset >= 0) {
366*795d594fSAndroid Build Coastguard Worker // Add entrypoint name.
367*795d594fSAndroid Build Coastguard Worker os_ << " ; ";
368*795d594fSAndroid Build Coastguard Worker disassembler_->GetDisassemblerOptions()->thread_offset_name_function_(
369*795d594fSAndroid Build Coastguard Worker os_, dchecked_integral_cast<uint32_t>(offset));
370*795d594fSAndroid Build Coastguard Worker }
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker
Print32Lui(uint32_t insn32)373*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Lui(uint32_t insn32) {
374*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x37u);
375*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Should we also print the actual sign-extend value?
376*795d594fSAndroid Build Coastguard Worker os_ << StringPrintf("lui %s, %u", XRegName(GetRd(insn32)), insn32 >> 12);
377*795d594fSAndroid Build Coastguard Worker }
378*795d594fSAndroid Build Coastguard Worker
Print32Auipc(const uint8_t * insn,uint32_t insn32)379*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Auipc([[maybe_unused]] const uint8_t* insn,
380*795d594fSAndroid Build Coastguard Worker uint32_t insn32) {
381*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x17u);
382*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Should we also print the calculated address?
383*795d594fSAndroid Build Coastguard Worker os_ << StringPrintf("auipc %s, %u", XRegName(GetRd(insn32)), insn32 >> 12);
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker
Print32Jal(const uint8_t * insn,uint32_t insn32)386*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Jal(const uint8_t* insn, uint32_t insn32) {
387*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x6fu);
388*795d594fSAndroid Build Coastguard Worker // Print an alias if available.
389*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
390*795d594fSAndroid Build Coastguard Worker os_ << (rd == Zero ? "j " : "jal ");
391*795d594fSAndroid Build Coastguard Worker if (rd != Zero && rd != RA) {
392*795d594fSAndroid Build Coastguard Worker os_ << XRegName(rd) << ", ";
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker uint32_t bit20 = (insn32 >> 31);
395*795d594fSAndroid Build Coastguard Worker uint32_t bits1_10 = (insn32 >> 21) & 0x3ffu;
396*795d594fSAndroid Build Coastguard Worker uint32_t bit11 = (insn32 >> 20) & 1u;
397*795d594fSAndroid Build Coastguard Worker uint32_t bits12_19 = (insn32 >> 12) & 0xffu;
398*795d594fSAndroid Build Coastguard Worker uint32_t imm = (bits1_10 << 1) + (bit11 << 11) + (bits12_19 << 12) + (bit20 << 20);
399*795d594fSAndroid Build Coastguard Worker int32_t offset = static_cast<int32_t>(imm) - static_cast<int32_t>(bit20 << 21); // Sign-extend.
400*795d594fSAndroid Build Coastguard Worker PrintBranchOffset(offset);
401*795d594fSAndroid Build Coastguard Worker os_ << " ; " << disassembler_->FormatInstructionPointer(insn + offset);
402*795d594fSAndroid Build Coastguard Worker
403*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): When we implement shared thunks to reduce AOT slow-path code size,
404*795d594fSAndroid Build Coastguard Worker // check if this JAL lands at an entrypoint load from TR and, if so, print its name.
405*795d594fSAndroid Build Coastguard Worker }
406*795d594fSAndroid Build Coastguard Worker
Print32Jalr(const uint8_t * insn,uint32_t insn32)407*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Jalr([[maybe_unused]] const uint8_t* insn,
408*795d594fSAndroid Build Coastguard Worker uint32_t insn32) {
409*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x67u);
410*795d594fSAndroid Build Coastguard Worker DCHECK_EQ((insn32 >> 12) & 7u, 0u);
411*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
412*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
413*795d594fSAndroid Build Coastguard Worker int32_t imm12 = Decode32Imm12(insn32);
414*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
415*795d594fSAndroid Build Coastguard Worker if (rd == Zero && rs1 == RA && imm12 == 0) {
416*795d594fSAndroid Build Coastguard Worker os_ << "ret";
417*795d594fSAndroid Build Coastguard Worker } else if (rd == Zero && imm12 == 0) {
418*795d594fSAndroid Build Coastguard Worker os_ << "jr " << XRegName(rs1);
419*795d594fSAndroid Build Coastguard Worker } else if (rd == RA && imm12 == 0) {
420*795d594fSAndroid Build Coastguard Worker os_ << "jalr " << XRegName(rs1);
421*795d594fSAndroid Build Coastguard Worker } else {
422*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Should we also print the calculated address if the preceding
423*795d594fSAndroid Build Coastguard Worker // instruction is AUIPC? (We would need to record the previous instruction.)
424*795d594fSAndroid Build Coastguard Worker os_ << "jalr " << XRegName(rd) << ", ";
425*795d594fSAndroid Build Coastguard Worker // Use the same format as llvm-objdump: "rs1" if `imm12` is zero, otherwise "imm12(rs1)".
426*795d594fSAndroid Build Coastguard Worker if (imm12 == 0) {
427*795d594fSAndroid Build Coastguard Worker os_ << XRegName(rs1);
428*795d594fSAndroid Build Coastguard Worker } else {
429*795d594fSAndroid Build Coastguard Worker os_ << imm12 << "(" << XRegName(rs1) << ")";
430*795d594fSAndroid Build Coastguard Worker }
431*795d594fSAndroid Build Coastguard Worker }
432*795d594fSAndroid Build Coastguard Worker }
433*795d594fSAndroid Build Coastguard Worker
Print32BCond(const uint8_t * insn,uint32_t insn32)434*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32BCond(const uint8_t* insn, uint32_t insn32) {
435*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x63u);
436*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
437*795d594fSAndroid Build Coastguard Worker "beq", "bne", nullptr, nullptr, "blt", "bge", "bltu", "bgeu"
438*795d594fSAndroid Build Coastguard Worker };
439*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
440*795d594fSAndroid Build Coastguard Worker const char* opcode = kOpcodes[funct3];
441*795d594fSAndroid Build Coastguard Worker if (opcode == nullptr) {
442*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
443*795d594fSAndroid Build Coastguard Worker return;
444*795d594fSAndroid Build Coastguard Worker }
445*795d594fSAndroid Build Coastguard Worker
446*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
447*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
448*795d594fSAndroid Build Coastguard Worker uint32_t rs2 = GetRs2(insn32);
449*795d594fSAndroid Build Coastguard Worker if (rs2 == Zero) {
450*795d594fSAndroid Build Coastguard Worker os_ << opcode << "z " << XRegName(rs1);
451*795d594fSAndroid Build Coastguard Worker } else if (rs1 == Zero && (funct3 == 4u || funct3 == 5u)) {
452*795d594fSAndroid Build Coastguard Worker // blt zero, rs2, offset ... bgtz rs2, offset
453*795d594fSAndroid Build Coastguard Worker // bge zero, rs2, offset ... blez rs2, offset
454*795d594fSAndroid Build Coastguard Worker os_ << (funct3 == 4u ? "bgtz " : "blez ") << XRegName(rs2);
455*795d594fSAndroid Build Coastguard Worker } else {
456*795d594fSAndroid Build Coastguard Worker os_ << opcode << " " << XRegName(rs1) << ", " << XRegName(rs2);
457*795d594fSAndroid Build Coastguard Worker }
458*795d594fSAndroid Build Coastguard Worker os_ << ", ";
459*795d594fSAndroid Build Coastguard Worker
460*795d594fSAndroid Build Coastguard Worker uint32_t bit12 = insn32 >> 31;
461*795d594fSAndroid Build Coastguard Worker uint32_t bits5_10 = (insn32 >> 25) & 0x3fu;
462*795d594fSAndroid Build Coastguard Worker uint32_t bits1_4 = (insn32 >> 8) & 0xfu;
463*795d594fSAndroid Build Coastguard Worker uint32_t bit11 = (insn32 >> 7) & 1u;
464*795d594fSAndroid Build Coastguard Worker uint32_t imm = (bit12 << 12) + (bit11 << 11) + (bits5_10 << 5) + (bits1_4 << 1);
465*795d594fSAndroid Build Coastguard Worker int32_t offset = static_cast<int32_t>(imm) - static_cast<int32_t>(bit12 << 13); // Sign-extend.
466*795d594fSAndroid Build Coastguard Worker PrintBranchOffset(offset);
467*795d594fSAndroid Build Coastguard Worker os_ << " ; " << disassembler_->FormatInstructionPointer(insn + offset);
468*795d594fSAndroid Build Coastguard Worker }
469*795d594fSAndroid Build Coastguard Worker
Print32Load(uint32_t insn32)470*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Load(uint32_t insn32) {
471*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x03u);
472*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
473*795d594fSAndroid Build Coastguard Worker "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", nullptr
474*795d594fSAndroid Build Coastguard Worker };
475*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
476*795d594fSAndroid Build Coastguard Worker const char* opcode = kOpcodes[funct3];
477*795d594fSAndroid Build Coastguard Worker if (opcode == nullptr) {
478*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
479*795d594fSAndroid Build Coastguard Worker return;
480*795d594fSAndroid Build Coastguard Worker }
481*795d594fSAndroid Build Coastguard Worker
482*795d594fSAndroid Build Coastguard Worker os_ << opcode << " " << XRegName(GetRd(insn32)) << ", ";
483*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1(insn32), Decode32Imm12(insn32));
484*795d594fSAndroid Build Coastguard Worker
485*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): If previous instruction is AUIPC for current `rs1` and we load
486*795d594fSAndroid Build Coastguard Worker // from the range specified by assembler options, print the loaded literal.
487*795d594fSAndroid Build Coastguard Worker }
488*795d594fSAndroid Build Coastguard Worker
Print32Store(uint32_t insn32)489*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Store(uint32_t insn32) {
490*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x23u);
491*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
492*795d594fSAndroid Build Coastguard Worker "sb", "sh", "sw", "sd", nullptr, nullptr, nullptr, nullptr
493*795d594fSAndroid Build Coastguard Worker };
494*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
495*795d594fSAndroid Build Coastguard Worker const char* opcode = kOpcodes[funct3];
496*795d594fSAndroid Build Coastguard Worker if (opcode == nullptr) {
497*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
498*795d594fSAndroid Build Coastguard Worker return;
499*795d594fSAndroid Build Coastguard Worker }
500*795d594fSAndroid Build Coastguard Worker
501*795d594fSAndroid Build Coastguard Worker os_ << opcode << " " << XRegName(GetRs2(insn32)) << ", ";
502*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1(insn32), Decode32StoreOffset(insn32));
503*795d594fSAndroid Build Coastguard Worker }
504*795d594fSAndroid Build Coastguard Worker
DecodeRVVMemMnemonic(const uint32_t insn32,bool is_load,const char ** rs2)505*795d594fSAndroid Build Coastguard Worker const char* DisassemblerRiscv64::Printer::DecodeRVVMemMnemonic(const uint32_t insn32,
506*795d594fSAndroid Build Coastguard Worker bool is_load,
507*795d594fSAndroid Build Coastguard Worker /*out*/ const char** rs2) {
508*795d594fSAndroid Build Coastguard Worker const uint32_t width_index = (insn32 >> 12) & 3u;
509*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(width_index != 0u, (insn32 & 0x4000u) != 0u);
510*795d594fSAndroid Build Coastguard Worker const uint32_t imm7 = Decode32UImm7(insn32);
511*795d594fSAndroid Build Coastguard Worker const enum Nf nf = static_cast<enum Nf>((imm7 >> 4) & 0x7u);
512*795d594fSAndroid Build Coastguard Worker const enum MemAddressMode mop = static_cast<enum MemAddressMode>((imm7 >> 1) & 0x3u);
513*795d594fSAndroid Build Coastguard Worker const uint32_t mew = (insn32 >> 28) & 1u;
514*795d594fSAndroid Build Coastguard Worker
515*795d594fSAndroid Build Coastguard Worker if (mew == 1u) {
516*795d594fSAndroid Build Coastguard Worker // 7.3. Vector Load/Store Width Encoding
517*795d594fSAndroid Build Coastguard Worker // The mew bit (inst[28]) when set is expected to be used to encode
518*795d594fSAndroid Build Coastguard Worker // expanded memory sizes of 128 bits and above,
519*795d594fSAndroid Build Coastguard Worker // but these encodings are currently reserved.
520*795d594fSAndroid Build Coastguard Worker return nullptr;
521*795d594fSAndroid Build Coastguard Worker }
522*795d594fSAndroid Build Coastguard Worker
523*795d594fSAndroid Build Coastguard Worker switch (mop) {
524*795d594fSAndroid Build Coastguard Worker case MemAddressMode::kUnitStride: {
525*795d594fSAndroid Build Coastguard Worker const uint32_t umop = GetRs2(insn32);
526*795d594fSAndroid Build Coastguard Worker switch (umop) {
527*795d594fSAndroid Build Coastguard Worker case 0b00000: // Vector Unit-Stride Load/Store
528*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVUSMnemonics[8][4] = {
529*795d594fSAndroid Build Coastguard Worker {"e8.v", "e16.v", "e32.v", "e64.v"},
530*795d594fSAndroid Build Coastguard Worker {"seg2e8.v", "seg2e16.v", "seg2e32.v", "seg2e64.v"},
531*795d594fSAndroid Build Coastguard Worker {"seg3e8.v", "seg3e16.v", "seg3e32.v", "seg3e64.v"},
532*795d594fSAndroid Build Coastguard Worker {"seg4e8.v", "seg4e16.v", "seg4e32.v", "seg4e64.v"},
533*795d594fSAndroid Build Coastguard Worker {"seg5e8.v", "seg5e16.v", "seg5e32.v", "seg5e64.v"},
534*795d594fSAndroid Build Coastguard Worker {"seg6e8.v", "seg6e16.v", "seg6e32.v", "seg6e64.v"},
535*795d594fSAndroid Build Coastguard Worker {"seg7e8.v", "seg7e16.v", "seg7e32.v", "seg7e64.v"},
536*795d594fSAndroid Build Coastguard Worker {"seg8e8.v", "seg8e16.v", "seg8e32.v", "seg8e64.v"},
537*795d594fSAndroid Build Coastguard Worker };
538*795d594fSAndroid Build Coastguard Worker return kVUSMnemonics[enum_cast<uint32_t>(nf)][width_index];
539*795d594fSAndroid Build Coastguard Worker case 0b01000: { // Vector Whole Register Load/Store
540*795d594fSAndroid Build Coastguard Worker if (is_load) {
541*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVWRLMnemonics[8][4] = {
542*795d594fSAndroid Build Coastguard Worker {"1re8.v", "1re16.v", "1re32.v", "1re64.v"},
543*795d594fSAndroid Build Coastguard Worker {"2re8.v", "2re16.v", "2re32.v", "2re64.v"},
544*795d594fSAndroid Build Coastguard Worker {nullptr, nullptr, nullptr, nullptr},
545*795d594fSAndroid Build Coastguard Worker {"4re8.v", "4re16.v", "4re32.v", "4re64.v"},
546*795d594fSAndroid Build Coastguard Worker {nullptr, nullptr, nullptr, nullptr},
547*795d594fSAndroid Build Coastguard Worker {nullptr, nullptr, nullptr, nullptr},
548*795d594fSAndroid Build Coastguard Worker {nullptr, nullptr, nullptr, nullptr},
549*795d594fSAndroid Build Coastguard Worker {"8re8.v", "8re16.v", "8re32.v", "8re64.v"},
550*795d594fSAndroid Build Coastguard Worker };
551*795d594fSAndroid Build Coastguard Worker return kVWRLMnemonics[enum_cast<uint32_t>(nf)][width_index];
552*795d594fSAndroid Build Coastguard Worker } else {
553*795d594fSAndroid Build Coastguard Worker if (width_index != 0) {
554*795d594fSAndroid Build Coastguard Worker return nullptr;
555*795d594fSAndroid Build Coastguard Worker }
556*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVWRSMnemonics[8] = {
557*795d594fSAndroid Build Coastguard Worker "1r", "2r", nullptr, "4r", nullptr, nullptr, nullptr, "8r"
558*795d594fSAndroid Build Coastguard Worker };
559*795d594fSAndroid Build Coastguard Worker return kVWRSMnemonics[enum_cast<uint32_t>(nf)];
560*795d594fSAndroid Build Coastguard Worker }
561*795d594fSAndroid Build Coastguard Worker }
562*795d594fSAndroid Build Coastguard Worker case 0b01011: // Vector Unit-Stride Mask Load/Store
563*795d594fSAndroid Build Coastguard Worker if (nf == Nf::k1 && width_index == 0 && (imm7 & 1u) == 1u) {
564*795d594fSAndroid Build Coastguard Worker return "m.v";
565*795d594fSAndroid Build Coastguard Worker } else {
566*795d594fSAndroid Build Coastguard Worker return nullptr;
567*795d594fSAndroid Build Coastguard Worker }
568*795d594fSAndroid Build Coastguard Worker case 0b10000: // Vector Unit-Stride Fault-Only-First Load
569*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVUSFFLMnemonics[8][4] = {
570*795d594fSAndroid Build Coastguard Worker {"e8ff.v", "e16ff.v", "e32ff.v", "e64ff.v"},
571*795d594fSAndroid Build Coastguard Worker {"seg2e8ff.v", "seg2e16ff.v", "seg2e32ff.v", "seg2e64ff.v"},
572*795d594fSAndroid Build Coastguard Worker {"seg3e8ff.v", "seg3e16ff.v", "seg3e32ff.v", "seg3e64ff.v"},
573*795d594fSAndroid Build Coastguard Worker {"seg4e8ff.v", "seg4e16ff.v", "seg4e32ff.v", "seg4e64ff.v"},
574*795d594fSAndroid Build Coastguard Worker {"seg5e8ff.v", "seg5e16ff.v", "seg5e32ff.v", "seg5e64ff.v"},
575*795d594fSAndroid Build Coastguard Worker {"seg6e8ff.v", "seg6e16ff.v", "seg6e32ff.v", "seg6e64ff.v"},
576*795d594fSAndroid Build Coastguard Worker {"seg7e8ff.v", "seg7e16ff.v", "seg7e32ff.v", "seg7e64ff.v"},
577*795d594fSAndroid Build Coastguard Worker {"seg8e8ff.v", "seg8e16ff.v", "seg8e32ff.v", "seg8e64ff.v"},
578*795d594fSAndroid Build Coastguard Worker };
579*795d594fSAndroid Build Coastguard Worker return is_load ? kVUSFFLMnemonics[enum_cast<uint32_t>(nf)][width_index] : nullptr;
580*795d594fSAndroid Build Coastguard Worker default: // Unknown
581*795d594fSAndroid Build Coastguard Worker return nullptr;
582*795d594fSAndroid Build Coastguard Worker }
583*795d594fSAndroid Build Coastguard Worker }
584*795d594fSAndroid Build Coastguard Worker case MemAddressMode::kIndexedUnordered: {
585*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVIUMnemonics[8][4] = {
586*795d594fSAndroid Build Coastguard Worker {"uxei8.v", "uxei16.v", "uxei32.v", "uxei64.v"},
587*795d594fSAndroid Build Coastguard Worker {"uxseg2ei8.v", "uxseg2ei16.v", "uxseg2ei32.v", "uxseg2ei64.v"},
588*795d594fSAndroid Build Coastguard Worker {"uxseg3ei8.v", "uxseg3ei16.v", "uxseg3ei32.v", "uxseg3ei64.v"},
589*795d594fSAndroid Build Coastguard Worker {"uxseg4ei8.v", "uxseg4ei16.v", "uxseg4ei32.v", "uxseg4ei64.v"},
590*795d594fSAndroid Build Coastguard Worker {"uxseg5ei8.v", "uxseg5ei16.v", "uxseg5ei32.v", "uxseg5ei64.v"},
591*795d594fSAndroid Build Coastguard Worker {"uxseg6ei8.v", "uxseg6ei16.v", "uxseg6ei32.v", "uxseg6ei64.v"},
592*795d594fSAndroid Build Coastguard Worker {"uxseg7ei8.v", "uxseg7ei16.v", "uxseg7ei32.v", "uxseg7ei64.v"},
593*795d594fSAndroid Build Coastguard Worker {"uxseg8ei8.v", "uxseg8ei16.v", "uxseg8ei32.v", "uxseg8ei64.v"},
594*795d594fSAndroid Build Coastguard Worker };
595*795d594fSAndroid Build Coastguard Worker *rs2 = VRegName(GetRs2(insn32));
596*795d594fSAndroid Build Coastguard Worker return kVIUMnemonics[enum_cast<uint32_t>(nf)][width_index];
597*795d594fSAndroid Build Coastguard Worker }
598*795d594fSAndroid Build Coastguard Worker case MemAddressMode::kStrided: {
599*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVSMnemonics[8][4] = {
600*795d594fSAndroid Build Coastguard Worker {"se8.v", "se16.v", "se32.v", "se64.v"},
601*795d594fSAndroid Build Coastguard Worker {"sseg2e8.v", "sseg2e16.v", "sseg2e32.v", "sseg2e64.v"},
602*795d594fSAndroid Build Coastguard Worker {"sseg3e8.v", "sseg3e16.v", "sseg3e32.v", "sseg3e64.v"},
603*795d594fSAndroid Build Coastguard Worker {"sseg4e8.v", "sseg4e16.v", "sseg4e32.v", "sseg4e64.v"},
604*795d594fSAndroid Build Coastguard Worker {"sseg5e8.v", "sseg5e16.v", "sseg5e32.v", "sseg5e64.v"},
605*795d594fSAndroid Build Coastguard Worker {"sseg6e8.v", "sseg6e16.v", "sseg6e32.v", "sseg6e64.v"},
606*795d594fSAndroid Build Coastguard Worker {"sseg7e8.v", "sseg7e16.v", "sseg7e32.v", "sseg7e64.v"},
607*795d594fSAndroid Build Coastguard Worker {"sseg8e8.v", "sseg8e16.v", "sseg8e32.v", "sseg8e64.v"},
608*795d594fSAndroid Build Coastguard Worker };
609*795d594fSAndroid Build Coastguard Worker *rs2 = XRegName(GetRs2(insn32));
610*795d594fSAndroid Build Coastguard Worker return kVSMnemonics[enum_cast<uint32_t>(nf)][width_index];
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker case MemAddressMode::kIndexedOrdered: {
613*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVIOMnemonics[8][4] = {
614*795d594fSAndroid Build Coastguard Worker {"oxei8.v", "oxei16.v", "oxei32.v", "oxei64.v"},
615*795d594fSAndroid Build Coastguard Worker {"oxseg2ei8.v", "oxseg2ei16.v", "oxseg2ei32.v", "oxseg2ei64.v"},
616*795d594fSAndroid Build Coastguard Worker {"oxseg3ei8.v", "oxseg3ei16.v", "oxseg3ei32.v", "oxseg3ei64.v"},
617*795d594fSAndroid Build Coastguard Worker {"oxseg4ei8.v", "oxseg4ei16.v", "oxseg4ei32.v", "oxseg4ei64.v"},
618*795d594fSAndroid Build Coastguard Worker {"oxseg5ei8.v", "oxseg5ei16.v", "oxseg5ei32.v", "oxseg5ei64.v"},
619*795d594fSAndroid Build Coastguard Worker {"oxseg6ei8.v", "oxseg6ei16.v", "oxseg6ei32.v", "oxseg6ei64.v"},
620*795d594fSAndroid Build Coastguard Worker {"oxseg7ei8.v", "oxseg7ei16.v", "oxseg7ei32.v", "oxseg7ei64.v"},
621*795d594fSAndroid Build Coastguard Worker {"oxseg8ei8.v", "oxseg8ei16.v", "oxseg8ei32.v", "oxseg8ei64.v"},
622*795d594fSAndroid Build Coastguard Worker };
623*795d594fSAndroid Build Coastguard Worker *rs2 = VRegName(GetRs2(insn32));
624*795d594fSAndroid Build Coastguard Worker return kVIOMnemonics[enum_cast<uint32_t>(nf)][width_index];
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker }
627*795d594fSAndroid Build Coastguard Worker }
628*795d594fSAndroid Build Coastguard Worker
629*795d594fSAndroid Build Coastguard Worker static constexpr const char* kFpMemMnemonics[] = {
630*795d594fSAndroid Build Coastguard Worker nullptr, "h", "w", "d", "q", nullptr, nullptr, nullptr
631*795d594fSAndroid Build Coastguard Worker };
632*795d594fSAndroid Build Coastguard Worker
Print32FLoad(uint32_t insn32)633*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32FLoad(uint32_t insn32) {
634*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x07u);
635*795d594fSAndroid Build Coastguard Worker int32_t offset = 0;
636*795d594fSAndroid Build Coastguard Worker const char* rd = nullptr;
637*795d594fSAndroid Build Coastguard Worker const char* rs2 = nullptr;
638*795d594fSAndroid Build Coastguard Worker const char* vm = "";
639*795d594fSAndroid Build Coastguard Worker const uint32_t funct3 = (insn32 >> 12) & 7u;
640*795d594fSAndroid Build Coastguard Worker const char* mnemonic = kFpMemMnemonics[funct3];
641*795d594fSAndroid Build Coastguard Worker const char* prefix = "f";
642*795d594fSAndroid Build Coastguard Worker if (mnemonic == nullptr) {
643*795d594fSAndroid Build Coastguard Worker // Vector Loads
644*795d594fSAndroid Build Coastguard Worker prefix = "v";
645*795d594fSAndroid Build Coastguard Worker mnemonic = DecodeRVVMemMnemonic(insn32, /*is_load=*/true, &rs2);
646*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
647*795d594fSAndroid Build Coastguard Worker
648*795d594fSAndroid Build Coastguard Worker if ((Decode32UImm7(insn32) & 0x1U) == 0) {
649*795d594fSAndroid Build Coastguard Worker vm = ", v0.t";
650*795d594fSAndroid Build Coastguard Worker }
651*795d594fSAndroid Build Coastguard Worker } else {
652*795d594fSAndroid Build Coastguard Worker rd = FRegName(GetRd(insn32));
653*795d594fSAndroid Build Coastguard Worker offset = Decode32Imm12(insn32);
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker
656*795d594fSAndroid Build Coastguard Worker if (mnemonic == nullptr) {
657*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
658*795d594fSAndroid Build Coastguard Worker return;
659*795d594fSAndroid Build Coastguard Worker }
660*795d594fSAndroid Build Coastguard Worker
661*795d594fSAndroid Build Coastguard Worker os_ << prefix << "l" << mnemonic << " " << rd << ", ";
662*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1(insn32), offset);
663*795d594fSAndroid Build Coastguard Worker
664*795d594fSAndroid Build Coastguard Worker if (rs2) {
665*795d594fSAndroid Build Coastguard Worker os_ << ", " << rs2;
666*795d594fSAndroid Build Coastguard Worker }
667*795d594fSAndroid Build Coastguard Worker
668*795d594fSAndroid Build Coastguard Worker os_ << vm;
669*795d594fSAndroid Build Coastguard Worker
670*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): If previous instruction is AUIPC for current `rs1` and we load
671*795d594fSAndroid Build Coastguard Worker // from the range specified by assembler options, print the loaded literal.
672*795d594fSAndroid Build Coastguard Worker }
673*795d594fSAndroid Build Coastguard Worker
Print32FStore(uint32_t insn32)674*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32FStore(uint32_t insn32) {
675*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x27u);
676*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 3u;
677*795d594fSAndroid Build Coastguard Worker const char* prefix = "f";
678*795d594fSAndroid Build Coastguard Worker const char* mnemonic = kFpMemMnemonics[funct3];
679*795d594fSAndroid Build Coastguard Worker
680*795d594fSAndroid Build Coastguard Worker if (mnemonic == nullptr) {
681*795d594fSAndroid Build Coastguard Worker // Vector Stores
682*795d594fSAndroid Build Coastguard Worker const char* rs2 = nullptr;
683*795d594fSAndroid Build Coastguard Worker prefix = "v";
684*795d594fSAndroid Build Coastguard Worker mnemonic = DecodeRVVMemMnemonic(insn32, /*is_load=*/false, &rs2);
685*795d594fSAndroid Build Coastguard Worker
686*795d594fSAndroid Build Coastguard Worker if (mnemonic == nullptr) {
687*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
688*795d594fSAndroid Build Coastguard Worker return;
689*795d594fSAndroid Build Coastguard Worker }
690*795d594fSAndroid Build Coastguard Worker
691*795d594fSAndroid Build Coastguard Worker os_ << prefix << "s" << mnemonic << " " << VRegName(GetRd(insn32)) << ", ";
692*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1(insn32), 0);
693*795d594fSAndroid Build Coastguard Worker
694*795d594fSAndroid Build Coastguard Worker if (rs2) {
695*795d594fSAndroid Build Coastguard Worker os_ << ", " << rs2;
696*795d594fSAndroid Build Coastguard Worker }
697*795d594fSAndroid Build Coastguard Worker
698*795d594fSAndroid Build Coastguard Worker if ((Decode32UImm7(insn32) & 0x1U) == 0) {
699*795d594fSAndroid Build Coastguard Worker os_ << ", v0.t";
700*795d594fSAndroid Build Coastguard Worker }
701*795d594fSAndroid Build Coastguard Worker } else {
702*795d594fSAndroid Build Coastguard Worker os_ << prefix << "s" << mnemonic << " " << FRegName(GetRs2(insn32)) << ", ";
703*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1(insn32), Decode32StoreOffset(insn32));
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker }
706*795d594fSAndroid Build Coastguard Worker
Print32BinOpImm(uint32_t insn32)707*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32BinOpImm(uint32_t insn32) {
708*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x77u, 0x13u); // Note: Bit 0x8 selects narrow binop.
709*795d594fSAndroid Build Coastguard Worker bool narrow = (insn32 & 0x8u) != 0u;
710*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
711*795d594fSAndroid Build Coastguard Worker uint32_t funct6 = (insn32 >> 26) & 0x3Fu;
712*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
713*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
714*795d594fSAndroid Build Coastguard Worker int32_t imm = Decode32Imm12(insn32);
715*795d594fSAndroid Build Coastguard Worker
716*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
717*795d594fSAndroid Build Coastguard Worker if (funct3 == /*ADDI*/ 0u && imm == 0u) {
718*795d594fSAndroid Build Coastguard Worker if (narrow) {
719*795d594fSAndroid Build Coastguard Worker os_ << "sextw " << XRegName(rd) << ", " << XRegName(rs1);
720*795d594fSAndroid Build Coastguard Worker } else if (rd == Zero && rs1 == Zero) {
721*795d594fSAndroid Build Coastguard Worker os_ << "nop"; // Only canonical nop. Non-Zero `rd == rs1` nops are printed as "mv".
722*795d594fSAndroid Build Coastguard Worker } else {
723*795d594fSAndroid Build Coastguard Worker os_ << "mv " << XRegName(rd) << ", " << XRegName(rs1);
724*795d594fSAndroid Build Coastguard Worker }
725*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*XORI*/ 4u && imm == -1) {
726*795d594fSAndroid Build Coastguard Worker os_ << "not " << XRegName(rd) << ", " << XRegName(rs1);
727*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*ANDI*/ 7u && imm == 0xff) {
728*795d594fSAndroid Build Coastguard Worker os_ << "zextb " << XRegName(rd) << ", " << XRegName(rs1);
729*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*SLTIU*/ 3u && imm == 1) {
730*795d594fSAndroid Build Coastguard Worker os_ << "seqz " << XRegName(rd) << ", " << XRegName(rs1);
731*795d594fSAndroid Build Coastguard Worker } else if ((insn32 & 0xfc00707fu) == 0x0800101bu) {
732*795d594fSAndroid Build Coastguard Worker os_ << "slli.uw " << XRegName(rd) << ", " << XRegName(rs1) << ", " << (imm & 0x3fu);
733*795d594fSAndroid Build Coastguard Worker } else if ((imm ^ 0x600u) < 3u && funct3 == 1u) {
734*795d594fSAndroid Build Coastguard Worker static const char* const kBitOpcodes[] = { "clz", "ctz", "cpop" };
735*795d594fSAndroid Build Coastguard Worker os_ << kBitOpcodes[imm ^ 0x600u] << (narrow ? "w " : " ")
736*795d594fSAndroid Build Coastguard Worker << XRegName(rd) << ", " << XRegName(rs1);
737*795d594fSAndroid Build Coastguard Worker } else if ((imm ^ 0x600u) < (narrow ? 32 : 64) && funct3 == 5u) {
738*795d594fSAndroid Build Coastguard Worker os_ << "rori" << (narrow ? "w " : " ")
739*795d594fSAndroid Build Coastguard Worker << XRegName(rd) << ", " << XRegName(rs1) << ", " << (imm ^ 0x600u);
740*795d594fSAndroid Build Coastguard Worker } else if (imm == 0x287u && !narrow && funct3 == 5u) {
741*795d594fSAndroid Build Coastguard Worker os_ << "orc.b " << XRegName(rd) << ", " << XRegName(rs1);
742*795d594fSAndroid Build Coastguard Worker } else if (imm == 0x6b8u && !narrow && funct3 == 5u) {
743*795d594fSAndroid Build Coastguard Worker os_ << "rev8 " << XRegName(rd) << ", " << XRegName(rs1);
744*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct6 == 0x12u && (funct3 == /*BCLRI*/ 1u || funct3 == /*BEXTI*/ 5u)) {
745*795d594fSAndroid Build Coastguard Worker os_ << ((funct3 == /*BCLRI*/ 1u) ? "bclri" : "bexti");
746*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct6 == 0x1Au && funct3 == 0x1u /*BINVI*/) {
747*795d594fSAndroid Build Coastguard Worker os_ << "binvi";
748*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct6 == 0xAu && funct3 == 0x1u /*BSETI*/) {
749*795d594fSAndroid Build Coastguard Worker os_ << "bseti";
750*795d594fSAndroid Build Coastguard Worker } else {
751*795d594fSAndroid Build Coastguard Worker bool bad_high_bits = false;
752*795d594fSAndroid Build Coastguard Worker if (funct3 == /*SLLI*/ 1u || funct3 == /*SRLI/SRAI*/ 5u) {
753*795d594fSAndroid Build Coastguard Worker imm &= (narrow ? 0x1fu : 0x3fu);
754*795d594fSAndroid Build Coastguard Worker uint32_t high_bits = insn32 & (narrow ? 0xfe000000u : 0xfc000000u);
755*795d594fSAndroid Build Coastguard Worker if (high_bits == 0x40000000u && funct3 == /*SRAI*/ 5u) {
756*795d594fSAndroid Build Coastguard Worker os_ << "srai";
757*795d594fSAndroid Build Coastguard Worker } else {
758*795d594fSAndroid Build Coastguard Worker os_ << ((funct3 == /*SRLI*/ 5u) ? "srli" : "slli");
759*795d594fSAndroid Build Coastguard Worker bad_high_bits = (high_bits != 0u);
760*795d594fSAndroid Build Coastguard Worker }
761*795d594fSAndroid Build Coastguard Worker } else if (!narrow || funct3 == /*ADDI*/ 0u) {
762*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
763*795d594fSAndroid Build Coastguard Worker "addi", nullptr, "slti", "sltiu", "xori", nullptr, "ori", "andi"
764*795d594fSAndroid Build Coastguard Worker };
765*795d594fSAndroid Build Coastguard Worker DCHECK(kOpcodes[funct3] != nullptr);
766*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[funct3];
767*795d594fSAndroid Build Coastguard Worker } else {
768*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>"; // There is no SLTIW/SLTIUW/XORIW/ORIW/ANDIW.
769*795d594fSAndroid Build Coastguard Worker return;
770*795d594fSAndroid Build Coastguard Worker }
771*795d594fSAndroid Build Coastguard Worker os_ << (narrow ? "w " : " ") << XRegName(rd) << ", " << XRegName(rs1) << ", " << imm;
772*795d594fSAndroid Build Coastguard Worker if (bad_high_bits) {
773*795d594fSAndroid Build Coastguard Worker os_ << " (invalid high bits)";
774*795d594fSAndroid Build Coastguard Worker }
775*795d594fSAndroid Build Coastguard Worker }
776*795d594fSAndroid Build Coastguard Worker }
777*795d594fSAndroid Build Coastguard Worker
Print32BinOp(uint32_t insn32)778*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32BinOp(uint32_t insn32) {
779*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x77u, 0x33u); // Note: Bit 0x8 selects narrow binop.
780*795d594fSAndroid Build Coastguard Worker bool narrow = (insn32 & 0x8u) != 0u;
781*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
782*795d594fSAndroid Build Coastguard Worker uint32_t funct7 = (insn32 >> 25) & 0x7Fu;
783*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
784*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
785*795d594fSAndroid Build Coastguard Worker uint32_t rs2 = GetRs2(insn32);
786*795d594fSAndroid Build Coastguard Worker
787*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
788*795d594fSAndroid Build Coastguard Worker if (funct7 == 0x20u && funct3 == /*SUB*/ 0u && rs1 == Zero) {
789*795d594fSAndroid Build Coastguard Worker os_ << (narrow ? "negw " : "neg ") << XRegName(rd) << ", " << XRegName(rs2);
790*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*SLT*/ 2u && rs2 == Zero) {
791*795d594fSAndroid Build Coastguard Worker os_ << "sltz " << XRegName(rd) << ", " << XRegName(rs1);
792*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*SLT*/ 2u && rs1 == Zero) {
793*795d594fSAndroid Build Coastguard Worker os_ << "sgtz " << XRegName(rd) << ", " << XRegName(rs2);
794*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct3 == /*SLTU*/ 3u && rs1 == Zero) {
795*795d594fSAndroid Build Coastguard Worker os_ << "snez " << XRegName(rd) << ", " << XRegName(rs2);
796*795d594fSAndroid Build Coastguard Worker } else if (narrow && funct7 == 4u && funct3 == /*ADD.UW*/ 0u && rs2 == Zero) {
797*795d594fSAndroid Build Coastguard Worker os_ << "zext.w " << XRegName(rd) << ", " << XRegName(rs1);
798*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct7 == 0x24u &&
799*795d594fSAndroid Build Coastguard Worker (funct3 == /*BCLR*/ 1u || funct3 == /*BEXT*/ 5u)) {
800*795d594fSAndroid Build Coastguard Worker os_ << ((funct3 == /*BCLR*/ 1u) ? "bclr" : "bext");
801*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct7 == 0x34u && funct3 == /*BINV*/ 1u) {
802*795d594fSAndroid Build Coastguard Worker os_ << "binv";
803*795d594fSAndroid Build Coastguard Worker } else if (!narrow && funct7 == 0x14u && funct3 == /*BSET*/ 1u) {
804*795d594fSAndroid Build Coastguard Worker os_ << "bset";
805*795d594fSAndroid Build Coastguard Worker } else {
806*795d594fSAndroid Build Coastguard Worker bool bad_high_bits = false;
807*795d594fSAndroid Build Coastguard Worker if (funct7 == 0x20u && (funct3 == /*SUB*/ 0u || funct3 == /*SRA*/ 5u)) {
808*795d594fSAndroid Build Coastguard Worker os_ << ((funct3 == /*SUB*/ 0u) ? "sub" : "sra");
809*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 1u &&
810*795d594fSAndroid Build Coastguard Worker (!narrow || (funct3 == /*MUL*/ 0u || funct3 >= /*DIV/DIVU/REM/REMU*/ 4u))) {
811*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
812*795d594fSAndroid Build Coastguard Worker "mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"
813*795d594fSAndroid Build Coastguard Worker };
814*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[funct3];
815*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 4u && narrow && funct3 == /*ADD.UW*/ 0u) {
816*795d594fSAndroid Build Coastguard Worker os_ << "add.u"; // "w" is added below.
817*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 0x10u && (funct3 & 1u) == 0u && funct3 != 0u) {
818*795d594fSAndroid Build Coastguard Worker static const char* const kZbaOpcodes[] = { nullptr, "sh1add", "sh2add", "sh3add" };
819*795d594fSAndroid Build Coastguard Worker DCHECK(kZbaOpcodes[funct3 >> 1] != nullptr);
820*795d594fSAndroid Build Coastguard Worker os_ << kZbaOpcodes[funct3 >> 1] << (narrow ? ".u" /* "w" is added below. */ : "");
821*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 0x20u && !narrow && funct3 >= 4u && funct3 != 5u) {
822*795d594fSAndroid Build Coastguard Worker static const char* const kZbbNegOpcodes[] = { "xnor", nullptr, "orn", "andn" };
823*795d594fSAndroid Build Coastguard Worker DCHECK(kZbbNegOpcodes[funct3 - 4u] != nullptr);
824*795d594fSAndroid Build Coastguard Worker os_ << kZbbNegOpcodes[funct3 - 4u];
825*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 0x5u && !narrow && funct3 >= 4u) {
826*795d594fSAndroid Build Coastguard Worker static const char* const kZbbMinMaxOpcodes[] = { "min", "minu", "max", "maxu" };
827*795d594fSAndroid Build Coastguard Worker DCHECK(kZbbMinMaxOpcodes[funct3 - 4u] != nullptr);
828*795d594fSAndroid Build Coastguard Worker os_ << kZbbMinMaxOpcodes[funct3 - 4u];
829*795d594fSAndroid Build Coastguard Worker } else if (funct7 == 0x30u && (funct3 == /*ROL*/ 1u || funct3 == /*ROL*/ 5u)) {
830*795d594fSAndroid Build Coastguard Worker os_ << (funct3 == /*ROL*/ 1u ? "rol" : "ror");
831*795d594fSAndroid Build Coastguard Worker } else if (!narrow || (funct3 == /*ADD*/ 0u || funct3 == /*SLL*/ 1u || funct3 == /*SRL*/ 5u)) {
832*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
833*795d594fSAndroid Build Coastguard Worker "add", "sll", "slt", "sltu", "xor", "srl", "or", "and"
834*795d594fSAndroid Build Coastguard Worker };
835*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[funct3];
836*795d594fSAndroid Build Coastguard Worker bad_high_bits = funct7 != 0u;
837*795d594fSAndroid Build Coastguard Worker } else {
838*795d594fSAndroid Build Coastguard Worker DCHECK(narrow);
839*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>"; // Some of the above instructions do not have a narrow version.
840*795d594fSAndroid Build Coastguard Worker return;
841*795d594fSAndroid Build Coastguard Worker }
842*795d594fSAndroid Build Coastguard Worker os_ << (narrow ? "w " : " ") << XRegName(rd) << ", " << XRegName(rs1) << ", " << XRegName(rs2);
843*795d594fSAndroid Build Coastguard Worker if (bad_high_bits) {
844*795d594fSAndroid Build Coastguard Worker os_ << " (invalid high bits)";
845*795d594fSAndroid Build Coastguard Worker }
846*795d594fSAndroid Build Coastguard Worker }
847*795d594fSAndroid Build Coastguard Worker }
848*795d594fSAndroid Build Coastguard Worker
Print32Atomic(uint32_t insn32)849*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Atomic(uint32_t insn32) {
850*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x2fu);
851*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
852*795d594fSAndroid Build Coastguard Worker uint32_t funct5 = (insn32 >> 27);
853*795d594fSAndroid Build Coastguard Worker if ((funct3 != 2u && funct3 != 3u) || // There are only 32-bit and 64-bit LR/SC/AMO*.
854*795d594fSAndroid Build Coastguard Worker (((funct5 & 3u) != 0u) && funct5 >= 4u)) { // Only multiples of 4, or 1-3.
855*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
856*795d594fSAndroid Build Coastguard Worker return;
857*795d594fSAndroid Build Coastguard Worker }
858*795d594fSAndroid Build Coastguard Worker static const char* const kMul4Opcodes[] = {
859*795d594fSAndroid Build Coastguard Worker "amoadd", "amoxor", "amoor", "amoand", "amomin", "amomax", "amominu", "amomaxu"
860*795d594fSAndroid Build Coastguard Worker };
861*795d594fSAndroid Build Coastguard Worker static const char* const kOtherOpcodes[] = {
862*795d594fSAndroid Build Coastguard Worker nullptr, "amoswap", "lr", "sc"
863*795d594fSAndroid Build Coastguard Worker };
864*795d594fSAndroid Build Coastguard Worker const char* opcode = ((funct5 & 3u) == 0u) ? kMul4Opcodes[funct5 >> 2] : kOtherOpcodes[funct5];
865*795d594fSAndroid Build Coastguard Worker DCHECK(opcode != nullptr);
866*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
867*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
868*795d594fSAndroid Build Coastguard Worker uint32_t rs2 = GetRs2(insn32);
869*795d594fSAndroid Build Coastguard Worker const char* type = (funct3 == 2u) ? ".w" : ".d";
870*795d594fSAndroid Build Coastguard Worker const char* aq = (((insn32 >> 26) & 1u) != 0u) ? ".aq" : "";
871*795d594fSAndroid Build Coastguard Worker const char* rl = (((insn32 >> 25) & 1u) != 0u) ? ".rl" : "";
872*795d594fSAndroid Build Coastguard Worker os_ << opcode << type << aq << rl << " " << XRegName(rd) << ", " << XRegName(rs1);
873*795d594fSAndroid Build Coastguard Worker if (funct5 == /*LR*/ 2u) {
874*795d594fSAndroid Build Coastguard Worker if (rs2 != 0u) {
875*795d594fSAndroid Build Coastguard Worker os_ << " (bad rs2)";
876*795d594fSAndroid Build Coastguard Worker }
877*795d594fSAndroid Build Coastguard Worker } else {
878*795d594fSAndroid Build Coastguard Worker os_ << ", " << XRegName(rs2);
879*795d594fSAndroid Build Coastguard Worker }
880*795d594fSAndroid Build Coastguard Worker }
881*795d594fSAndroid Build Coastguard Worker
Print32FpOp(uint32_t insn32)882*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32FpOp(uint32_t insn32) {
883*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x53u);
884*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
885*795d594fSAndroid Build Coastguard Worker uint32_t rs1 = GetRs1(insn32);
886*795d594fSAndroid Build Coastguard Worker uint32_t rs2 = GetRs2(insn32); // Sometimes used to to differentiate opcodes.
887*795d594fSAndroid Build Coastguard Worker uint32_t rm = GetRoundingMode(insn32); // Sometimes used to to differentiate opcodes.
888*795d594fSAndroid Build Coastguard Worker uint32_t funct7 = insn32 >> 25;
889*795d594fSAndroid Build Coastguard Worker const char* type = ((funct7 & 1u) != 0u) ? ".d" : ".s";
890*795d594fSAndroid Build Coastguard Worker if ((funct7 & 2u) != 0u) {
891*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>"; // Note: This includes the "H" and "Q" extensions.
892*795d594fSAndroid Build Coastguard Worker return;
893*795d594fSAndroid Build Coastguard Worker }
894*795d594fSAndroid Build Coastguard Worker switch (funct7 >> 2) {
895*795d594fSAndroid Build Coastguard Worker case 0u:
896*795d594fSAndroid Build Coastguard Worker case 1u:
897*795d594fSAndroid Build Coastguard Worker case 2u:
898*795d594fSAndroid Build Coastguard Worker case 3u: {
899*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = { "fadd", "fsub", "fmul", "fdiv" };
900*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[funct7 >> 2] << type << RoundingModeName(rm) << " "
901*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << FRegName(rs1) << ", " << FRegName(rs2);
902*795d594fSAndroid Build Coastguard Worker return;
903*795d594fSAndroid Build Coastguard Worker }
904*795d594fSAndroid Build Coastguard Worker case 4u: { // FSGN*
905*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
906*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = { "fsgnj", "fsgnjn", "fsgnjx" };
907*795d594fSAndroid Build Coastguard Worker if (rm < std::size(kOpcodes)) {
908*795d594fSAndroid Build Coastguard Worker if (rs1 == rs2) {
909*795d594fSAndroid Build Coastguard Worker static const char* const kAltOpcodes[] = { "fmv", "fneg", "fabs" };
910*795d594fSAndroid Build Coastguard Worker static_assert(std::size(kOpcodes) == std::size(kAltOpcodes));
911*795d594fSAndroid Build Coastguard Worker os_ << kAltOpcodes[rm] << type << " " << FRegName(rd) << ", " << FRegName(rs1);
912*795d594fSAndroid Build Coastguard Worker } else {
913*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[rm] << type << " "
914*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << FRegName(rs1) << ", " << FRegName(rs2);
915*795d594fSAndroid Build Coastguard Worker }
916*795d594fSAndroid Build Coastguard Worker return;
917*795d594fSAndroid Build Coastguard Worker }
918*795d594fSAndroid Build Coastguard Worker break;
919*795d594fSAndroid Build Coastguard Worker }
920*795d594fSAndroid Build Coastguard Worker case 5u: { // FMIN/FMAX
921*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = { "fmin", "fmax" };
922*795d594fSAndroid Build Coastguard Worker if (rm < std::size(kOpcodes)) {
923*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[rm] << type << " "
924*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << FRegName(rs1) << ", " << FRegName(rs2);
925*795d594fSAndroid Build Coastguard Worker return;
926*795d594fSAndroid Build Coastguard Worker }
927*795d594fSAndroid Build Coastguard Worker break;
928*795d594fSAndroid Build Coastguard Worker }
929*795d594fSAndroid Build Coastguard Worker case 0x8u: // FCVT between FP numbers.
930*795d594fSAndroid Build Coastguard Worker if ((rs2 ^ 1u) == (funct7 & 1u)) {
931*795d594fSAndroid Build Coastguard Worker os_ << ((rs2 != 0u) ? "fcvt.s.d" : "fcvt.d.s") << RoundingModeName(rm) << " "
932*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << FRegName(rs1);
933*795d594fSAndroid Build Coastguard Worker }
934*795d594fSAndroid Build Coastguard Worker break;
935*795d594fSAndroid Build Coastguard Worker case 0xbu:
936*795d594fSAndroid Build Coastguard Worker if (rs2 == 0u) {
937*795d594fSAndroid Build Coastguard Worker os_ << "fsqrt" << type << RoundingModeName(rm) << " "
938*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << FRegName(rs1);
939*795d594fSAndroid Build Coastguard Worker return;
940*795d594fSAndroid Build Coastguard Worker }
941*795d594fSAndroid Build Coastguard Worker break;
942*795d594fSAndroid Build Coastguard Worker case 0x14u: { // FLE/FLT/FEQ
943*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = { "fle", "flt", "feq" };
944*795d594fSAndroid Build Coastguard Worker if (rm < std::size(kOpcodes)) {
945*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[rm] << type << " "
946*795d594fSAndroid Build Coastguard Worker << XRegName(rd) << ", " << FRegName(rs1) << ", " << FRegName(rs2);
947*795d594fSAndroid Build Coastguard Worker return;
948*795d594fSAndroid Build Coastguard Worker }
949*795d594fSAndroid Build Coastguard Worker break;
950*795d594fSAndroid Build Coastguard Worker }
951*795d594fSAndroid Build Coastguard Worker case 0x18u: { // FCVT from floating point numbers to integers
952*795d594fSAndroid Build Coastguard Worker static const char* const kIntTypes[] = { "w", "wu", "l", "lu" };
953*795d594fSAndroid Build Coastguard Worker if (rs2 < std::size(kIntTypes)) {
954*795d594fSAndroid Build Coastguard Worker os_ << "fcvt." << kIntTypes[rs2] << type << RoundingModeName(rm) << " "
955*795d594fSAndroid Build Coastguard Worker << XRegName(rd) << ", " << FRegName(rs1);
956*795d594fSAndroid Build Coastguard Worker return;
957*795d594fSAndroid Build Coastguard Worker }
958*795d594fSAndroid Build Coastguard Worker break;
959*795d594fSAndroid Build Coastguard Worker }
960*795d594fSAndroid Build Coastguard Worker case 0x1au: { // FCVT from integers to floating point numbers
961*795d594fSAndroid Build Coastguard Worker static const char* const kIntTypes[] = { "w", "wu", "l", "lu" };
962*795d594fSAndroid Build Coastguard Worker if (rs2 < std::size(kIntTypes)) {
963*795d594fSAndroid Build Coastguard Worker os_ << "fcvt" << type << "." << kIntTypes[rs2] << RoundingModeName(rm) << " "
964*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << XRegName(rs1);
965*795d594fSAndroid Build Coastguard Worker return;
966*795d594fSAndroid Build Coastguard Worker }
967*795d594fSAndroid Build Coastguard Worker break;
968*795d594fSAndroid Build Coastguard Worker }
969*795d594fSAndroid Build Coastguard Worker case 0x1cu: // FMV from FPR to GPR, or FCLASS
970*795d594fSAndroid Build Coastguard Worker if (rs2 == 0u && rm == 0u) {
971*795d594fSAndroid Build Coastguard Worker os_ << (((funct7 & 1u) != 0u) ? "fmv.x.d " : "fmv.x.w ")
972*795d594fSAndroid Build Coastguard Worker << XRegName(rd) << ", " << FRegName(rs1);
973*795d594fSAndroid Build Coastguard Worker return;
974*795d594fSAndroid Build Coastguard Worker } else if (rs2 == 0u && rm == 1u) {
975*795d594fSAndroid Build Coastguard Worker os_ << "fclass" << type << " " << XRegName(rd) << ", " << FRegName(rs1);
976*795d594fSAndroid Build Coastguard Worker return;
977*795d594fSAndroid Build Coastguard Worker }
978*795d594fSAndroid Build Coastguard Worker break;
979*795d594fSAndroid Build Coastguard Worker case 0x1eu: // FMV from GPR to FPR
980*795d594fSAndroid Build Coastguard Worker if (rs2 == 0u && rm == 0u) {
981*795d594fSAndroid Build Coastguard Worker os_ << (((funct7 & 1u) != 0u) ? "fmv.d.x " : "fmv.w.x ")
982*795d594fSAndroid Build Coastguard Worker << FRegName(rd) << ", " << XRegName(rs1);
983*795d594fSAndroid Build Coastguard Worker return;
984*795d594fSAndroid Build Coastguard Worker }
985*795d594fSAndroid Build Coastguard Worker break;
986*795d594fSAndroid Build Coastguard Worker default:
987*795d594fSAndroid Build Coastguard Worker break;
988*795d594fSAndroid Build Coastguard Worker }
989*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
990*795d594fSAndroid Build Coastguard Worker }
991*795d594fSAndroid Build Coastguard Worker
AppendVType(uint32_t vtype)992*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::AppendVType(uint32_t vtype) {
993*795d594fSAndroid Build Coastguard Worker const uint32_t lmul_v = vtype & 0x7U;
994*795d594fSAndroid Build Coastguard Worker const uint32_t vsew_v = (vtype >> 3) & 0x7U;
995*795d594fSAndroid Build Coastguard Worker const uint32_t vta_v = (vtype >> 6) & 0x1U;
996*795d594fSAndroid Build Coastguard Worker const uint32_t vma_v = (vtype >> 7) & 0x1U;
997*795d594fSAndroid Build Coastguard Worker
998*795d594fSAndroid Build Coastguard Worker if ((vsew_v & 0x4U) == 0u) {
999*795d594fSAndroid Build Coastguard Worker if (lmul_v != 0b100) {
1000*795d594fSAndroid Build Coastguard Worker static const char* const vsews[] = {"e8", "e16", "e32", "e64"};
1001*795d594fSAndroid Build Coastguard Worker static const char* const lmuls[] = {
1002*795d594fSAndroid Build Coastguard Worker "m1", "m2", "m4", "m8", nullptr, "mf8", "mf4", "mf2"
1003*795d594fSAndroid Build Coastguard Worker };
1004*795d594fSAndroid Build Coastguard Worker
1005*795d594fSAndroid Build Coastguard Worker const char* vma = vma_v ? "ma" : "mu";
1006*795d594fSAndroid Build Coastguard Worker const char* vta = vta_v ? "ta" : "tu";
1007*795d594fSAndroid Build Coastguard Worker const char* vsew = vsews[vsew_v & 0x3u];
1008*795d594fSAndroid Build Coastguard Worker const char* lmul = lmuls[lmul_v];
1009*795d594fSAndroid Build Coastguard Worker
1010*795d594fSAndroid Build Coastguard Worker os_ << vsew << ", " << lmul << ", " << vta << ", " << vma;
1011*795d594fSAndroid Build Coastguard Worker return;
1012*795d594fSAndroid Build Coastguard Worker }
1013*795d594fSAndroid Build Coastguard Worker }
1014*795d594fSAndroid Build Coastguard Worker
1015*795d594fSAndroid Build Coastguard Worker os_ << StringPrintf("0x%08x", vtype) << "\t# incorrect VType literal";
1016*795d594fSAndroid Build Coastguard Worker }
1017*795d594fSAndroid Build Coastguard Worker
1018*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VWXUNARY0 = 0b010000;
1019*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VRXUNARY0 = 0b010000;
1020*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VXUNARY0 = 0b010010;
1021*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VMUNARY0 = 0b010100;
1022*795d594fSAndroid Build Coastguard Worker
1023*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VWFUNARY0 = 0b010000;
1024*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VRFUNARY0 = 0b010000;
1025*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VFUNARY0 = 0b010010;
1026*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t VFUNARY1 = 0b010011;
1027*795d594fSAndroid Build Coastguard Worker
MaybeSwapOperands(uint32_t funct6,const char * & rs1,const char * & rs2)1028*795d594fSAndroid Build Coastguard Worker static void MaybeSwapOperands(uint32_t funct6,
1029*795d594fSAndroid Build Coastguard Worker /*inout*/ const char*& rs1,
1030*795d594fSAndroid Build Coastguard Worker /*inout*/ const char*& rs2) {
1031*795d594fSAndroid Build Coastguard Worker if ((0x28u <= funct6 && funct6 < 0x30u) || funct6 >= 0x3Cu) {
1032*795d594fSAndroid Build Coastguard Worker std::swap(rs1, rs2);
1033*795d594fSAndroid Build Coastguard Worker }
1034*795d594fSAndroid Build Coastguard Worker }
1035*795d594fSAndroid Build Coastguard Worker
Print32RVVOp(uint32_t insn32)1036*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32RVVOp(uint32_t insn32) {
1037*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Print pseudo-instruction aliases when applicable.
1038*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x57u);
1039*795d594fSAndroid Build Coastguard Worker const enum VAIEncodings vai = static_cast<enum VAIEncodings>((insn32 >> 12) & 7u);
1040*795d594fSAndroid Build Coastguard Worker const uint32_t funct7 = Decode32UImm7(insn32);
1041*795d594fSAndroid Build Coastguard Worker const uint32_t funct6 = funct7 >> 1;
1042*795d594fSAndroid Build Coastguard Worker const bool masked = (funct7 & 1) == 0;
1043*795d594fSAndroid Build Coastguard Worker const char* vm = masked ? ", v0.t" : "";
1044*795d594fSAndroid Build Coastguard Worker const char* opcode = nullptr;
1045*795d594fSAndroid Build Coastguard Worker const char* rd = nullptr;
1046*795d594fSAndroid Build Coastguard Worker const char* rs1 = nullptr;
1047*795d594fSAndroid Build Coastguard Worker const char* rs2 = nullptr;
1048*795d594fSAndroid Build Coastguard Worker
1049*795d594fSAndroid Build Coastguard Worker switch (vai) {
1050*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpIVV: {
1051*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPIVVOpcodes[64] = {
1052*795d594fSAndroid Build Coastguard Worker "vadd.vv", nullptr, "vsub.vv", nullptr,
1053*795d594fSAndroid Build Coastguard Worker "vminu.vv", "vmin.vv", "vmaxu.vv", "vmax.vv",
1054*795d594fSAndroid Build Coastguard Worker nullptr, "vand.vv", "vor.vv", "vxor.vv",
1055*795d594fSAndroid Build Coastguard Worker "vrgather.vv", nullptr, "vrgatherei16.vv", nullptr,
1056*795d594fSAndroid Build Coastguard Worker "vadc.vvm", "vmadc.vvm", "vsbc.vvm", "vmsbc.vvm",
1057*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, "<vmerge/vmv>",
1058*795d594fSAndroid Build Coastguard Worker "vmseq.vv", "vmsne.vv", "vmsltu.vv", "vmslt.vv",
1059*795d594fSAndroid Build Coastguard Worker "vmsleu.vv", "vmsle.vv", nullptr, nullptr,
1060*795d594fSAndroid Build Coastguard Worker "vsaddu.vv", "vsadd.vv", "vssubu.vv", "vssub.vv",
1061*795d594fSAndroid Build Coastguard Worker nullptr, "vsll.vv", nullptr, "vsmul.vv",
1062*795d594fSAndroid Build Coastguard Worker "vsrl.vv", "vsra.vv", "vssrl.vv", "vssra.vv",
1063*795d594fSAndroid Build Coastguard Worker "vnsrl.wv", "vnsra.wv", "vnclipu.wv", "vnclip.wv",
1064*795d594fSAndroid Build Coastguard Worker "vwredsumu.vs", "vwredsum.vs", nullptr, nullptr,
1065*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1066*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1067*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1068*795d594fSAndroid Build Coastguard Worker };
1069*795d594fSAndroid Build Coastguard Worker
1070*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1071*795d594fSAndroid Build Coastguard Worker if (funct6 == 0b010111) {
1072*795d594fSAndroid Build Coastguard Worker // vmerge/vmv
1073*795d594fSAndroid Build Coastguard Worker if (masked) {
1074*795d594fSAndroid Build Coastguard Worker opcode = "vmerge.vvm";
1075*795d594fSAndroid Build Coastguard Worker vm = ", v0";
1076*795d594fSAndroid Build Coastguard Worker } else if (GetRs2(insn32) == 0) {
1077*795d594fSAndroid Build Coastguard Worker opcode = "vmv.v.v";
1078*795d594fSAndroid Build Coastguard Worker rs2 = nullptr;
1079*795d594fSAndroid Build Coastguard Worker } else {
1080*795d594fSAndroid Build Coastguard Worker opcode = nullptr;
1081*795d594fSAndroid Build Coastguard Worker }
1082*795d594fSAndroid Build Coastguard Worker } else {
1083*795d594fSAndroid Build Coastguard Worker opcode = kOPIVVOpcodes[funct6];
1084*795d594fSAndroid Build Coastguard Worker }
1085*795d594fSAndroid Build Coastguard Worker
1086*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1087*795d594fSAndroid Build Coastguard Worker rs1 = VRegName(GetRs1(insn32));
1088*795d594fSAndroid Build Coastguard Worker break;
1089*795d594fSAndroid Build Coastguard Worker }
1090*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpIVX: {
1091*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPIVXOpcodes[64] = {
1092*795d594fSAndroid Build Coastguard Worker "vadd.vx", nullptr, "vsub.vx", "vrsub.vx",
1093*795d594fSAndroid Build Coastguard Worker "vminu.vx", "vmin.vx", "vmaxu.vx", "vmax.vx",
1094*795d594fSAndroid Build Coastguard Worker nullptr, "vand.vx", "vor.vx", "vxor.vx",
1095*795d594fSAndroid Build Coastguard Worker "vrgather.vx", nullptr, "vslideup.vx", "vslidedown.vx",
1096*795d594fSAndroid Build Coastguard Worker "vadc.vxm", "vmadc.vxm", "vsbc.vxm", "vmsbc.vxm",
1097*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, "<vmerge/vmv>",
1098*795d594fSAndroid Build Coastguard Worker "vmseq.vx", "vmsne.vx", "vmsltu.vx", "vmslt.vx",
1099*795d594fSAndroid Build Coastguard Worker "vmsleu.vx", "vmsle.vx", "vmsgtu.vx", "vmsgt.vx",
1100*795d594fSAndroid Build Coastguard Worker "vsaddu.vx", "vsadd.vx", "vssubu.vx", "vssub.vx",
1101*795d594fSAndroid Build Coastguard Worker nullptr, "vsll.vx", nullptr, "vsmul.vx",
1102*795d594fSAndroid Build Coastguard Worker "vsrl.vx", "vsra.vx", "vssrl.vx", "vssra.vx",
1103*795d594fSAndroid Build Coastguard Worker "vnsrl.wx", "vnsra.wx", "vnclipu.wx", "vnclip.wx",
1104*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1105*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1106*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1107*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1108*795d594fSAndroid Build Coastguard Worker };
1109*795d594fSAndroid Build Coastguard Worker
1110*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1111*795d594fSAndroid Build Coastguard Worker if (funct6 == 0b010111) {
1112*795d594fSAndroid Build Coastguard Worker // vmerge/vmv
1113*795d594fSAndroid Build Coastguard Worker if (masked) {
1114*795d594fSAndroid Build Coastguard Worker opcode = "vmerge.vxm";
1115*795d594fSAndroid Build Coastguard Worker vm = ", v0";
1116*795d594fSAndroid Build Coastguard Worker } else if (GetRs2(insn32) == 0) {
1117*795d594fSAndroid Build Coastguard Worker opcode = "vmv.v.x";
1118*795d594fSAndroid Build Coastguard Worker rs2 = nullptr;
1119*795d594fSAndroid Build Coastguard Worker } else {
1120*795d594fSAndroid Build Coastguard Worker opcode = nullptr;
1121*795d594fSAndroid Build Coastguard Worker }
1122*795d594fSAndroid Build Coastguard Worker } else {
1123*795d594fSAndroid Build Coastguard Worker opcode = kOPIVXOpcodes[funct6];
1124*795d594fSAndroid Build Coastguard Worker }
1125*795d594fSAndroid Build Coastguard Worker
1126*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1127*795d594fSAndroid Build Coastguard Worker rs1 = XRegName(GetRs1(insn32));
1128*795d594fSAndroid Build Coastguard Worker break;
1129*795d594fSAndroid Build Coastguard Worker }
1130*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpIVI: {
1131*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPIVIOpcodes[64] = {
1132*795d594fSAndroid Build Coastguard Worker "vadd.vi", nullptr, nullptr, "vrsub.vi",
1133*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1134*795d594fSAndroid Build Coastguard Worker nullptr, "vand.vi", "vor.vi", "vxor.vi",
1135*795d594fSAndroid Build Coastguard Worker "vrgather.vi", nullptr, "vslideup.vi", "vslidedown.vi",
1136*795d594fSAndroid Build Coastguard Worker "vadc.vim", "vmadc.vim", nullptr, nullptr,
1137*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, "<vmerge/vmv>",
1138*795d594fSAndroid Build Coastguard Worker "vmseq.vi", "vmsne.vi", nullptr, nullptr,
1139*795d594fSAndroid Build Coastguard Worker "vmsleu.vi", "vmsle.vi", "vmsgtu.vi", "vmsgt.vi",
1140*795d594fSAndroid Build Coastguard Worker "vsaddu.vi", "vsadd.vi", nullptr, nullptr,
1141*795d594fSAndroid Build Coastguard Worker nullptr, "vsll.vi", nullptr, "<vmvNr.v>",
1142*795d594fSAndroid Build Coastguard Worker "vsrl.vi", "vsra.vi", "vssrl.vi", "vssra.vi",
1143*795d594fSAndroid Build Coastguard Worker "vnsrl.wi", "vnsra.wi", "vnclipu.wi", "vnclip.wi",
1144*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1145*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1146*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1147*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1148*795d594fSAndroid Build Coastguard Worker };
1149*795d594fSAndroid Build Coastguard Worker
1150*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1151*795d594fSAndroid Build Coastguard Worker
1152*795d594fSAndroid Build Coastguard Worker if (funct6 == 0b010111) {
1153*795d594fSAndroid Build Coastguard Worker // vmerge/vmv
1154*795d594fSAndroid Build Coastguard Worker if (masked) {
1155*795d594fSAndroid Build Coastguard Worker opcode = "vmerge.vim";
1156*795d594fSAndroid Build Coastguard Worker vm = ", v0";
1157*795d594fSAndroid Build Coastguard Worker } else if (GetRs2(insn32) == 0) {
1158*795d594fSAndroid Build Coastguard Worker opcode = "vmv.v.i";
1159*795d594fSAndroid Build Coastguard Worker rs2 = nullptr;
1160*795d594fSAndroid Build Coastguard Worker } else {
1161*795d594fSAndroid Build Coastguard Worker opcode = nullptr;
1162*795d594fSAndroid Build Coastguard Worker }
1163*795d594fSAndroid Build Coastguard Worker } else if (funct6 == 0b100111) {
1164*795d594fSAndroid Build Coastguard Worker uint32_t rs1V = GetRs1(insn32);
1165*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVmvnrOpcodes[8] = {
1166*795d594fSAndroid Build Coastguard Worker "vmv1r.v", "vmv2r.v", nullptr, "vmv4r.v",
1167*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, "vmv8r.v",
1168*795d594fSAndroid Build Coastguard Worker };
1169*795d594fSAndroid Build Coastguard Worker if (IsUint<3>(rs1V)) {
1170*795d594fSAndroid Build Coastguard Worker opcode = kVmvnrOpcodes[rs1V];
1171*795d594fSAndroid Build Coastguard Worker }
1172*795d594fSAndroid Build Coastguard Worker } else {
1173*795d594fSAndroid Build Coastguard Worker opcode = kOPIVIOpcodes[funct6];
1174*795d594fSAndroid Build Coastguard Worker }
1175*795d594fSAndroid Build Coastguard Worker
1176*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1177*795d594fSAndroid Build Coastguard Worker break;
1178*795d594fSAndroid Build Coastguard Worker }
1179*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpMVV: {
1180*795d594fSAndroid Build Coastguard Worker switch (funct6) {
1181*795d594fSAndroid Build Coastguard Worker case VWXUNARY0: {
1182*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVWXUNARY0Opcodes[32] = {
1183*795d594fSAndroid Build Coastguard Worker "vmv.x.s", nullptr, nullptr, nullptr,
1184*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1185*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1186*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1187*795d594fSAndroid Build Coastguard Worker "vcpop.m", "vfirst.m", nullptr, nullptr,
1188*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1189*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1190*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1191*795d594fSAndroid Build Coastguard Worker };
1192*795d594fSAndroid Build Coastguard Worker opcode = kVWXUNARY0Opcodes[GetRs1(insn32)];
1193*795d594fSAndroid Build Coastguard Worker rd = XRegName(GetRd(insn32));
1194*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1195*795d594fSAndroid Build Coastguard Worker break;
1196*795d594fSAndroid Build Coastguard Worker }
1197*795d594fSAndroid Build Coastguard Worker case VXUNARY0: {
1198*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVXUNARY0Opcodes[32] = {
1199*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, "vzext.vf8", "vsext.vf8",
1200*795d594fSAndroid Build Coastguard Worker "vzext.vf4", "vsext.vf4", "vzext.vf2", "vsext.vf2",
1201*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1202*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1203*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1204*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1205*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1206*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1207*795d594fSAndroid Build Coastguard Worker };
1208*795d594fSAndroid Build Coastguard Worker opcode = kVXUNARY0Opcodes[GetRs1(insn32)];
1209*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1210*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1211*795d594fSAndroid Build Coastguard Worker break;
1212*795d594fSAndroid Build Coastguard Worker }
1213*795d594fSAndroid Build Coastguard Worker case VMUNARY0: {
1214*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVMUNARY0Opcodes[32] = {
1215*795d594fSAndroid Build Coastguard Worker nullptr, "vmsbf.m", "vmsof.m", "vmsif.m",
1216*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1217*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1218*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1219*795d594fSAndroid Build Coastguard Worker "viota.m", "vid.v", nullptr, nullptr,
1220*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1221*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1222*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1223*795d594fSAndroid Build Coastguard Worker };
1224*795d594fSAndroid Build Coastguard Worker opcode = kVMUNARY0Opcodes[GetRs1(insn32)];
1225*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1226*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1227*795d594fSAndroid Build Coastguard Worker break;
1228*795d594fSAndroid Build Coastguard Worker }
1229*795d594fSAndroid Build Coastguard Worker default: {
1230*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPMVVOpcodes[64] = {
1231*795d594fSAndroid Build Coastguard Worker "vredsum.vs", "vredand.vs", "vredor.vs", "vredxor.vs",
1232*795d594fSAndroid Build Coastguard Worker "vredminu.vs", "vredmin.vs", "vredmaxu.vs", "vredmax.vs",
1233*795d594fSAndroid Build Coastguard Worker "vaaddu.vv", "vaadd.vv", "vasubu.vv", "vasub.vv",
1234*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1235*795d594fSAndroid Build Coastguard Worker "<VWXUNARY0>", nullptr, "<VXUNARY0>", nullptr,
1236*795d594fSAndroid Build Coastguard Worker "<VMUNARY0>", nullptr, nullptr, "vcompress.vm",
1237*795d594fSAndroid Build Coastguard Worker "vmandn.mm", "vmand.mm", "vmor.mm", "vmxor.mm",
1238*795d594fSAndroid Build Coastguard Worker "vmorn.mm", "vmnand.mm", "vmnor.mm", "vmxnor.mm",
1239*795d594fSAndroid Build Coastguard Worker "vdivu.vv", "vdiv.vv", "vremu.vv", "vrem.vv",
1240*795d594fSAndroid Build Coastguard Worker "vmulhu.vv", "vmul.vv", "vmulhsu.vv", "vmulh.vv",
1241*795d594fSAndroid Build Coastguard Worker nullptr, "vmadd.vv", nullptr, "vnmsub.vv",
1242*795d594fSAndroid Build Coastguard Worker nullptr, "vmacc.vv", nullptr, "vnmsac.vv",
1243*795d594fSAndroid Build Coastguard Worker "vwaddu.vv", "vwadd.vv", "vwsubu.vv", "vwsub.vv",
1244*795d594fSAndroid Build Coastguard Worker "vwaddu.wv", "vwadd.wv", "vwsubu.wv", "vwsub.wv",
1245*795d594fSAndroid Build Coastguard Worker "vwmulu.vv", nullptr, "vwmulsu.vv", "vwmul.vv",
1246*795d594fSAndroid Build Coastguard Worker "vwmaccu.vv", "vwmacc.vv", nullptr, "vwmaccsu.vv",
1247*795d594fSAndroid Build Coastguard Worker };
1248*795d594fSAndroid Build Coastguard Worker
1249*795d594fSAndroid Build Coastguard Worker opcode = kOPMVVOpcodes[funct6];
1250*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1251*795d594fSAndroid Build Coastguard Worker rs1 = VRegName(GetRs1(insn32));
1252*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1253*795d594fSAndroid Build Coastguard Worker
1254*795d594fSAndroid Build Coastguard Worker if (0x17u <= funct6 && funct6 <= 0x1Fu) {
1255*795d594fSAndroid Build Coastguard Worker if (masked) {
1256*795d594fSAndroid Build Coastguard Worker // for vcompress.vm and *.mm encodings with vm=0 are reserved
1257*795d594fSAndroid Build Coastguard Worker opcode = nullptr;
1258*795d594fSAndroid Build Coastguard Worker }
1259*795d594fSAndroid Build Coastguard Worker }
1260*795d594fSAndroid Build Coastguard Worker
1261*795d594fSAndroid Build Coastguard Worker MaybeSwapOperands(funct6, rs1, rs2);
1262*795d594fSAndroid Build Coastguard Worker
1263*795d594fSAndroid Build Coastguard Worker break;
1264*795d594fSAndroid Build Coastguard Worker }
1265*795d594fSAndroid Build Coastguard Worker }
1266*795d594fSAndroid Build Coastguard Worker break;
1267*795d594fSAndroid Build Coastguard Worker }
1268*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpMVX: {
1269*795d594fSAndroid Build Coastguard Worker switch (funct6) {
1270*795d594fSAndroid Build Coastguard Worker case VRXUNARY0: {
1271*795d594fSAndroid Build Coastguard Worker opcode = GetRs2(insn32) == 0u ? "vmv.s.x" : nullptr;
1272*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1273*795d594fSAndroid Build Coastguard Worker rs1 = XRegName(GetRs1(insn32));
1274*795d594fSAndroid Build Coastguard Worker break;
1275*795d594fSAndroid Build Coastguard Worker }
1276*795d594fSAndroid Build Coastguard Worker default: {
1277*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPMVXOpcodes[64] = {
1278*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1279*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1280*795d594fSAndroid Build Coastguard Worker "vaaddu.vx", "vaadd.vx", "vasubu.vx", "vasub.vx",
1281*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, "vslide1up.vx", "vslide1down.vx",
1282*795d594fSAndroid Build Coastguard Worker "<VRXUNARY0>", nullptr, nullptr, nullptr,
1283*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1284*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1285*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1286*795d594fSAndroid Build Coastguard Worker "vdivu.vx", "vdiv.vx", "vremu.vx", "vrem.vx",
1287*795d594fSAndroid Build Coastguard Worker "vmulhu.vx", "vmul.vx", "vmulhsu.vx", "vmulh.vx",
1288*795d594fSAndroid Build Coastguard Worker nullptr, "vmadd.vx", nullptr, "vnmsub.vx",
1289*795d594fSAndroid Build Coastguard Worker nullptr, "vmacc.vx", nullptr, "vnmsac.vx",
1290*795d594fSAndroid Build Coastguard Worker "vwaddu.vx", "vwadd.vx", "vwsubu.vx", "vwsub.vx",
1291*795d594fSAndroid Build Coastguard Worker "vwaddu.wv", "vwadd.wv", "vwsubu.wv", "vwsub.wv",
1292*795d594fSAndroid Build Coastguard Worker "vwmulu.vx", nullptr, "vwmulsu.vx", "vwmul.vx",
1293*795d594fSAndroid Build Coastguard Worker "vwmaccu.vx", "vwmacc.vx", "vwmaccus.vx", "vwmaccsu.vx",
1294*795d594fSAndroid Build Coastguard Worker };
1295*795d594fSAndroid Build Coastguard Worker opcode = kOPMVXOpcodes[funct6];
1296*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1297*795d594fSAndroid Build Coastguard Worker rs1 = XRegName(GetRs1(insn32));
1298*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1299*795d594fSAndroid Build Coastguard Worker
1300*795d594fSAndroid Build Coastguard Worker MaybeSwapOperands(funct6, rs1, rs2);
1301*795d594fSAndroid Build Coastguard Worker
1302*795d594fSAndroid Build Coastguard Worker break;
1303*795d594fSAndroid Build Coastguard Worker }
1304*795d594fSAndroid Build Coastguard Worker }
1305*795d594fSAndroid Build Coastguard Worker break;
1306*795d594fSAndroid Build Coastguard Worker }
1307*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpFVV: {
1308*795d594fSAndroid Build Coastguard Worker switch (funct6) {
1309*795d594fSAndroid Build Coastguard Worker case VWFUNARY0: {
1310*795d594fSAndroid Build Coastguard Worker opcode = GetRs1(insn32) == 0u ? "vfmv.f.s" : nullptr;
1311*795d594fSAndroid Build Coastguard Worker rd = XRegName(GetRd(insn32));
1312*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1313*795d594fSAndroid Build Coastguard Worker break;
1314*795d594fSAndroid Build Coastguard Worker }
1315*795d594fSAndroid Build Coastguard Worker case VFUNARY0: {
1316*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVFUNARY0Opcodes[32] = {
1317*795d594fSAndroid Build Coastguard Worker "vfcvt.xu.f.v", "vfcvt.x.f.v", "vfcvt.f.xu.v", "vfcvt.f.x.v",
1318*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, "vfcvt.rtz.xu.f.v", "vfcvt.rtz.x.f.v",
1319*795d594fSAndroid Build Coastguard Worker "vfwcvt.xu.f.v", "vfwcvt.x.f.v", "vfwcvt.f.xu.v", "vfwcvt.f.x.v",
1320*795d594fSAndroid Build Coastguard Worker "vfwcvt.f.f.v", nullptr, "vfwcvt.rtz.xu.f.v", "vfwcvt.rtz.x.f.v",
1321*795d594fSAndroid Build Coastguard Worker "vfncvt.xu.f.w", "vfncvt.x.f.w", "vfncvt.f.xu.w", "vfncvt.f.x.w",
1322*795d594fSAndroid Build Coastguard Worker "vfncvt.f.f.w", "vfncvt.rod.f.f.w", "vfncvt.rtz.xu.f.w", "vfncvt.rtz.x.f.w",
1323*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1324*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1325*795d594fSAndroid Build Coastguard Worker };
1326*795d594fSAndroid Build Coastguard Worker opcode = kVFUNARY0Opcodes[GetRs1(insn32)];
1327*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1328*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1329*795d594fSAndroid Build Coastguard Worker break;
1330*795d594fSAndroid Build Coastguard Worker }
1331*795d594fSAndroid Build Coastguard Worker case VFUNARY1: {
1332*795d594fSAndroid Build Coastguard Worker static constexpr const char* kVFUNARY1Opcodes[32] = {
1333*795d594fSAndroid Build Coastguard Worker "vfsqrt.v", nullptr, nullptr, nullptr,
1334*795d594fSAndroid Build Coastguard Worker "vfrsqrt7.v", "vfrec7.v", nullptr, nullptr,
1335*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1336*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1337*795d594fSAndroid Build Coastguard Worker "vfclass.v", nullptr, nullptr, nullptr,
1338*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1339*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1340*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1341*795d594fSAndroid Build Coastguard Worker };
1342*795d594fSAndroid Build Coastguard Worker opcode = kVFUNARY1Opcodes[GetRs1(insn32)];
1343*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1344*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1345*795d594fSAndroid Build Coastguard Worker break;
1346*795d594fSAndroid Build Coastguard Worker }
1347*795d594fSAndroid Build Coastguard Worker default: {
1348*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPFVVOpcodes[64] = {
1349*795d594fSAndroid Build Coastguard Worker "vfadd.vv", "vfredusum.vs", "vfsub.vv", "vfredosum.vs",
1350*795d594fSAndroid Build Coastguard Worker "vfmin.vv", "vfredmin.vs", "vfmax.vv", "vfredmax.vs",
1351*795d594fSAndroid Build Coastguard Worker "vfsgnj.vv", "vfsgnjn.vv", "vfsgnjx.vv", nullptr,
1352*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1353*795d594fSAndroid Build Coastguard Worker "<VWFUNARY0>", nullptr, "<VFUNARY0>", "<VFUNARY1>",
1354*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr,
1355*795d594fSAndroid Build Coastguard Worker "vmfeq.vv", "vmfle.vv", nullptr, "vmflt.vv",
1356*795d594fSAndroid Build Coastguard Worker "vmfne.vv", nullptr, nullptr, nullptr,
1357*795d594fSAndroid Build Coastguard Worker "vfdiv.vv", nullptr, nullptr, nullptr,
1358*795d594fSAndroid Build Coastguard Worker "vfmul.vv", nullptr, nullptr, nullptr,
1359*795d594fSAndroid Build Coastguard Worker "vfmadd.vv", "vfnmadd.vv", "vfmsub.vv", "vfnmsub.vv",
1360*795d594fSAndroid Build Coastguard Worker "vfmacc.vv", "vfnmacc.vv", "vfmsac.vv", "vfnmsac.vv",
1361*795d594fSAndroid Build Coastguard Worker "vfwadd.vv", "vfwredusum.vs", "vfwsub.vv", "vfwredosum.vs",
1362*795d594fSAndroid Build Coastguard Worker "vfwadd.wv", nullptr, "vfwsub.wv", nullptr,
1363*795d594fSAndroid Build Coastguard Worker "vfwmul.vv", nullptr, nullptr, nullptr,
1364*795d594fSAndroid Build Coastguard Worker "vfwmacc.vv", "vfwnmacc.vv", "vfwmsac.vv", "vfwnmsac.vv",
1365*795d594fSAndroid Build Coastguard Worker };
1366*795d594fSAndroid Build Coastguard Worker opcode = kOPFVVOpcodes[funct6];
1367*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1368*795d594fSAndroid Build Coastguard Worker rs1 = VRegName(GetRs1(insn32));
1369*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1370*795d594fSAndroid Build Coastguard Worker
1371*795d594fSAndroid Build Coastguard Worker MaybeSwapOperands(funct6, rs1, rs2);
1372*795d594fSAndroid Build Coastguard Worker
1373*795d594fSAndroid Build Coastguard Worker break;
1374*795d594fSAndroid Build Coastguard Worker }
1375*795d594fSAndroid Build Coastguard Worker }
1376*795d594fSAndroid Build Coastguard Worker break;
1377*795d594fSAndroid Build Coastguard Worker }
1378*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpFVF: {
1379*795d594fSAndroid Build Coastguard Worker switch (funct6) {
1380*795d594fSAndroid Build Coastguard Worker case VRFUNARY0: {
1381*795d594fSAndroid Build Coastguard Worker opcode = GetRs2(insn32) == 0u ? "vfmv.s.f" : nullptr;
1382*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1383*795d594fSAndroid Build Coastguard Worker rs1 = FRegName(GetRs1(insn32));
1384*795d594fSAndroid Build Coastguard Worker break;
1385*795d594fSAndroid Build Coastguard Worker }
1386*795d594fSAndroid Build Coastguard Worker default: {
1387*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOPFVFOpcodes[64] = {
1388*795d594fSAndroid Build Coastguard Worker "vfadd.vf", nullptr, "vfsub.vf", nullptr,
1389*795d594fSAndroid Build Coastguard Worker "vfmin.vf", nullptr, "vfmax.vf", nullptr,
1390*795d594fSAndroid Build Coastguard Worker "vfsgnj.vf", "vfsgnjn.vf", "vfsgnjx.vf", nullptr,
1391*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, "vfslide1up.vf", "vfslide1down.vf",
1392*795d594fSAndroid Build Coastguard Worker "<VRFUNARY0>", nullptr, nullptr, nullptr,
1393*795d594fSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, "<vfmerge.vfm/vfmv>",
1394*795d594fSAndroid Build Coastguard Worker "vmfeq.vf", "vmfle.vf", nullptr, "vmflt.vf",
1395*795d594fSAndroid Build Coastguard Worker "vmfne.vf", "vmfgt.vf", nullptr, "vmfge.vf",
1396*795d594fSAndroid Build Coastguard Worker "vfdiv.vf", "vfrdiv.vf", nullptr, nullptr,
1397*795d594fSAndroid Build Coastguard Worker "vfmul.vf", nullptr, nullptr, "vfrsub.vf",
1398*795d594fSAndroid Build Coastguard Worker "vfmadd.vf", "vfnmadd.vf", "vfmsub.vf", "vfnmsub.vf",
1399*795d594fSAndroid Build Coastguard Worker "vfmacc.vf", "vfnmacc.vf", "vfmsac.vf", "vfnmsac.vf",
1400*795d594fSAndroid Build Coastguard Worker "vfwadd.vf", nullptr, "vfwsub.vf", nullptr,
1401*795d594fSAndroid Build Coastguard Worker "vfwadd.wf", nullptr, "vfwsub.wf", nullptr,
1402*795d594fSAndroid Build Coastguard Worker "vfwmul.vf", nullptr, nullptr, nullptr,
1403*795d594fSAndroid Build Coastguard Worker "vfwmacc.vf", "vfwnmacc.vf", "vfwmsac.vf", "vfwnmsac.vf",
1404*795d594fSAndroid Build Coastguard Worker };
1405*795d594fSAndroid Build Coastguard Worker
1406*795d594fSAndroid Build Coastguard Worker rs2 = VRegName(GetRs2(insn32));
1407*795d594fSAndroid Build Coastguard Worker if (funct6 == 0b010111) {
1408*795d594fSAndroid Build Coastguard Worker // vfmerge/vfmv
1409*795d594fSAndroid Build Coastguard Worker if (masked) {
1410*795d594fSAndroid Build Coastguard Worker opcode = "vfmerge.vfm";
1411*795d594fSAndroid Build Coastguard Worker vm = ", v0";
1412*795d594fSAndroid Build Coastguard Worker } else if (GetRs2(insn32) == 0) {
1413*795d594fSAndroid Build Coastguard Worker opcode = "vfmv.v.f";
1414*795d594fSAndroid Build Coastguard Worker rs2 = nullptr;
1415*795d594fSAndroid Build Coastguard Worker } else {
1416*795d594fSAndroid Build Coastguard Worker opcode = nullptr;
1417*795d594fSAndroid Build Coastguard Worker }
1418*795d594fSAndroid Build Coastguard Worker } else {
1419*795d594fSAndroid Build Coastguard Worker opcode = kOPFVFOpcodes[funct6];
1420*795d594fSAndroid Build Coastguard Worker }
1421*795d594fSAndroid Build Coastguard Worker
1422*795d594fSAndroid Build Coastguard Worker rd = VRegName(GetRd(insn32));
1423*795d594fSAndroid Build Coastguard Worker rs1 = FRegName(GetRs1(insn32));
1424*795d594fSAndroid Build Coastguard Worker
1425*795d594fSAndroid Build Coastguard Worker MaybeSwapOperands(funct6, rs1, rs2);
1426*795d594fSAndroid Build Coastguard Worker
1427*795d594fSAndroid Build Coastguard Worker break;
1428*795d594fSAndroid Build Coastguard Worker }
1429*795d594fSAndroid Build Coastguard Worker }
1430*795d594fSAndroid Build Coastguard Worker break;
1431*795d594fSAndroid Build Coastguard Worker }
1432*795d594fSAndroid Build Coastguard Worker case VAIEncodings::kOpCFG: { // vector ALU control instructions
1433*795d594fSAndroid Build Coastguard Worker if ((insn32 >> 31) != 0u) {
1434*795d594fSAndroid Build Coastguard Worker if (((insn32 >> 30) & 0x1U) != 0u) { // vsetivli
1435*795d594fSAndroid Build Coastguard Worker const uint32_t zimm = Decode32UImm12(insn32) & ~0xC00U;
1436*795d594fSAndroid Build Coastguard Worker const uint32_t imm5 = GetRs1(insn32);
1437*795d594fSAndroid Build Coastguard Worker os_ << "vsetivli " << XRegName(GetRd(insn32)) << ", " << StringPrintf("0x%08x", imm5)
1438*795d594fSAndroid Build Coastguard Worker << ", ";
1439*795d594fSAndroid Build Coastguard Worker AppendVType(zimm);
1440*795d594fSAndroid Build Coastguard Worker } else { // vsetvl
1441*795d594fSAndroid Build Coastguard Worker os_ << "vsetvl " << XRegName(GetRd(insn32)) << ", " << XRegName(GetRs1(insn32)) << ", "
1442*795d594fSAndroid Build Coastguard Worker << XRegName(GetRs2(insn32));
1443*795d594fSAndroid Build Coastguard Worker if ((Decode32UImm7(insn32) & 0x40u) != 0u) {
1444*795d594fSAndroid Build Coastguard Worker os_ << "\t# incorrect funct7 literal : "
1445*795d594fSAndroid Build Coastguard Worker << StringPrintf("0x%08x", Decode32UImm7(insn32));
1446*795d594fSAndroid Build Coastguard Worker }
1447*795d594fSAndroid Build Coastguard Worker }
1448*795d594fSAndroid Build Coastguard Worker } else { // vsetvli
1449*795d594fSAndroid Build Coastguard Worker const uint32_t zimm = Decode32UImm12(insn32) & ~0x800U;
1450*795d594fSAndroid Build Coastguard Worker os_ << "vsetvli " << XRegName(GetRd(insn32)) << ", " << XRegName(GetRs1(insn32)) << ", ";
1451*795d594fSAndroid Build Coastguard Worker AppendVType(zimm);
1452*795d594fSAndroid Build Coastguard Worker }
1453*795d594fSAndroid Build Coastguard Worker return;
1454*795d594fSAndroid Build Coastguard Worker }
1455*795d594fSAndroid Build Coastguard Worker }
1456*795d594fSAndroid Build Coastguard Worker
1457*795d594fSAndroid Build Coastguard Worker if (opcode == nullptr) {
1458*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
1459*795d594fSAndroid Build Coastguard Worker return;
1460*795d594fSAndroid Build Coastguard Worker }
1461*795d594fSAndroid Build Coastguard Worker
1462*795d594fSAndroid Build Coastguard Worker os_ << opcode << " " << rd;
1463*795d594fSAndroid Build Coastguard Worker
1464*795d594fSAndroid Build Coastguard Worker if (rs2 != nullptr) {
1465*795d594fSAndroid Build Coastguard Worker os_ << ", " << rs2;
1466*795d594fSAndroid Build Coastguard Worker }
1467*795d594fSAndroid Build Coastguard Worker
1468*795d594fSAndroid Build Coastguard Worker if (rs1 != nullptr) {
1469*795d594fSAndroid Build Coastguard Worker os_ << ", " << rs1;
1470*795d594fSAndroid Build Coastguard Worker } else if (vai == VAIEncodings::kOpIVI) {
1471*795d594fSAndroid Build Coastguard Worker os_ << StringPrintf(", 0x%08x", GetRs1(insn32));
1472*795d594fSAndroid Build Coastguard Worker }
1473*795d594fSAndroid Build Coastguard Worker
1474*795d594fSAndroid Build Coastguard Worker os_ << vm;
1475*795d594fSAndroid Build Coastguard Worker }
1476*795d594fSAndroid Build Coastguard Worker
Print32FpFma(uint32_t insn32)1477*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32FpFma(uint32_t insn32) {
1478*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x73u, 0x43u); // Note: Bits 0xc select the FMA opcode.
1479*795d594fSAndroid Build Coastguard Worker uint32_t funct2 = (insn32 >> 25) & 3u;
1480*795d594fSAndroid Build Coastguard Worker if (funct2 >= 2u) {
1481*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>"; // Note: This includes the "H" and "Q" extensions.
1482*795d594fSAndroid Build Coastguard Worker return;
1483*795d594fSAndroid Build Coastguard Worker }
1484*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = { "fmadd", "fmsub", "fnmsub", "fnmadd" };
1485*795d594fSAndroid Build Coastguard Worker os_ << kOpcodes[(insn32 >> 2) & 3u] << ((funct2 != 0u) ? ".d" : ".s")
1486*795d594fSAndroid Build Coastguard Worker << RoundingModeName(GetRoundingMode(insn32)) << " "
1487*795d594fSAndroid Build Coastguard Worker << FRegName(GetRd(insn32)) << ", " << FRegName(GetRs1(insn32)) << ", "
1488*795d594fSAndroid Build Coastguard Worker << FRegName(GetRs2(insn32)) << ", " << FRegName(GetRs3(insn32));
1489*795d594fSAndroid Build Coastguard Worker }
1490*795d594fSAndroid Build Coastguard Worker
Print32Zicsr(uint32_t insn32)1491*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Zicsr(uint32_t insn32) {
1492*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x73u);
1493*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = (insn32 >> 12) & 7u;
1494*795d594fSAndroid Build Coastguard Worker static const char* const kOpcodes[] = {
1495*795d594fSAndroid Build Coastguard Worker nullptr, "csrrw", "csrrs", "csrrc", nullptr, "csrrwi", "csrrsi", "csrrci"
1496*795d594fSAndroid Build Coastguard Worker };
1497*795d594fSAndroid Build Coastguard Worker const char* opcode = kOpcodes[funct3];
1498*795d594fSAndroid Build Coastguard Worker if (opcode == nullptr) {
1499*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
1500*795d594fSAndroid Build Coastguard Worker return;
1501*795d594fSAndroid Build Coastguard Worker }
1502*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRd(insn32);
1503*795d594fSAndroid Build Coastguard Worker uint32_t rs1_or_uimm = GetRs1(insn32);
1504*795d594fSAndroid Build Coastguard Worker uint32_t csr = insn32 >> 20;
1505*795d594fSAndroid Build Coastguard Worker // Print shorter macro instruction notation if available.
1506*795d594fSAndroid Build Coastguard Worker if (funct3 == /*CSRRW*/ 1u && rd == 0u && rs1_or_uimm == 0u && csr == 0xc00u) {
1507*795d594fSAndroid Build Coastguard Worker os_ << "unimp";
1508*795d594fSAndroid Build Coastguard Worker return;
1509*795d594fSAndroid Build Coastguard Worker } else if (funct3 == /*CSRRS*/ 2u && rs1_or_uimm == 0u) {
1510*795d594fSAndroid Build Coastguard Worker if (csr == 0xc00u) {
1511*795d594fSAndroid Build Coastguard Worker os_ << "rdcycle " << XRegName(rd);
1512*795d594fSAndroid Build Coastguard Worker } else if (csr == 0xc01u) {
1513*795d594fSAndroid Build Coastguard Worker os_ << "rdtime " << XRegName(rd);
1514*795d594fSAndroid Build Coastguard Worker } else if (csr == 0xc02u) {
1515*795d594fSAndroid Build Coastguard Worker os_ << "rdinstret " << XRegName(rd);
1516*795d594fSAndroid Build Coastguard Worker } else {
1517*795d594fSAndroid Build Coastguard Worker os_ << "csrr " << XRegName(rd) << ", " << csr;
1518*795d594fSAndroid Build Coastguard Worker }
1519*795d594fSAndroid Build Coastguard Worker return;
1520*795d594fSAndroid Build Coastguard Worker }
1521*795d594fSAndroid Build Coastguard Worker
1522*795d594fSAndroid Build Coastguard Worker if (rd == 0u) {
1523*795d594fSAndroid Build Coastguard Worker static const char* const kAltOpcodes[] = {
1524*795d594fSAndroid Build Coastguard Worker nullptr, "csrw", "csrs", "csrc", nullptr, "csrwi", "csrsi", "csrci"
1525*795d594fSAndroid Build Coastguard Worker };
1526*795d594fSAndroid Build Coastguard Worker DCHECK(kAltOpcodes[funct3] != nullptr);
1527*795d594fSAndroid Build Coastguard Worker os_ << kAltOpcodes[funct3] << " " << csr << ", ";
1528*795d594fSAndroid Build Coastguard Worker } else {
1529*795d594fSAndroid Build Coastguard Worker os_ << opcode << " " << XRegName(rd) << ", " << csr << ", ";
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker if (funct3 >= /*CSRRWI/CSRRSI/CSRRCI*/ 4u) {
1532*795d594fSAndroid Build Coastguard Worker os_ << rs1_or_uimm;
1533*795d594fSAndroid Build Coastguard Worker } else {
1534*795d594fSAndroid Build Coastguard Worker os_ << XRegName(rs1_or_uimm);
1535*795d594fSAndroid Build Coastguard Worker }
1536*795d594fSAndroid Build Coastguard Worker }
1537*795d594fSAndroid Build Coastguard Worker
Print32Fence(uint32_t insn32)1538*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Print32Fence(uint32_t insn32) {
1539*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn32 & 0x7fu, 0x0fu);
1540*795d594fSAndroid Build Coastguard Worker if ((insn32 & 0xf00fffffu) == 0x0000000fu) {
1541*795d594fSAndroid Build Coastguard Worker auto print_flags = [&](uint32_t flags) {
1542*795d594fSAndroid Build Coastguard Worker if (flags == 0u) {
1543*795d594fSAndroid Build Coastguard Worker os_ << "0";
1544*795d594fSAndroid Build Coastguard Worker } else {
1545*795d594fSAndroid Build Coastguard Worker DCHECK_LT(flags, 0x10u);
1546*795d594fSAndroid Build Coastguard Worker static const char kFlagNames[] = "wroi";
1547*795d594fSAndroid Build Coastguard Worker for (size_t bit : { 3u, 2u, 1u, 0u }) { // Print in the "iorw" order.
1548*795d594fSAndroid Build Coastguard Worker if ((flags & (1u << bit)) != 0u) {
1549*795d594fSAndroid Build Coastguard Worker os_ << kFlagNames[bit];
1550*795d594fSAndroid Build Coastguard Worker }
1551*795d594fSAndroid Build Coastguard Worker }
1552*795d594fSAndroid Build Coastguard Worker }
1553*795d594fSAndroid Build Coastguard Worker };
1554*795d594fSAndroid Build Coastguard Worker os_ << "fence.";
1555*795d594fSAndroid Build Coastguard Worker print_flags((insn32 >> 24) & 0xfu);
1556*795d594fSAndroid Build Coastguard Worker os_ << ".";
1557*795d594fSAndroid Build Coastguard Worker print_flags((insn32 >> 20) & 0xfu);
1558*795d594fSAndroid Build Coastguard Worker } else if (insn32 == 0x8330000fu) {
1559*795d594fSAndroid Build Coastguard Worker os_ << "fence.tso";
1560*795d594fSAndroid Build Coastguard Worker } else if (insn32 == 0x0000100fu) {
1561*795d594fSAndroid Build Coastguard Worker os_ << "fence.i";
1562*795d594fSAndroid Build Coastguard Worker } else {
1563*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
1564*795d594fSAndroid Build Coastguard Worker }
1565*795d594fSAndroid Build Coastguard Worker }
1566*795d594fSAndroid Build Coastguard Worker
Dump32(const uint8_t * insn)1567*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Dump32(const uint8_t* insn) {
1568*795d594fSAndroid Build Coastguard Worker uint32_t insn32 = static_cast<uint32_t>(insn[0]) +
1569*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(insn[1]) << 8) +
1570*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(insn[2]) << 16) +
1571*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(insn[3]) << 24);
1572*795d594fSAndroid Build Coastguard Worker CHECK_EQ(insn32 & 3u, 3u);
1573*795d594fSAndroid Build Coastguard Worker os_ << disassembler_->FormatInstructionPointer(insn) << StringPrintf(": %08x\t", insn32);
1574*795d594fSAndroid Build Coastguard Worker switch (insn32 & 0x7fu) {
1575*795d594fSAndroid Build Coastguard Worker case 0x37u:
1576*795d594fSAndroid Build Coastguard Worker Print32Lui(insn32);
1577*795d594fSAndroid Build Coastguard Worker break;
1578*795d594fSAndroid Build Coastguard Worker case 0x17u:
1579*795d594fSAndroid Build Coastguard Worker Print32Auipc(insn, insn32);
1580*795d594fSAndroid Build Coastguard Worker break;
1581*795d594fSAndroid Build Coastguard Worker case 0x6fu:
1582*795d594fSAndroid Build Coastguard Worker Print32Jal(insn, insn32);
1583*795d594fSAndroid Build Coastguard Worker break;
1584*795d594fSAndroid Build Coastguard Worker case 0x67u:
1585*795d594fSAndroid Build Coastguard Worker switch ((insn32 >> 12) & 7u) { // funct3
1586*795d594fSAndroid Build Coastguard Worker case 0:
1587*795d594fSAndroid Build Coastguard Worker Print32Jalr(insn, insn32);
1588*795d594fSAndroid Build Coastguard Worker break;
1589*795d594fSAndroid Build Coastguard Worker default:
1590*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
1591*795d594fSAndroid Build Coastguard Worker break;
1592*795d594fSAndroid Build Coastguard Worker }
1593*795d594fSAndroid Build Coastguard Worker break;
1594*795d594fSAndroid Build Coastguard Worker case 0x63u:
1595*795d594fSAndroid Build Coastguard Worker Print32BCond(insn, insn32);
1596*795d594fSAndroid Build Coastguard Worker break;
1597*795d594fSAndroid Build Coastguard Worker case 0x03u:
1598*795d594fSAndroid Build Coastguard Worker Print32Load(insn32);
1599*795d594fSAndroid Build Coastguard Worker break;
1600*795d594fSAndroid Build Coastguard Worker case 0x23u:
1601*795d594fSAndroid Build Coastguard Worker Print32Store(insn32);
1602*795d594fSAndroid Build Coastguard Worker break;
1603*795d594fSAndroid Build Coastguard Worker case 0x07u:
1604*795d594fSAndroid Build Coastguard Worker Print32FLoad(insn32);
1605*795d594fSAndroid Build Coastguard Worker break;
1606*795d594fSAndroid Build Coastguard Worker case 0x27u:
1607*795d594fSAndroid Build Coastguard Worker Print32FStore(insn32);
1608*795d594fSAndroid Build Coastguard Worker break;
1609*795d594fSAndroid Build Coastguard Worker case 0x13u:
1610*795d594fSAndroid Build Coastguard Worker case 0x1bu:
1611*795d594fSAndroid Build Coastguard Worker Print32BinOpImm(insn32);
1612*795d594fSAndroid Build Coastguard Worker break;
1613*795d594fSAndroid Build Coastguard Worker case 0x33u:
1614*795d594fSAndroid Build Coastguard Worker case 0x3bu:
1615*795d594fSAndroid Build Coastguard Worker Print32BinOp(insn32);
1616*795d594fSAndroid Build Coastguard Worker break;
1617*795d594fSAndroid Build Coastguard Worker case 0x2fu:
1618*795d594fSAndroid Build Coastguard Worker Print32Atomic(insn32);
1619*795d594fSAndroid Build Coastguard Worker break;
1620*795d594fSAndroid Build Coastguard Worker case 0x53u:
1621*795d594fSAndroid Build Coastguard Worker Print32FpOp(insn32);
1622*795d594fSAndroid Build Coastguard Worker break;
1623*795d594fSAndroid Build Coastguard Worker case 0x57u:
1624*795d594fSAndroid Build Coastguard Worker Print32RVVOp(insn32);
1625*795d594fSAndroid Build Coastguard Worker break;
1626*795d594fSAndroid Build Coastguard Worker case 0x43u:
1627*795d594fSAndroid Build Coastguard Worker case 0x47u:
1628*795d594fSAndroid Build Coastguard Worker case 0x4bu:
1629*795d594fSAndroid Build Coastguard Worker case 0x4fu:
1630*795d594fSAndroid Build Coastguard Worker Print32FpFma(insn32);
1631*795d594fSAndroid Build Coastguard Worker break;
1632*795d594fSAndroid Build Coastguard Worker case 0x73u:
1633*795d594fSAndroid Build Coastguard Worker if ((insn32 & 0xffefffffu) == 0x00000073u) {
1634*795d594fSAndroid Build Coastguard Worker os_ << ((insn32 == 0x00000073u) ? "ecall" : "ebreak");
1635*795d594fSAndroid Build Coastguard Worker } else {
1636*795d594fSAndroid Build Coastguard Worker Print32Zicsr(insn32);
1637*795d594fSAndroid Build Coastguard Worker }
1638*795d594fSAndroid Build Coastguard Worker break;
1639*795d594fSAndroid Build Coastguard Worker case 0x0fu:
1640*795d594fSAndroid Build Coastguard Worker Print32Fence(insn32);
1641*795d594fSAndroid Build Coastguard Worker break;
1642*795d594fSAndroid Build Coastguard Worker default:
1643*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Disassemble more instructions.
1644*795d594fSAndroid Build Coastguard Worker os_ << "<unknown32>";
1645*795d594fSAndroid Build Coastguard Worker break;
1646*795d594fSAndroid Build Coastguard Worker }
1647*795d594fSAndroid Build Coastguard Worker os_ << "\n";
1648*795d594fSAndroid Build Coastguard Worker }
1649*795d594fSAndroid Build Coastguard Worker
Dump16(const uint8_t * insn)1650*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Dump16(const uint8_t* insn) {
1651*795d594fSAndroid Build Coastguard Worker uint32_t insn16 = static_cast<uint32_t>(insn[0]) + (static_cast<uint32_t>(insn[1]) << 8);
1652*795d594fSAndroid Build Coastguard Worker ScopedNewLinePrinter nl(os_);
1653*795d594fSAndroid Build Coastguard Worker CHECK_NE(insn16 & 3u, 3u);
1654*795d594fSAndroid Build Coastguard Worker os_ << disassembler_->FormatInstructionPointer(insn) << StringPrintf(": %04x \t", insn16);
1655*795d594fSAndroid Build Coastguard Worker
1656*795d594fSAndroid Build Coastguard Worker uint32_t funct3 = BitFieldExtract(insn16, 13, 3);
1657*795d594fSAndroid Build Coastguard Worker int32_t offset = -1;
1658*795d594fSAndroid Build Coastguard Worker
1659*795d594fSAndroid Build Coastguard Worker switch (insn16 & 3u) {
1660*795d594fSAndroid Build Coastguard Worker case 0b00u: // Quadrant 0
1661*795d594fSAndroid Build Coastguard Worker switch (funct3) {
1662*795d594fSAndroid Build Coastguard Worker case 0b000u:
1663*795d594fSAndroid Build Coastguard Worker if (insn16 == 0u) {
1664*795d594fSAndroid Build Coastguard Worker os_ << "c.unimp";
1665*795d594fSAndroid Build Coastguard Worker } else {
1666*795d594fSAndroid Build Coastguard Worker uint32_t nzuimm = BitFieldExtract(insn16, 5, 8);
1667*795d594fSAndroid Build Coastguard Worker if (nzuimm != 0u) {
1668*795d594fSAndroid Build Coastguard Worker uint32_t decoded =
1669*795d594fSAndroid Build Coastguard Worker BitFieldExtract(nzuimm, 0, 1) << 3 | BitFieldExtract(nzuimm, 1, 1) << 2 |
1670*795d594fSAndroid Build Coastguard Worker BitFieldExtract(nzuimm, 2, 4) << 6 | BitFieldExtract(nzuimm, 6, 2) << 4;
1671*795d594fSAndroid Build Coastguard Worker os_ << "c.addi4spn " << XRegName(GetRs2Short16(insn16)) << ", sp, " << decoded;
1672*795d594fSAndroid Build Coastguard Worker } else {
1673*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1674*795d594fSAndroid Build Coastguard Worker }
1675*795d594fSAndroid Build Coastguard Worker }
1676*795d594fSAndroid Build Coastguard Worker return;
1677*795d594fSAndroid Build Coastguard Worker case 0b001u:
1678*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetD(insn16);
1679*795d594fSAndroid Build Coastguard Worker os_ << "c.fld " << FRegName(GetRs2Short16(insn16));
1680*795d594fSAndroid Build Coastguard Worker break;
1681*795d594fSAndroid Build Coastguard Worker case 0b010u:
1682*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetW(insn16);
1683*795d594fSAndroid Build Coastguard Worker os_ << "c.lw " << XRegName(GetRs2Short16(insn16));
1684*795d594fSAndroid Build Coastguard Worker break;
1685*795d594fSAndroid Build Coastguard Worker case 0b011u:
1686*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetD(insn16);
1687*795d594fSAndroid Build Coastguard Worker os_ << "c.ld " << XRegName(GetRs2Short16(insn16));
1688*795d594fSAndroid Build Coastguard Worker break;
1689*795d594fSAndroid Build Coastguard Worker case 0b100u: {
1690*795d594fSAndroid Build Coastguard Worker uint32_t opcode2 = BitFieldExtract(insn16, 10, 3);
1691*795d594fSAndroid Build Coastguard Worker uint32_t imm = BitFieldExtract(insn16, 5, 2);
1692*795d594fSAndroid Build Coastguard Worker switch (opcode2) {
1693*795d594fSAndroid Build Coastguard Worker case 0b000:
1694*795d594fSAndroid Build Coastguard Worker offset = Uimm2ToOffset10(imm);
1695*795d594fSAndroid Build Coastguard Worker os_ << "c.lbu " << XRegName(GetRs2Short16(insn16));
1696*795d594fSAndroid Build Coastguard Worker break;
1697*795d594fSAndroid Build Coastguard Worker case 0b001:
1698*795d594fSAndroid Build Coastguard Worker offset = Uimm2ToOffset1(imm);
1699*795d594fSAndroid Build Coastguard Worker os_ << (BitFieldExtract(imm, 1, 1) == 0u ? "c.lhu " : "c.lh ");
1700*795d594fSAndroid Build Coastguard Worker os_ << XRegName(GetRs2Short16(insn16));
1701*795d594fSAndroid Build Coastguard Worker break;
1702*795d594fSAndroid Build Coastguard Worker case 0b010:
1703*795d594fSAndroid Build Coastguard Worker offset = Uimm2ToOffset10(imm);
1704*795d594fSAndroid Build Coastguard Worker os_ << "c.sb " << XRegName(GetRs2Short16(insn16));
1705*795d594fSAndroid Build Coastguard Worker break;
1706*795d594fSAndroid Build Coastguard Worker case 0b011:
1707*795d594fSAndroid Build Coastguard Worker if (BitFieldExtract(imm, 1, 1) == 0u) {
1708*795d594fSAndroid Build Coastguard Worker offset = Uimm2ToOffset1(imm);
1709*795d594fSAndroid Build Coastguard Worker os_ << "c.sh " << XRegName(GetRs2Short16(insn16));
1710*795d594fSAndroid Build Coastguard Worker break;
1711*795d594fSAndroid Build Coastguard Worker }
1712*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
1713*795d594fSAndroid Build Coastguard Worker default:
1714*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1715*795d594fSAndroid Build Coastguard Worker return;
1716*795d594fSAndroid Build Coastguard Worker }
1717*795d594fSAndroid Build Coastguard Worker break;
1718*795d594fSAndroid Build Coastguard Worker }
1719*795d594fSAndroid Build Coastguard Worker case 0b101u:
1720*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetD(insn16);
1721*795d594fSAndroid Build Coastguard Worker os_ << "c.fsd " << FRegName(GetRs2Short16(insn16));
1722*795d594fSAndroid Build Coastguard Worker break;
1723*795d594fSAndroid Build Coastguard Worker case 0b110u:
1724*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetW(insn16);
1725*795d594fSAndroid Build Coastguard Worker os_ << "c.sw " << XRegName(GetRs2Short16(insn16));
1726*795d594fSAndroid Build Coastguard Worker break;
1727*795d594fSAndroid Build Coastguard Worker case 0b111u:
1728*795d594fSAndroid Build Coastguard Worker offset = Decode16CMOffsetD(insn16);
1729*795d594fSAndroid Build Coastguard Worker os_ << "c.sd " << XRegName(GetRs2Short16(insn16));
1730*795d594fSAndroid Build Coastguard Worker break;
1731*795d594fSAndroid Build Coastguard Worker default:
1732*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1733*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1734*795d594fSAndroid Build Coastguard Worker }
1735*795d594fSAndroid Build Coastguard Worker os_ << ", ";
1736*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(GetRs1Short16(insn16), offset);
1737*795d594fSAndroid Build Coastguard Worker return;
1738*795d594fSAndroid Build Coastguard Worker case 0b01u: // Quadrant 1
1739*795d594fSAndroid Build Coastguard Worker switch (funct3) {
1740*795d594fSAndroid Build Coastguard Worker case 0b000u: {
1741*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1742*795d594fSAndroid Build Coastguard Worker if (rd == 0) {
1743*795d594fSAndroid Build Coastguard Worker if (Decode16Imm6<uint32_t>(insn16) != 0u) {
1744*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1745*795d594fSAndroid Build Coastguard Worker } else {
1746*795d594fSAndroid Build Coastguard Worker os_ << "c.nop";
1747*795d594fSAndroid Build Coastguard Worker }
1748*795d594fSAndroid Build Coastguard Worker } else {
1749*795d594fSAndroid Build Coastguard Worker int32_t imm = Decode16Imm6<int32_t>(insn16);
1750*795d594fSAndroid Build Coastguard Worker if (imm != 0) {
1751*795d594fSAndroid Build Coastguard Worker os_ << "c.addi " << XRegName(rd) << ", " << imm;
1752*795d594fSAndroid Build Coastguard Worker } else {
1753*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1754*795d594fSAndroid Build Coastguard Worker }
1755*795d594fSAndroid Build Coastguard Worker }
1756*795d594fSAndroid Build Coastguard Worker break;
1757*795d594fSAndroid Build Coastguard Worker }
1758*795d594fSAndroid Build Coastguard Worker case 0b001u: {
1759*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1760*795d594fSAndroid Build Coastguard Worker if (rd != 0) {
1761*795d594fSAndroid Build Coastguard Worker os_ << "c.addiw " << XRegName(rd) << ", " << Decode16Imm6<int32_t>(insn16);
1762*795d594fSAndroid Build Coastguard Worker } else {
1763*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1764*795d594fSAndroid Build Coastguard Worker }
1765*795d594fSAndroid Build Coastguard Worker break;
1766*795d594fSAndroid Build Coastguard Worker }
1767*795d594fSAndroid Build Coastguard Worker case 0b010u: {
1768*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1769*795d594fSAndroid Build Coastguard Worker if (rd != 0) {
1770*795d594fSAndroid Build Coastguard Worker os_ << "c.li " << XRegName(rd) << ", " << Decode16Imm6<int32_t>(insn16);
1771*795d594fSAndroid Build Coastguard Worker } else {
1772*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1773*795d594fSAndroid Build Coastguard Worker }
1774*795d594fSAndroid Build Coastguard Worker break;
1775*795d594fSAndroid Build Coastguard Worker }
1776*795d594fSAndroid Build Coastguard Worker case 0b011u: {
1777*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1778*795d594fSAndroid Build Coastguard Worker uint32_t imm6_bits = Decode16Imm6<uint32_t>(insn16);
1779*795d594fSAndroid Build Coastguard Worker if (imm6_bits != 0u) {
1780*795d594fSAndroid Build Coastguard Worker if (rd == 2) {
1781*795d594fSAndroid Build Coastguard Worker int32_t nzimm =
1782*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 6, 1) << 4 | BitFieldExtract(insn16, 2, 1) << 5 |
1783*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 5, 1) << 6 | BitFieldExtract(insn16, 3, 2) << 7 |
1784*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 12, 1) << 9;
1785*795d594fSAndroid Build Coastguard Worker os_ << "c.addi16sp sp, " << SignExtendBits<10>(nzimm);
1786*795d594fSAndroid Build Coastguard Worker } else if (rd != 0) {
1787*795d594fSAndroid Build Coastguard Worker // sign-extend bits and mask with 0xfffff as llvm-objdump does
1788*795d594fSAndroid Build Coastguard Worker uint32_t mask = MaskLeastSignificant<uint32_t>(20);
1789*795d594fSAndroid Build Coastguard Worker os_ << "c.lui " << XRegName(rd) << ", " << (SignExtendBits<6>(imm6_bits) & mask);
1790*795d594fSAndroid Build Coastguard Worker } else {
1791*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1792*795d594fSAndroid Build Coastguard Worker }
1793*795d594fSAndroid Build Coastguard Worker } else {
1794*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1795*795d594fSAndroid Build Coastguard Worker }
1796*795d594fSAndroid Build Coastguard Worker break;
1797*795d594fSAndroid Build Coastguard Worker }
1798*795d594fSAndroid Build Coastguard Worker case 0b100u: {
1799*795d594fSAndroid Build Coastguard Worker uint32_t funct2 = BitFieldExtract(insn16, 10, 2);
1800*795d594fSAndroid Build Coastguard Worker switch (funct2) {
1801*795d594fSAndroid Build Coastguard Worker case 0b00: {
1802*795d594fSAndroid Build Coastguard Worker int32_t nzuimm = Decode16Imm6<uint32_t>(insn16);
1803*795d594fSAndroid Build Coastguard Worker if (nzuimm != 0) {
1804*795d594fSAndroid Build Coastguard Worker os_ << "c.srli " << XRegName(GetRs1Short16(insn16)) << ", " << nzuimm;
1805*795d594fSAndroid Build Coastguard Worker } else {
1806*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1807*795d594fSAndroid Build Coastguard Worker }
1808*795d594fSAndroid Build Coastguard Worker break;
1809*795d594fSAndroid Build Coastguard Worker }
1810*795d594fSAndroid Build Coastguard Worker case 0b01: {
1811*795d594fSAndroid Build Coastguard Worker int32_t nzuimm = Decode16Imm6<uint32_t>(insn16);
1812*795d594fSAndroid Build Coastguard Worker if (nzuimm != 0) {
1813*795d594fSAndroid Build Coastguard Worker os_ << "c.srai " << XRegName(GetRs1Short16(insn16)) << ", " << nzuimm;
1814*795d594fSAndroid Build Coastguard Worker } else {
1815*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1816*795d594fSAndroid Build Coastguard Worker }
1817*795d594fSAndroid Build Coastguard Worker break;
1818*795d594fSAndroid Build Coastguard Worker }
1819*795d594fSAndroid Build Coastguard Worker case 0b10:
1820*795d594fSAndroid Build Coastguard Worker os_ << "c.andi " << XRegName(GetRs1Short16(insn16)) << ", "
1821*795d594fSAndroid Build Coastguard Worker << Decode16Imm6<int32_t>(insn16);
1822*795d594fSAndroid Build Coastguard Worker break;
1823*795d594fSAndroid Build Coastguard Worker case 0b11: {
1824*795d594fSAndroid Build Coastguard Worker constexpr static const char* mnemonics[] = {
1825*795d594fSAndroid Build Coastguard Worker "c.sub", "c.xor", "c.or", "c.and", "c.subw", "c.addw", "c.mul", nullptr
1826*795d594fSAndroid Build Coastguard Worker };
1827*795d594fSAndroid Build Coastguard Worker uint32_t opc = BitFieldInsert(
1828*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 5, 2), BitFieldExtract(insn16, 12, 1), 2, 1);
1829*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<3>(opc));
1830*795d594fSAndroid Build Coastguard Worker const char* mnem = mnemonics[opc];
1831*795d594fSAndroid Build Coastguard Worker if (mnem != nullptr) {
1832*795d594fSAndroid Build Coastguard Worker os_ << mnem << " " << XRegName(GetRs1Short16(insn16)) << ", "
1833*795d594fSAndroid Build Coastguard Worker << XRegName(GetRs2Short16(insn16));
1834*795d594fSAndroid Build Coastguard Worker } else {
1835*795d594fSAndroid Build Coastguard Worker constexpr static const char* zbc_mnemonics[] = {
1836*795d594fSAndroid Build Coastguard Worker "c.zext.b", "c.sext.b", "c.zext.h", "c.sext.h",
1837*795d594fSAndroid Build Coastguard Worker "c.zext.w", "c.not", nullptr, nullptr,
1838*795d594fSAndroid Build Coastguard Worker };
1839*795d594fSAndroid Build Coastguard Worker mnem = zbc_mnemonics[BitFieldExtract(insn16, 2, 3)];
1840*795d594fSAndroid Build Coastguard Worker if (mnem != nullptr) {
1841*795d594fSAndroid Build Coastguard Worker os_ << mnem << " " << XRegName(GetRs1Short16(insn16));
1842*795d594fSAndroid Build Coastguard Worker } else {
1843*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1844*795d594fSAndroid Build Coastguard Worker }
1845*795d594fSAndroid Build Coastguard Worker }
1846*795d594fSAndroid Build Coastguard Worker break;
1847*795d594fSAndroid Build Coastguard Worker }
1848*795d594fSAndroid Build Coastguard Worker default:
1849*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1850*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1851*795d594fSAndroid Build Coastguard Worker }
1852*795d594fSAndroid Build Coastguard Worker break;
1853*795d594fSAndroid Build Coastguard Worker }
1854*795d594fSAndroid Build Coastguard Worker case 0b101u: {
1855*795d594fSAndroid Build Coastguard Worker int32_t disp = BitFieldExtract(insn16, 3, 3) << 1 | BitFieldExtract(insn16, 11, 1) << 4 |
1856*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 2, 1) << 5 | BitFieldExtract(insn16, 7, 1) << 6 |
1857*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 6, 1) << 7 | BitFieldExtract(insn16, 9, 2) << 8 |
1858*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 8, 1) << 10 | BitFieldExtract(insn16, 12, 1) << 11;
1859*795d594fSAndroid Build Coastguard Worker os_ << "c.j ";
1860*795d594fSAndroid Build Coastguard Worker PrintBranchOffset(SignExtendBits<12>(disp));
1861*795d594fSAndroid Build Coastguard Worker break;
1862*795d594fSAndroid Build Coastguard Worker }
1863*795d594fSAndroid Build Coastguard Worker case 0b110u:
1864*795d594fSAndroid Build Coastguard Worker case 0b111u: {
1865*795d594fSAndroid Build Coastguard Worker int32_t disp = BitFieldExtract(insn16, 3, 2) << 1 | BitFieldExtract(insn16, 10, 2) << 3 |
1866*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 2, 1) << 5 | BitFieldExtract(insn16, 5, 2) << 6 |
1867*795d594fSAndroid Build Coastguard Worker BitFieldExtract(insn16, 12, 1) << 8;
1868*795d594fSAndroid Build Coastguard Worker
1869*795d594fSAndroid Build Coastguard Worker os_ << (funct3 == 0b110u ? "c.beqz " : "c.bnez ");
1870*795d594fSAndroid Build Coastguard Worker os_ << XRegName(GetRs1Short16(insn16)) << ", ";
1871*795d594fSAndroid Build Coastguard Worker PrintBranchOffset(SignExtendBits<9>(disp));
1872*795d594fSAndroid Build Coastguard Worker break;
1873*795d594fSAndroid Build Coastguard Worker }
1874*795d594fSAndroid Build Coastguard Worker default:
1875*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1876*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1877*795d594fSAndroid Build Coastguard Worker }
1878*795d594fSAndroid Build Coastguard Worker break;
1879*795d594fSAndroid Build Coastguard Worker case 0b10u: // Quadrant 2
1880*795d594fSAndroid Build Coastguard Worker switch (funct3) {
1881*795d594fSAndroid Build Coastguard Worker case 0b000u: {
1882*795d594fSAndroid Build Coastguard Worker uint32_t nzuimm = Decode16Imm6<uint32_t>(insn16);
1883*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1884*795d594fSAndroid Build Coastguard Worker if (rd == 0 || nzuimm == 0) {
1885*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1886*795d594fSAndroid Build Coastguard Worker } else {
1887*795d594fSAndroid Build Coastguard Worker os_ << "c.slli " << XRegName(rd) << ", " << nzuimm;
1888*795d594fSAndroid Build Coastguard Worker }
1889*795d594fSAndroid Build Coastguard Worker return;
1890*795d594fSAndroid Build Coastguard Worker }
1891*795d594fSAndroid Build Coastguard Worker case 0b001u: {
1892*795d594fSAndroid Build Coastguard Worker offset = Uimm6ToOffsetD16(Decode16Imm6<uint32_t>(insn16));
1893*795d594fSAndroid Build Coastguard Worker os_ << "c.fldsp " << FRegName(GetRs1_16(insn16));
1894*795d594fSAndroid Build Coastguard Worker break;
1895*795d594fSAndroid Build Coastguard Worker }
1896*795d594fSAndroid Build Coastguard Worker case 0b010u: {
1897*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1898*795d594fSAndroid Build Coastguard Worker if (rd != 0) {
1899*795d594fSAndroid Build Coastguard Worker offset = Uimm6ToOffsetW16(Decode16Imm6<uint32_t>(insn16));
1900*795d594fSAndroid Build Coastguard Worker os_ << "c.lwsp " << XRegName(GetRs1_16(insn16));
1901*795d594fSAndroid Build Coastguard Worker } else {
1902*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1903*795d594fSAndroid Build Coastguard Worker return;
1904*795d594fSAndroid Build Coastguard Worker }
1905*795d594fSAndroid Build Coastguard Worker break;
1906*795d594fSAndroid Build Coastguard Worker }
1907*795d594fSAndroid Build Coastguard Worker case 0b011u: {
1908*795d594fSAndroid Build Coastguard Worker uint32_t rd = GetRs1_16(insn16);
1909*795d594fSAndroid Build Coastguard Worker if (rd != 0) {
1910*795d594fSAndroid Build Coastguard Worker offset = Uimm6ToOffsetD16(Decode16Imm6<uint32_t>(insn16));
1911*795d594fSAndroid Build Coastguard Worker os_ << "c.ldsp " << XRegName(GetRs1_16(insn16));
1912*795d594fSAndroid Build Coastguard Worker } else {
1913*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1914*795d594fSAndroid Build Coastguard Worker return;
1915*795d594fSAndroid Build Coastguard Worker }
1916*795d594fSAndroid Build Coastguard Worker break;
1917*795d594fSAndroid Build Coastguard Worker }
1918*795d594fSAndroid Build Coastguard Worker case 0b100u: {
1919*795d594fSAndroid Build Coastguard Worker uint32_t rd_rs1 = GetRs1_16(insn16);
1920*795d594fSAndroid Build Coastguard Worker uint32_t rs2 = GetRs2_16(insn16);
1921*795d594fSAndroid Build Coastguard Worker uint32_t b12 = BitFieldExtract(insn16, 12, 1);
1922*795d594fSAndroid Build Coastguard Worker if (b12 == 0) {
1923*795d594fSAndroid Build Coastguard Worker if (rd_rs1 != 0 && rs2 != 0) {
1924*795d594fSAndroid Build Coastguard Worker os_ << "c.mv " << XRegName(rd_rs1) << ", " << XRegName(rs2);
1925*795d594fSAndroid Build Coastguard Worker } else if (rd_rs1 != 0) {
1926*795d594fSAndroid Build Coastguard Worker os_ << "c.jr " << XRegName(rd_rs1);
1927*795d594fSAndroid Build Coastguard Worker } else if (rs2 != 0) {
1928*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1929*795d594fSAndroid Build Coastguard Worker } else {
1930*795d594fSAndroid Build Coastguard Worker os_ << "<unknown16>";
1931*795d594fSAndroid Build Coastguard Worker }
1932*795d594fSAndroid Build Coastguard Worker } else {
1933*795d594fSAndroid Build Coastguard Worker if (rd_rs1 != 0 && rs2 != 0) {
1934*795d594fSAndroid Build Coastguard Worker os_ << "c.add " << XRegName(rd_rs1) << ", " << XRegName(rs2);
1935*795d594fSAndroid Build Coastguard Worker } else if (rd_rs1 != 0) {
1936*795d594fSAndroid Build Coastguard Worker os_ << "c.jalr " << XRegName(rd_rs1);
1937*795d594fSAndroid Build Coastguard Worker } else if (rs2 != 0) {
1938*795d594fSAndroid Build Coastguard Worker os_ << "<hint16>";
1939*795d594fSAndroid Build Coastguard Worker } else {
1940*795d594fSAndroid Build Coastguard Worker os_ << "c.ebreak";
1941*795d594fSAndroid Build Coastguard Worker }
1942*795d594fSAndroid Build Coastguard Worker }
1943*795d594fSAndroid Build Coastguard Worker return;
1944*795d594fSAndroid Build Coastguard Worker }
1945*795d594fSAndroid Build Coastguard Worker case 0b101u:
1946*795d594fSAndroid Build Coastguard Worker offset = BitFieldExtract(insn16, 7, 3) << 6 | BitFieldExtract(insn16, 10, 3) << 3;
1947*795d594fSAndroid Build Coastguard Worker os_ << "c.fsdsp " << FRegName(GetRs2_16(insn16));
1948*795d594fSAndroid Build Coastguard Worker break;
1949*795d594fSAndroid Build Coastguard Worker case 0b110u:
1950*795d594fSAndroid Build Coastguard Worker offset = BitFieldExtract(insn16, 7, 2) << 6 | BitFieldExtract(insn16, 9, 4) << 2;
1951*795d594fSAndroid Build Coastguard Worker os_ << "c.swsp " << XRegName(GetRs2_16(insn16));
1952*795d594fSAndroid Build Coastguard Worker break;
1953*795d594fSAndroid Build Coastguard Worker case 0b111u:
1954*795d594fSAndroid Build Coastguard Worker offset = BitFieldExtract(insn16, 7, 3) << 6 | BitFieldExtract(insn16, 10, 3) << 3;
1955*795d594fSAndroid Build Coastguard Worker os_ << "c.sdsp " << XRegName(GetRs2_16(insn16));
1956*795d594fSAndroid Build Coastguard Worker break;
1957*795d594fSAndroid Build Coastguard Worker default:
1958*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1959*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1960*795d594fSAndroid Build Coastguard Worker }
1961*795d594fSAndroid Build Coastguard Worker
1962*795d594fSAndroid Build Coastguard Worker os_ << ", ";
1963*795d594fSAndroid Build Coastguard Worker PrintLoadStoreAddress(/* sp */ 2, offset);
1964*795d594fSAndroid Build Coastguard Worker
1965*795d594fSAndroid Build Coastguard Worker break;
1966*795d594fSAndroid Build Coastguard Worker default:
1967*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1968*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1969*795d594fSAndroid Build Coastguard Worker }
1970*795d594fSAndroid Build Coastguard Worker }
1971*795d594fSAndroid Build Coastguard Worker
Dump2Byte(const uint8_t * data)1972*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::Dump2Byte(const uint8_t* data) {
1973*795d594fSAndroid Build Coastguard Worker uint32_t value = data[0] + (data[1] << 8);
1974*795d594fSAndroid Build Coastguard Worker os_ << disassembler_->FormatInstructionPointer(data)
1975*795d594fSAndroid Build Coastguard Worker << StringPrintf(": %04x \t.2byte %u\n", value, value);
1976*795d594fSAndroid Build Coastguard Worker }
1977*795d594fSAndroid Build Coastguard Worker
DumpByte(const uint8_t * data)1978*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Printer::DumpByte(const uint8_t* data) {
1979*795d594fSAndroid Build Coastguard Worker uint32_t value = *data;
1980*795d594fSAndroid Build Coastguard Worker os_ << disassembler_->FormatInstructionPointer(data)
1981*795d594fSAndroid Build Coastguard Worker << StringPrintf(": %02x \t.byte %u\n", value, value);
1982*795d594fSAndroid Build Coastguard Worker }
1983*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,const uint8_t * begin)1984*795d594fSAndroid Build Coastguard Worker size_t DisassemblerRiscv64::Dump(std::ostream& os, const uint8_t* begin) {
1985*795d594fSAndroid Build Coastguard Worker if (begin < GetDisassemblerOptions()->base_address_ ||
1986*795d594fSAndroid Build Coastguard Worker begin >= GetDisassemblerOptions()->end_address_) {
1987*795d594fSAndroid Build Coastguard Worker return 0u; // Outside the range.
1988*795d594fSAndroid Build Coastguard Worker }
1989*795d594fSAndroid Build Coastguard Worker Printer printer(this, os);
1990*795d594fSAndroid Build Coastguard Worker if (!IsAligned<2u>(begin) || GetDisassemblerOptions()->end_address_ - begin == 1) {
1991*795d594fSAndroid Build Coastguard Worker printer.DumpByte(begin);
1992*795d594fSAndroid Build Coastguard Worker return 1u;
1993*795d594fSAndroid Build Coastguard Worker }
1994*795d594fSAndroid Build Coastguard Worker if ((*begin & 3u) == 3u) {
1995*795d594fSAndroid Build Coastguard Worker if (GetDisassemblerOptions()->end_address_ - begin >= 4) {
1996*795d594fSAndroid Build Coastguard Worker printer.Dump32(begin);
1997*795d594fSAndroid Build Coastguard Worker return 4u;
1998*795d594fSAndroid Build Coastguard Worker } else {
1999*795d594fSAndroid Build Coastguard Worker printer.Dump2Byte(begin);
2000*795d594fSAndroid Build Coastguard Worker return 2u;
2001*795d594fSAndroid Build Coastguard Worker }
2002*795d594fSAndroid Build Coastguard Worker } else {
2003*795d594fSAndroid Build Coastguard Worker printer.Dump16(begin);
2004*795d594fSAndroid Build Coastguard Worker return 2u;
2005*795d594fSAndroid Build Coastguard Worker }
2006*795d594fSAndroid Build Coastguard Worker }
2007*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,const uint8_t * begin,const uint8_t * end)2008*795d594fSAndroid Build Coastguard Worker void DisassemblerRiscv64::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
2009*795d594fSAndroid Build Coastguard Worker Printer printer(this, os);
2010*795d594fSAndroid Build Coastguard Worker const uint8_t* cur = begin;
2011*795d594fSAndroid Build Coastguard Worker if (cur < end && !IsAligned<2u>(cur)) {
2012*795d594fSAndroid Build Coastguard Worker // Unaligned, dump as a `.byte` to get to an aligned address.
2013*795d594fSAndroid Build Coastguard Worker printer.DumpByte(cur);
2014*795d594fSAndroid Build Coastguard Worker cur += 1;
2015*795d594fSAndroid Build Coastguard Worker }
2016*795d594fSAndroid Build Coastguard Worker if (cur >= end) {
2017*795d594fSAndroid Build Coastguard Worker return;
2018*795d594fSAndroid Build Coastguard Worker }
2019*795d594fSAndroid Build Coastguard Worker while (end - cur >= 4) {
2020*795d594fSAndroid Build Coastguard Worker if ((*cur & 3u) == 3u) {
2021*795d594fSAndroid Build Coastguard Worker printer.Dump32(cur);
2022*795d594fSAndroid Build Coastguard Worker cur += 4;
2023*795d594fSAndroid Build Coastguard Worker } else {
2024*795d594fSAndroid Build Coastguard Worker printer.Dump16(cur);
2025*795d594fSAndroid Build Coastguard Worker cur += 2;
2026*795d594fSAndroid Build Coastguard Worker }
2027*795d594fSAndroid Build Coastguard Worker }
2028*795d594fSAndroid Build Coastguard Worker if (end - cur >= 2) {
2029*795d594fSAndroid Build Coastguard Worker if ((*cur & 3u) == 3u) {
2030*795d594fSAndroid Build Coastguard Worker // Not enough data for a 32-bit instruction. Dump as `.2byte`.
2031*795d594fSAndroid Build Coastguard Worker printer.Dump2Byte(cur);
2032*795d594fSAndroid Build Coastguard Worker } else {
2033*795d594fSAndroid Build Coastguard Worker printer.Dump16(cur);
2034*795d594fSAndroid Build Coastguard Worker }
2035*795d594fSAndroid Build Coastguard Worker cur += 2;
2036*795d594fSAndroid Build Coastguard Worker }
2037*795d594fSAndroid Build Coastguard Worker if (end != cur) {
2038*795d594fSAndroid Build Coastguard Worker CHECK_EQ(end - cur, 1);
2039*795d594fSAndroid Build Coastguard Worker printer.DumpByte(cur);
2040*795d594fSAndroid Build Coastguard Worker }
2041*795d594fSAndroid Build Coastguard Worker }
2042*795d594fSAndroid Build Coastguard Worker
2043*795d594fSAndroid Build Coastguard Worker } // namespace riscv64
2044*795d594fSAndroid Build Coastguard Worker } // namespace art
2045