1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_DECODER_RISCV64_DECODER_H_
18 #define BERBERIS_DECODER_RISCV64_DECODER_H_
19 
20 #include <climits>
21 #include <cstdint>
22 #include <cstring>
23 #include <type_traits>
24 
25 #include "berberis/base/bit_util.h"
26 #include "berberis/base/checks.h"
27 
28 namespace berberis {
29 
30 // Decode() method takes a sequence of bytes and decodes it into the instruction opcode and fields.
31 // The InsnConsumer's method corresponding to the decoded opcode is called with the decoded fields
32 // as an argument. Returned is the instruction size.
33 template <class InsnConsumer>
34 class Decoder {
35  public:
Decoder(InsnConsumer * insn_consumer)36   explicit Decoder(InsnConsumer* insn_consumer) : insn_consumer_(insn_consumer) {}
37 
38   // https://eel.is/c++draft/enum#dcl.enum-8
39   // For an enumeration whose underlying type is fixed, the values of the enumeration are the values
40   // of the underlying type.
41 
42   // To ensure that there are no surprises we specify that type in all enums below.
43 
44   enum class AmoOpcode : uint8_t {
45     kLr = 0b00010,
46     kSc = 0b00011,
47     kAmoswap = 0b00001,
48     kAmoadd = 0b00000,
49     kAmoxor = 0b00100,
50     kAmoand = 0b01100,
51     kAmoor = 0b01000,
52     kAmomin = 0b10000,
53     kAmomax = 0b10100,
54     kAmominu = 0b11000,
55     kAmomaxu = 0b11100,
56   };
57 
58   enum class BranchOpcode : uint8_t {
59     kBeq = 0b000,
60     kBne = 0b001,
61     kBlt = 0b100,
62     kBge = 0b101,
63     kBltu = 0b110,
64     kBgeu = 0b111,
65   };
66 
67   enum class CsrOpcode : uint8_t {
68     kCsrrw = 0b01,
69     kCsrrs = 0b10,
70     kCsrrc = 0b11,
71   };
72 
73   enum class CsrImmOpcode : uint8_t {
74     kCsrrwi = 0b01,
75     kCsrrsi = 0b10,
76     kCsrrci = 0b11,
77   };
78 
79   enum class FmaOpcode : uint8_t {
80     kFmadd = 0b00,
81     kFmsub = 0b01,
82     kFnmsub = 0b10,
83     kFnmadd = 0b11,
84   };
85 
86   enum class FenceOpcode : uint8_t {
87     kFence = 0b0000,
88     kFenceTso = 0b1000,
89   };
90 
91   enum class OpOpcode : uint16_t {
92     kAdd = 0b0000'000'000,
93     kSub = 0b0100'000'000,
94     kSll = 0b0000'000'001,
95     kSlt = 0b0000'000'010,
96     kSltu = 0b0000'000'011,
97     kXor = 0b0000'000'100,
98     kSrl = 0b0000'000'101,
99     kSra = 0b0100'000'101,
100     kOr = 0b0000'000'110,
101     kAnd = 0b0000'000'111,
102     kMul = 0b0000'001'000,
103     kMulh = 0b0000'001'001,
104     kMulhsu = 0b0000'001'010,
105     kMulhu = 0b0000'001'011,
106     kDiv = 0b0000'001'100,
107     kDivu = 0b0000'001'101,
108     kRem = 0b0000'001'110,
109     kRemu = 0b0000'001'111,
110     kAndn = 0b0100'000'111,
111     kOrn = 0b0100'000'110,
112     kXnor = 0b0100'000'100,
113     kMax = 0b0000'101'110,
114     kMaxu = 0b0000'101'111,
115     kMin = 0b0000'101'100,
116     kMinu = 0b0000'101'101,
117     kRol = 0b0110'000'001,
118     kRor = 0b0110'000'101,
119     kSh1add = 0b0010'000'010,
120     kSh2add = 0b0010'000'100,
121     kSh3add = 0b0010'000'110,
122     kBclr = 0b0100'100'001,
123     kBext = 0b0100'100'101,
124     kBinv = 0b0110'100'001,
125     kBset = 0b0010'100'001,
126   };
127 
128   enum class Op32Opcode : uint16_t {
129     kAddw = 0b0000'000'000,
130     kAdduw = 0b0000'100'000,
131     kSubw = 0b0100'000'000,
132     kSllw = 0b0000'000'001,
133     kSrlw = 0b0000'000'101,
134     kSraw = 0b0100'000'101,
135     kMulw = 0b0000'001'000,
136     kDivw = 0b0000'001'100,
137     kDivuw = 0b0000'001'101,
138     kRemw = 0b0000'001'110,
139     kRemuw = 0b0000'001'111,
140     kRolw = 0b0110'000'001,
141     kRorw = 0b0110'000'101,
142     kSh1adduw = 0b0010'000'010,
143     kSh2adduw = 0b0010'000'100,
144     kSh3adduw = 0b0010'000'110,
145   };
146 
147   enum class OpSingleInputOpcode : uint16_t {
148     kZexth = 0b0000'100'100,
149     kZextb,
150     kZextw,
151     kSextb,
152     kSexth,
153   };
154 
155   enum class OpFpGpRegisterTargetNoRoundingOpcode : uint8_t {
156     kFle = 0b00'000,
157     kFlt = 0b00'001,
158     kFeq = 0b00'010,
159   };
160 
161   enum class OpFpGpRegisterTargetSingleInputNoRoundingOpcode : uint16_t {
162     kFclass = 0b00'00000'001,
163   };
164 
165   enum class OpFpNoRoundingOpcode : uint8_t {
166     kFSgnj = 0b00'000,
167     kFSgnjn = 0b00'001,
168     kFSgnjx = 0b00'010,
169     kFMin = 0b01'000,
170     kFMax = 0b01'001,
171   };
172 
173   enum class OpFpOpcode : uint8_t {
174     kFAdd = 0b00,
175     kFSub = 0b01,
176     kFMul = 0b10,
177     kFDiv = 0b11,
178   };
179 
180   enum class OpFpSingleInputOpcode : uint8_t {
181     kFSqrt = 0b11'00000,
182   };
183 
184   enum class OpFpSingleInputNoRoundingOpcode : uint8_t {
185     kFmv,
186   };
187 
188   enum class OpImmOpcode : uint8_t {
189     kAddi = 0b000,
190     kSlti = 0b010,
191     kSltiu = 0b011,
192     kXori = 0b100,
193     kOri = 0b110,
194     kAndi = 0b111,
195   };
196 
197   enum class OpImm32Opcode : uint8_t {
198     kAddiw = 0b000,
199   };
200 
201   enum class ShiftImmOpcode : uint8_t {
202     kSlli = 0b000000'001,
203     kSrli = 0b000000'101,
204     kSrai = 0b010000'101,
205   };
206 
207   enum class ShiftImm32Opcode : uint16_t {
208     kSlliw = 0b0000000'001,
209     kSrliw = 0b0000000'101,
210     kSraiw = 0b0100000'101,
211   };
212 
213   enum class BitmanipImmOpcode : uint16_t {
214     kClz = 0b0110000'00000'001,
215     kCpop = 0b0110000'00010'001,
216     kCtz = 0b0110000'00001'001,
217     kSextb = 0b0110000'00100'001,
218     kSexth = 0b0110000'00101'001,
219     kOrcb = 0b0010100'00111'101,
220     kRev8 = 0b0110101'11000'101,
221     kRori = 0b011000'101,
222     kBclri = 0b010010'001,
223     kBexti = 0b010010'101,
224     kBinvi = 0b011010'001,
225     kBseti = 0b001010'001,
226   };
227 
228   enum class BitmanipImm32Opcode : uint16_t {
229     kClzw = 0b0110000'00000'001,
230     kCpopw = 0b0110000'00010'001,
231     kCtzw = 0b0110000'00001'001,
232     kRoriw = 0b0110000'101,
233     kSlliuw = 0b0000100'001,
234   };
235 
236   enum class SystemOpcode : uint32_t {
237     kEcall = 0b000000000000'00000'000'00000,
238     kEbreak = 0b000000000001'00000'000'00000,
239   };
240 
241   enum class VLUmOpOpcode : uint8_t {
242     kVleXX = 0b00000,
243     kVlXreXX = 0b01000,
244     kVleXXff = 0b10000,
245     kVlm = 0b01011,
246   };
247 
248   enum class VOpFVfOpcode : uint8_t {
249     kVfaddvf = 0b000000,
250     kVfsubvf = 0b000010,
251     kVfminvf = 0b000100,
252     kVfmaxvf = 0b000110,
253     kVfsgnjvf = 0b001000,
254     kVfsgnjnvf = 0b001001,
255     kVfsgnjxvf = 0b001010,
256     kVfslide1upvf = 0b001110,
257     kVfslide1downvf = 0b001111,
258     kVfmvsf = 0b010000,
259     kVfmergevf = 0b010111,  // Also kVfmv.vf
260     kVmfeqvf = 0b011000,
261     kVmflevf = 0b011001,
262     kVmfltvf = 0b011011,
263     kVmfnevf = 0b011100,
264     kVmfgtvf = 0b011101,
265     kVmfgevf = 0b011111,
266     kVfdivvf = 0b100000,
267     kVfrdivvf = 0b100001,
268     kVfmulvf = 0b100100,
269     kVfrsubvf = 0b100111,
270     kVfmaddvf = 0b101000,
271     kVfnmaddvf = 0b101001,
272     kVfmsubvf = 0b101010,
273     kVfnmsubvf = 0b101011,
274     kVfmaccvf = 0b101100,
275     kVfnmaccvf = 0b101101,
276     kVfmsacvf = 0b101110,
277     kVfnmsacvf = 0b101111,
278     kVfwaddvf = 0b110000,
279     kVfwsubvf = 0b110010,
280     kVfwaddwf = 0b110100,
281     kVfwsubwf = 0b110110,
282     kVfwmulvf = 0b111000,
283     kVfwmaccvf = 0b111100,
284     kVfwnmaccvf = 0b111101,
285     kVfwmsacvf = 0b111110,
286     kVfwnmsacvf = 0b111111,
287   };
288 
289   enum class VOpFVvOpcode : uint8_t {
290     kVfaddvv = 0b000000,
291     kVfredusumvs = 0b000001,
292     kVfsubvv = 0b000010,
293     kVfredosumvs = 0b000011,
294     kVfminvv = 0b000100,
295     kVfredminvs = 0b000101,
296     kVfmaxvv = 0b000110,
297     kVfredmaxvs = 0b000111,
298     kVfsgnjvv = 0b001000,
299     kVfsgnjnvv = 0b001001,
300     kVfsgnjxvv = 0b001010,
301     kVfmvfs = 0b010000,
302     kVFUnary0 = 0b010010,
303     kVFUnary1 = 0b010011,
304     kVmfeqvv = 0b011000,
305     kVmflevv = 0b011001,
306     kVmfltvv = 0b011011,
307     kVmfnevv = 0b011100,
308     kVfdivvv = 0b100000,
309     kVfmulvv = 0b100100,
310     kVfmaddvv = 0b101000,
311     kVfnmaddvv = 0b101001,
312     kVfmsubvv = 0b101010,
313     kVfnmsubvv = 0b101011,
314     kVfmaccvv = 0b101100,
315     kVfnmaccvv = 0b101101,
316     kVfmsacvv = 0b101110,
317     kVfnmsacvv = 0b101111,
318     kVfwaddvv = 0b110000,
319     kVfwredusumvs = 0b110001,
320     kVfwsubvv = 0b110010,
321     kVfwredosumvs = 0b110011,
322     kVfwaddwv = 0b110100,
323     kVfwsubwv = 0b110110,
324     kVfwmulvv = 0b111000,
325     kVfwmaccvv = 0b111100,
326     kVfwnmaccvv = 0b111101,
327     kVfwmsacvv = 0b111110,
328     kVfwnmsacvv = 0b111111,
329   };
330 
331   enum class VOpIViOpcode : uint8_t {
332     kVaddvi = 0b000000,
333     kVrsubvi = 0b000011,
334     kVandvi = 0b001001,
335     kVorvi = 0b001010,
336     kVxorvi = 0b001011,
337     kVrgathervi = 0b001100,
338     kVslideupvi = 0b001110,
339     kVslidedownvi = 0b001111,
340     kVadcvi = 0b010000,
341     kVmadcvi = 0b010001,
342     kVmergevi = 0b010111,  // Also kVmv.vi
343     kVmseqvi = 0b011000,
344     kVmsnevi = 0b011001,
345     kVmsleuvi = 0b011100,
346     kVmslevi = 0b011101,
347     kVmsgtuvi = 0b011110,
348     kVmsgtvi = 0b011111,
349     kVsadduvi = 0b100000,
350     kVsaddvi = 0b100001,
351     kVsllvi = 0b100101,
352     kVmvXrv = 0b100111,
353     kVsrlvi = 0b101000,
354     kVsravi = 0b101001,
355     kVssrlvi = 0b101010,
356     kVssravi = 0b101011,
357     kVnsrlwi = 0b101100,
358     kVnsrawi = 0b101101,
359     kVnclipuwi = 0b101110,
360     kVnclipwi = 0b101111,
361   };
362 
363   enum class VOpIVvOpcode : uint8_t {
364     kVaddvv = 0b000000,
365     kVsubvv = 0b000010,
366     kVminuvv = 0b000100,
367     kVminvv = 0b000101,
368     kVmaxuvv = 0b000110,
369     kVmaxvv = 0b000111,
370     kVandvv = 0b001001,
371     kVorvv = 0b001010,
372     kVxorvv = 0b001011,
373     kVrgathervv = 0b001100,
374     kVrgatherei16vv = 0b001110,
375     kVadcvv = 0b010000,
376     kVmadcvv = 0b010001,
377     kVsbcvv = 0b010010,
378     kVmsbcvv = 0b010011,
379     kVmergevv = 0b010111,  // Also kVmv.vv
380     kVmseqvv = 0b011000,
381     kVmsnevv = 0b011001,
382     kVmsltuvv = 0b011010,
383     kVmsltvv = 0b011011,
384     kVmsleuvv = 0b011100,
385     kVmslevv = 0b011101,
386     kVsadduvv = 0b100000,
387     kVsaddvv = 0b100001,
388     kVssubuvv = 0b100010,
389     kVssubvv = 0b100011,
390     kVsllvv = 0b100101,
391     kVsmulvv = 0b100111,
392     kVsrlvv = 0b101000,
393     kVsravv = 0b101001,
394     kVssrlvv = 0b101010,
395     kVssravv = 0b101011,
396     kVnsrlwv = 0b101100,
397     kVnsrawv = 0b101101,
398     kVnclipuwv = 0b101110,
399     kVnclipwv = 0b101111,
400     kVwredsumuvs = 0b110000,
401     kVwredsumvs = 0b110001,
402   };
403 
404   enum class VOpIVxOpcode : uint8_t {
405     kVaddvx = 0b000000,
406     kVsubvx = 0b000010,
407     kVrsubvx = 0b000011,
408     kVminuvx = 0b000100,
409     kVminvx = 0b000101,
410     kVmaxuvx = 0b000110,
411     kVmaxvx = 0b000111,
412     kVandvx = 0b001001,
413     kVorvx = 0b001010,
414     kVxorvx = 0b001011,
415     kVrgathervx = 0b001100,
416     kVslideupvx = 0b001110,
417     kVslidedownvx = 0b001111,
418     kVadcvx = 0b010000,
419     kVmadcvx = 0b010001,
420     kVsbcvx = 0b010010,
421     kVmsbcvx = 0b010011,
422     kVmergevx = 0b010111,  // Also Vmv.vx
423     kVmseqvx = 0b011000,
424     kVmsnevx = 0b011001,
425     kVmsltuvx = 0b011010,
426     kVmsltvx = 0b011011,
427     kVmsleuvx = 0b011100,
428     kVmslevx = 0b011101,
429     kVmsgtuvx = 0b011110,
430     kVmsgtvx = 0b011111,
431     kVsadduvx = 0b100000,
432     kVsaddvx = 0b100001,
433     kVssubuvx = 0b100010,
434     kVssubvx = 0b100011,
435     kVsllvx = 0b100101,
436     kVsmulvx = 0b100111,
437     kVsrlvx = 0b101000,
438     kVsravx = 0b101001,
439     kVssrlvx = 0b101010,
440     kVssravx = 0b101011,
441     kVnsrlwx = 0b101100,
442     kVnsrawx = 0b101101,
443     kVnclipuwx = 0b101110,
444     kVnclipwx = 0b101111,
445   };
446 
447   enum class VOpMVvOpcode : uint8_t {
448     kVredsumvs = 0b000000,
449     kVredandvs = 0b000001,
450     kVredorvs = 0b000010,
451     kVredxorvs = 0b000011,
452     kVredminuvs = 0b000100,
453     kVredminvs = 0b000101,
454     kVredmaxuvs = 0b000110,
455     kVredmaxvs = 0b000111,
456     kVaadduvv = 0b001000,
457     kVaaddvv = 0b001001,
458     kVasubuvv = 0b001010,
459     kVasubvv = 0b001011,
460     kVWXUnary0 = 0b010000,
461     kVFUnary0 = 0b010010,
462     kVMUnary0 = 0b010100,
463     kVmandnmm = 0b011000,
464     kVmandmm = 0b011001,
465     kVmormm = 0b011010,
466     kVmxormm = 0b011011,
467     kVmornmm = 0b011100,
468     kVmnandmm = 0b011101,
469     kVmnormm = 0b011110,
470     kVmxnormm = 0b011111,
471     kVdivuvv = 0b100000,
472     kVdivvv = 0b100001,
473     kVremuvv = 0b100010,
474     kVremvv = 0b100011,
475     kVmulhuvv = 0b100100,
476     kVmulvv = 0b100101,
477     kVmulhsuvv = 0b100110,
478     kVmulhvv = 0b100111,
479     kVmaddvv = 0b101001,
480     kVnmsubvv = 0b101011,
481     kVmaccvv = 0b101101,
482     kVnmsacvv = 0b101111,
483     kVwadduvv = 0b110000,
484     kVwaddvv = 0b110001,
485     kVwsubuvv = 0b110010,
486     kVwsubvv = 0b110011,
487     kVwadduwv = 0b110100,
488     kVwaddwv = 0b110101,
489     kVwsubuwv = 0b110110,
490     kVwsubwv = 0b110111,
491     kVwmuluvv = 0b111000,
492     kVwmulsuvv = 0b111010,
493     kVwmulvv = 0b111011,
494     kVwmaccuvv = 0b111100,
495     kVwmaccvv = 0b111101,
496     kVwmaccsuvv = 0b111111,
497   };
498 
499   enum class VOpMVxOpcode : uint8_t {
500     kVaadduvx = 0b001000,
501     kVaaddvx = 0b001001,
502     kVasubuvx = 0b001010,
503     kVasubvx = 0b001011,
504     kVslide1upvx = 0b001110,
505     kVslide1downvx = 0b001111,
506     kVRXUnary0 = 0b010000,
507     kVdivuvx = 0b100000,
508     kVdivvx = 0b100001,
509     kVremuvx = 0b100010,
510     kVremvx = 0b100011,
511     kVmulhuvx = 0b100100,
512     kVmulvx = 0b100101,
513     kVmulhsuvx = 0b100110,
514     kVmulhvx = 0b100111,
515     kVmaddvx = 0b101001,
516     kVnmsubvx = 0b101011,
517     kVmaccvx = 0b101101,
518     kVnmsacvx = 0b101111,
519     kVwadduvx = 0b110000,
520     kVwaddvx = 0b110001,
521     kVwsubuvx = 0b110010,
522     kVwsubvx = 0b110011,
523     kVwadduwx = 0b110100,
524     kVwaddwx = 0b110101,
525     kVwsubuwx = 0b110110,
526     kVwsubwx = 0b110111,
527     kVwmuluvx = 0b111000,
528     kVwmulsuvx = 0b111010,
529     kVwmulvx = 0b111011,
530     kVwmaccuvx = 0b111100,
531     kVwmaccvx = 0b111101,
532     kVwmaccusvx = 0b111110,
533     kVwmaccsuvx = 0b111111,
534   };
535 
536   enum class VSUmOpOpcode : uint8_t {
537     kVseXX = 0b00000,
538     kVsX = 0b01000,
539     kVsm = 0b01011,
540   };
541 
542   enum class VFUnary0Opcode : uint8_t {
543     kVfcvtxufv = 0b00000,
544     kVfcvtxfv = 0b00001,
545     kVfcvtfxuv = 0b00010,
546     kVfcvtfxv = 0b00011,
547     kVfcvtrtzxufv = 0b00110,
548     kVfcvtrtzxfv = 0b00111,
549     kVfwcvtxufv = 0b01000,
550     kVfwcvtxfv = 0b01001,
551     kVfwcvtfxuv = 0b01010,
552     kVfwcvtfxv = 0b01011,
553     kVfwcvtffv = 0b01100,
554     kVfwcvtrtzxufv = 0b01110,
555     kVfwcvtrtzxfv = 0b01111,
556     kVfncvtxufw = 0b10000,
557     kVfncvtxfw = 0b10001,
558     kVfncvtfxuw = 0b10010,
559     kVfncvtfxw = 0b10011,
560     kVfncvtffw = 0b10100,
561     kVfncvtrodffw = 0b10101,
562     kVfncvtrtzxufw = 0b10110,
563     kVfncvtrtzxfw = 0b10111,
564   };
565 
566   enum class VFUnary1Opcode : uint8_t {
567     kVfsqrtv = 0b00000,
568     kVfrsqrt7v = 0b00100,
569     kVfclassv = 0b10000,
570   };
571 
572   enum class VRXUnary0Opcode : uint8_t {
573     kVmvsx = 0b00000,
574   };
575 
576   enum class VWXUnary0Opcode : uint8_t {
577     kVmvxs = 0b00000,
578     kVcpopm = 0b10000,
579     kVfirstm = 0b10001,
580   };
581 
582   enum class VMUnary0Opcode : uint8_t {
583     kVmsbfm = 0b00001,
584     kVmsofm = 0b00010,
585     kVmsifm = 0b00011,
586     kViotam = 0b10000,
587     kVidv = 0b10001,
588   };
589 
590   enum class VXUnary0Opcode : uint8_t {
591     kVzextvf8m = 0b00010,
592     kVsextvf8m = 0b00011,
593     kVzextvf4m = 0b00100,
594     kVsextvf4m = 0b00101,
595     kVzextvf2m = 0b00110,
596     kVsextvf2m = 0b00111,
597     kVbrev8v = 0b01000,
598   };
599 
600   // Load/Store instruction include 3bit “width” field while all other floating-point instructions
601   // include 2bit “fmt” field.
602   //
603   // Decoder unifies these differences and uses FloatOperandType for types of all floating-point
604   // operands.
605   //
606   // Load/Store for regular instruction coulnd't be simiarly unified: Load instructions include
607   // seven types, while Store instructions have only four.
608   //
609   // Fcvt instructions have their own operand type encoding because they are only supporting 32bit
610   // and 64bit operands, there is no support for 8bit and 16bit operands.
611   //
612   // This is because Load can perform either sign-extension or zero-extension for all sizes except
613   // 64bit (which doesn't need neither sign-extension nor zero-extension since operand size is the
614   // same as register size in that case).
615 
616   enum class FcvtOperandType : uint8_t {
617     k32bitSigned = 0b00000,
618     k32bitUnsigned = 0b00001,
619     k64bitSigned = 0b00010,
620     k64bitUnsigned = 0b00011,
621   };
622 
623   enum class FloatOperandType : uint8_t {
624     kFloat = 0b00,
625     kDouble = 0b01,
626     kHalf = 0b10,
627     kQuad = 0b11,
628   };
629 
630   // Used in vector loads and stores, and also in scalar stores.
631   // Scalar loads use different type because loads needs to either sign-extend value or zero-extend
632   // it which makes difference between signed and unsigned types meaningful.
633   enum class MemoryDataOperandType : uint8_t {
634     k8bit = 0b000,
635     k16bit = 0b001,
636     k32bit = 0b010,
637     k64bit = 0b011,
638   };
639 
640   enum class LoadOperandType : uint8_t {
641     k8bitSigned = 0b000,
642     k16bitSigned = 0b001,
643     k32bitSigned = 0b010,
644     k64bit = 0b011,
645     k8bitUnsigned = 0b100,
646     k16bitUnsigned = 0b101,
647     k32bitUnsigned = 0b110,
648   };
649 
650   struct AmoArgs {
651     AmoOpcode opcode;
652     MemoryDataOperandType operand_type;
653     uint8_t dst;
654     uint8_t src1;
655     uint8_t src2;
656     bool rl : 1;
657     bool aq : 1;
658   };
659 
660   struct BranchArgs {
661     BranchOpcode opcode;
662     uint8_t src1;
663     uint8_t src2;
664     int16_t offset;
665   };
666 
667   struct CsrArgs {
668     CsrOpcode opcode;
669     uint8_t dst;
670     uint8_t src;
671     uint16_t csr;
672   };
673 
674   struct CsrImmArgs {
675     CsrImmOpcode opcode;
676     uint8_t dst;
677     uint8_t imm;
678     uint16_t csr;
679   };
680 
681   struct FcvtFloatToFloatArgs {
682     FloatOperandType dst_type;
683     FloatOperandType src_type;
684     uint8_t dst;
685     uint8_t src;
686     uint8_t rm;
687   };
688 
689   struct FcvtFloatToIntegerArgs {
690     FcvtOperandType dst_type;
691     FloatOperandType src_type;
692     uint8_t dst;
693     uint8_t src;
694     uint8_t rm;
695   };
696 
697   struct FcvtIntegerToFloatArgs {
698     FloatOperandType dst_type;
699     FcvtOperandType src_type;
700     uint8_t dst;
701     uint8_t src;
702     uint8_t rm;
703   };
704 
705   struct FenceArgs {
706     FenceOpcode opcode;
707     uint8_t dst;
708     uint8_t src;
709     bool sw : 1;
710     bool sr : 1;
711     bool so : 1;
712     bool si : 1;
713     bool pw : 1;
714     bool pr : 1;
715     bool po : 1;
716     bool pi : 1;
717   };
718 
719   struct FenceIArgs {
720     uint8_t dst;
721     uint8_t src;
722     int16_t imm;
723   };
724 
725   struct FmaArgs {
726     FmaOpcode opcode;
727     FloatOperandType operand_type;
728     uint8_t dst;
729     uint8_t src1;
730     uint8_t src2;
731     uint8_t src3;
732     uint8_t rm;
733   };
734 
735   struct JumpAndLinkArgs {
736     uint8_t dst;
737     int32_t offset;
738     uint8_t insn_len;
739   };
740 
741   struct JumpAndLinkRegisterArgs {
742     uint8_t dst;
743     uint8_t base;
744     int16_t offset;
745     uint8_t insn_len;
746   };
747 
748   template <typename OpcodeType>
749   struct OpArgsTemplate {
750     OpcodeType opcode;
751     uint8_t dst;
752     uint8_t src1;
753     uint8_t src2;
754   };
755 
756   struct OpSingleInputArgs {
757     OpSingleInputOpcode opcode;
758     uint8_t dst;
759     uint8_t src;
760   };
761 
762   using OpArgs = OpArgsTemplate<OpOpcode>;
763   using Op32Args = OpArgsTemplate<Op32Opcode>;
764 
765   struct OpFpArgs {
766     OpFpOpcode opcode;
767     FloatOperandType operand_type;
768     uint8_t dst;
769     uint8_t src1;
770     uint8_t src2;
771     uint8_t rm;
772   };
773 
774   struct OpFpGpRegisterTargetNoRoundingArgs {
775     OpFpGpRegisterTargetNoRoundingOpcode opcode;
776     FloatOperandType operand_type;
777     uint8_t dst;
778     uint8_t src1;
779     uint8_t src2;
780   };
781 
782   struct OpFpGpRegisterTargetSingleInputNoRoundingArgs {
783     OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode;
784     FloatOperandType operand_type;
785     uint8_t dst;
786     uint8_t src;
787   };
788 
789   struct FmvFloatToIntegerArgs {
790     FloatOperandType operand_type;
791     uint8_t dst;
792     uint8_t src;
793   };
794 
795   struct FmvIntegerToFloatArgs {
796     FloatOperandType operand_type;
797     uint8_t dst;
798     uint8_t src;
799   };
800 
801   struct OpFpNoRoundingArgs {
802     OpFpNoRoundingOpcode opcode;
803     FloatOperandType operand_type;
804     uint8_t dst;
805     uint8_t src1;
806     uint8_t src2;
807   };
808 
809   struct OpFpSingleInputArgs {
810     OpFpSingleInputOpcode opcode;
811     FloatOperandType operand_type;
812     uint8_t dst;
813     uint8_t src;
814     uint8_t rm;
815   };
816 
817   struct OpFpSingleInputNoRoundingArgs {
818     OpFpSingleInputNoRoundingOpcode opcode;
819     FloatOperandType operand_type;
820     uint8_t dst;
821     uint8_t src;
822   };
823 
824   template <typename OpcodeType>
825   struct OpImmArgsTemplate {
826     OpcodeType opcode;
827     uint8_t dst;
828     uint8_t src;
829     int16_t imm;
830   };
831 
832   using OpImmArgs = OpImmArgsTemplate<OpImmOpcode>;
833   using OpImm32Args = OpImmArgsTemplate<OpImm32Opcode>;
834 
835   struct VLoadIndexedArgs {
836     MemoryDataOperandType width;
837     bool vm;
838     bool ordered;
839     uint8_t nf;
840     uint8_t dst;
841     uint8_t src;
842     uint8_t idx;
843   };
844 
845   struct VLoadStrideArgs {
846     MemoryDataOperandType width;
847     bool vm;
848     bool ordered;
849     uint8_t nf;
850     uint8_t dst;
851     uint8_t src;
852     uint8_t std;
853   };
854 
855   struct VLoadUnitStrideArgs {
856     VLUmOpOpcode opcode;
857     MemoryDataOperandType width;
858     bool vm;
859     uint8_t nf;
860     uint8_t dst;
861     uint8_t src;
862   };
863 
864   struct VOpFVfArgs {
865     VOpFVfOpcode opcode;
866     bool vm;
867     uint8_t dst;
868     uint8_t src1;
869     uint8_t src2;
870   };
871 
872   struct VOpFVvArgs {
873     VOpFVvOpcode opcode;
874     bool vm;
875     uint8_t dst;
876     uint8_t src1;
877     union {
878       VFUnary0Opcode vfunary0_opcode;
879       VFUnary1Opcode vfunary1_opcode;
880       uint8_t src2;
881     };
882   };
883 
884   struct VOpIViArgs {
885     VOpIViOpcode opcode;
886     bool vm;
887     uint8_t dst;
888     uint8_t src;
889     union {
890       int8_t imm : 5;
891       uint8_t uimm : 5;
892     };
893   };
894 
895   struct VOpIVvArgs {
896     VOpIVvOpcode opcode;
897     bool vm;
898     uint8_t dst;
899     uint8_t src1;
900     uint8_t src2;
901   };
902 
903   struct VOpIVxArgs {
904     VOpIVxOpcode opcode;
905     bool vm;
906     uint8_t dst;
907     uint8_t src1;
908     uint8_t src2;
909   };
910 
911   struct VOpMVvArgs {
912     VOpMVvOpcode opcode;
913     bool vm;
914     uint8_t dst;
915     uint8_t src1;
916     union {
917       VWXUnary0Opcode vwxunary0_opcode;
918       VMUnary0Opcode vmunary0_opcode;
919       VXUnary0Opcode vxunary0_opcode;
920       uint8_t src2;
921     };
922   };
923 
924   struct VOpMVxArgs {
925     VOpMVxOpcode opcode;
926     bool vm;
927     uint8_t dst;
928     union {
929       VRXUnary0Opcode vrxunary0_opcode;
930       uint8_t src1;
931     };
932     uint8_t src2;
933   };
934 
935   struct VsetivliArgs {
936     uint8_t dst;
937     uint8_t avl;
938     uint16_t vtype;
939   };
940 
941   struct VsetvliArgs {
942     uint8_t dst;
943     uint8_t src;
944     uint16_t vtype;
945   };
946 
947   struct VsetvlArgs {
948     uint8_t dst;
949     uint8_t src1;
950     uint8_t src2;
951   };
952 
953   struct VStoreIndexedArgs {
954     MemoryDataOperandType width;
955     bool vm;
956     bool ordered;
957     uint8_t nf;
958     uint8_t src;
959     uint8_t idx;
960     uint8_t data;
961   };
962 
963   struct VStoreStrideArgs {
964     MemoryDataOperandType width;
965     bool vm;
966     bool ordered;
967     uint8_t nf;
968     uint8_t src;
969     uint8_t std;
970     uint8_t data;
971   };
972 
973   struct VStoreUnitStrideArgs {
974     VSUmOpOpcode opcode;
975     MemoryDataOperandType width;
976     bool vm;
977     uint8_t nf;
978     uint8_t src;
979     uint8_t data;
980   };
981 
982   template <typename OperandTypeEnum>
983   struct LoadArgsTemplate {
984     OperandTypeEnum operand_type;
985     uint8_t dst;
986     uint8_t src;
987     int16_t offset;
988   };
989 
990   using LoadArgs = LoadArgsTemplate<LoadOperandType>;
991   using LoadFpArgs = LoadArgsTemplate<FloatOperandType>;
992 
993   template <typename OpcodeType>
994   struct ShiftImmArgsTemplate {
995     OpcodeType opcode;
996     uint8_t dst;
997     uint8_t src;
998     uint8_t imm;
999   };
1000 
1001   using ShiftImmArgs = ShiftImmArgsTemplate<ShiftImmOpcode>;
1002   using ShiftImm32Args = ShiftImmArgsTemplate<ShiftImm32Opcode>;
1003 
1004   template <typename OpcodeType>
1005   struct BitmanipImmArgsTemplate {
1006     OpcodeType opcode;
1007     uint8_t dst;
1008     uint8_t src;
1009     uint8_t shamt;
1010   };
1011 
1012   using BitmanipImmArgs = BitmanipImmArgsTemplate<BitmanipImmOpcode>;
1013   using BitmanipImm32Args = BitmanipImmArgsTemplate<BitmanipImm32Opcode>;
1014 
1015   template <typename OperandTypeEnum>
1016   struct StoreArgsTemplate {
1017     OperandTypeEnum operand_type;
1018     uint8_t src;
1019     int16_t offset;
1020     uint8_t data;
1021   };
1022 
1023   using StoreArgs = StoreArgsTemplate<MemoryDataOperandType>;
1024   using StoreFpArgs = StoreArgsTemplate<FloatOperandType>;
1025 
1026   struct SystemArgs {
1027     SystemOpcode opcode;
1028   };
1029 
1030   struct UpperImmArgs {
1031     uint8_t dst;
1032     int32_t imm;
1033   };
1034 
GetInsnSize(const uint16_t * code)1035   static uint8_t GetInsnSize(const uint16_t* code) {
1036     constexpr uint16_t kInsnLenMask = uint16_t{0b11};
1037     return ((*code & kInsnLenMask) != kInsnLenMask) ? 2 : 4;
1038   }
1039 
Decode(const uint16_t * code)1040   uint8_t Decode(const uint16_t* code) {
1041     uint8_t insn_size = GetInsnSize(code);
1042     if (insn_size == 2) {
1043       code_ = *code;
1044       return DecodeCompressedInstruction();
1045     }
1046     CHECK_EQ(insn_size, 4);
1047     // Warning: do not cast and dereference the pointer
1048     // since the address may not be 4-bytes aligned.
1049     memcpy(&code_, code, sizeof(code_));
1050     return DecodeBaseInstruction();
1051   }
1052 
DecodeCompressedInstruction()1053   uint8_t DecodeCompressedInstruction() {
1054     CompressedOpcode opcode_bits{(GetBits<13, 3>() << 2) | GetBits<0, 2>()};
1055 
1056     switch (opcode_bits) {
1057       case CompressedOpcode::kAddi4spn:
1058         DecodeCompressedAddi4spn();
1059         break;
1060       case CompressedOpcode::kFld:
1061         DecodeCompressedLoadStore<LoadStore::kLoad, FloatOperandType::kDouble>();
1062         break;
1063       case CompressedOpcode::kLw:
1064         DecodeCompressedLoadStore<LoadStore::kLoad, LoadOperandType::k32bitSigned>();
1065         break;
1066       case CompressedOpcode::kLd:
1067         DecodeCompressedLoadStore<LoadStore::kLoad, LoadOperandType::k64bit>();
1068         break;
1069       case CompressedOpcode::kFsd:
1070         DecodeCompressedLoadStore<LoadStore::kStore, FloatOperandType::kDouble>();
1071         break;
1072       case CompressedOpcode::kSw:
1073         DecodeCompressedLoadStore<LoadStore::kStore, MemoryDataOperandType::k32bit>();
1074         break;
1075       case CompressedOpcode::kSd:
1076         DecodeCompressedLoadStore<LoadStore::kStore, MemoryDataOperandType::k64bit>();
1077         break;
1078       case CompressedOpcode::kAddi:
1079         DecodeCompressedAddi();
1080         break;
1081       case CompressedOpcode::kAddiw:
1082         DecodeCompressedAddiw();
1083         break;
1084       case CompressedOpcode::kLi:
1085         DecodeCompressedLi();
1086         break;
1087       case CompressedOpcode::kLui_Addi16sp:
1088         DecodeCompressedLuiAddi16sp();
1089         break;
1090       case CompressedOpcode::kMisc_Alu:
1091         DecodeCompressedMiscAlu();
1092         break;
1093       case CompressedOpcode::kJ:
1094         DecodeCompressedJ();
1095         break;
1096       case CompressedOpcode::kBeqz:
1097       case CompressedOpcode::kBnez:
1098         DecodeCompressedBeqzBnez();
1099         break;
1100       case CompressedOpcode::kSlli:
1101         DecodeCompressedSlli();
1102         break;
1103       case CompressedOpcode::kFldsp:
1104         DecodeCompressedLoadsp<FloatOperandType::kDouble>();
1105         break;
1106       case CompressedOpcode::kLwsp:
1107         DecodeCompressedLoadsp<LoadOperandType::k32bitSigned>();
1108         break;
1109       case CompressedOpcode::kLdsp:
1110         DecodeCompressedLoadsp<LoadOperandType::k64bit>();
1111         break;
1112       case CompressedOpcode::kJr_Jalr_Mv_Add:
1113         DecodeCompressedJr_Jalr_Mv_Add();
1114         break;
1115       case CompressedOpcode::kFsdsp:
1116         DecodeCompressedStoresp<FloatOperandType::kDouble>();
1117         break;
1118       case CompressedOpcode::kSwsp:
1119         DecodeCompressedStoresp<MemoryDataOperandType::k32bit>();
1120         break;
1121       case CompressedOpcode::kSdsp:
1122         DecodeCompressedStoresp<MemoryDataOperandType::k64bit>();
1123         break;
1124       default:
1125         insn_consumer_->Undefined();
1126     }
1127     return 2;
1128   }
1129 
DecodeCompressedLi()1130   void DecodeCompressedLi() {
1131     uint8_t low_imm = GetBits<2, 5>();
1132     uint8_t high_imm = GetBits<12, 1>();
1133     uint8_t rd = GetBits<7, 5>();
1134     int8_t imm = SignExtend<6>((high_imm << 5) + low_imm);
1135     const OpImmArgs args = {
1136         .opcode = OpImmOpcode::kAddi,
1137         .dst = rd,
1138         .src = 0,
1139         .imm = imm,
1140     };
1141     insn_consumer_->OpImm(args);
1142   }
1143 
DecodeCompressedMiscAlu()1144   void DecodeCompressedMiscAlu() {
1145     uint8_t r = GetBits<7, 3>() + 8;
1146     uint8_t low_imm = GetBits<2, 5>();
1147     uint8_t high_imm = GetBits<12, 1>();
1148     uint8_t imm = (high_imm << 5) + low_imm;
1149     uint8_t zc_high_opcode_bits = GetBits<10, 3>();
1150     uint16_t zc_opcode{static_cast<uint16_t>(low_imm | (zc_high_opcode_bits << 5))};
1151 
1152     std::optional<OpSingleInputOpcode> si_opcode;
1153     switch (zc_opcode) {
1154       case 0b111'11'010:
1155         si_opcode = OpSingleInputOpcode::kZexth;
1156         break;
1157       case 0b111'11'000:
1158         si_opcode = OpSingleInputOpcode::kZextb;
1159         break;
1160       case 0b111'11'100:
1161         si_opcode = OpSingleInputOpcode::kZextw;
1162         break;
1163       case 0b111'11'001:
1164         si_opcode = OpSingleInputOpcode::kSextb;
1165         break;
1166       case 0b111'11'011:
1167         si_opcode = OpSingleInputOpcode::kSexth;
1168         break;
1169       default:
1170         break;
1171     }
1172     if (si_opcode.has_value()) {
1173       const OpSingleInputArgs args = {.opcode = si_opcode.value(), .dst = r, .src = r};
1174       return insn_consumer_->OpSingleInput(args);
1175     }
1176 
1177     switch (GetBits<10, 2>()) {
1178       case 0b00: {
1179         const ShiftImmArgs args = {
1180             .opcode = ShiftImmOpcode::kSrli,
1181             .dst = r,
1182             .src = r,
1183             .imm = imm,
1184         };
1185         return insn_consumer_->OpImm(args);
1186       }
1187       case 0b01: {
1188         const ShiftImmArgs args = {
1189             .opcode = ShiftImmOpcode::kSrai,
1190             .dst = r,
1191             .src = r,
1192             .imm = imm,
1193         };
1194         return insn_consumer_->OpImm(args);
1195       }
1196       case 0b10: {
1197         const OpImmArgs args = {
1198             .opcode = OpImmOpcode::kAndi,
1199             .dst = r,
1200             .src = r,
1201             .imm = SignExtend<6>(imm),
1202         };
1203         return insn_consumer_->OpImm(args);
1204       }
1205     }
1206     uint8_t rs2 = GetBits<2, 3>() + 8;
1207     if (GetBits<12, 1>() == 0) {
1208       OpOpcode opcode;
1209       switch (GetBits<5, 2>()) {
1210         case 0b00:
1211           opcode = OpOpcode::kSub;
1212           break;
1213         case 0b01:
1214           opcode = OpOpcode::kXor;
1215           break;
1216         case 0b10:
1217           opcode = OpOpcode::kOr;
1218           break;
1219         case 0b11:
1220           opcode = OpOpcode::kAnd;
1221           break;
1222       }
1223       const OpArgs args = {
1224           .opcode = opcode,
1225           .dst = r,
1226           .src1 = r,
1227           .src2 = rs2,
1228       };
1229       return insn_consumer_->Op(args);
1230     } else {
1231       Op32Opcode opcode;
1232       switch (GetBits<5, 2>()) {
1233         case 0b00:
1234           opcode = Op32Opcode::kSubw;
1235           break;
1236         case 0b01:
1237           opcode = Op32Opcode::kAddw;
1238           break;
1239         default:
1240           return Undefined();
1241       }
1242       const Op32Args args = {
1243           .opcode = opcode,
1244           .dst = r,
1245           .src1 = r,
1246           .src2 = rs2,
1247       };
1248       return insn_consumer_->Op(args);
1249     }
1250   }
1251 
1252   template <auto kOperandType>
DecodeCompressedStoresp()1253   void DecodeCompressedStoresp() {
1254     uint8_t raw_imm = GetBits<7, 6>();
1255     uint8_t rs2 = GetBits<2, 5>();
1256     constexpr uint8_t k32bit[64] = {
1257         0x00, 0x10, 0x20, 0x30, 0x01, 0x11, 0x21, 0x31, 0x02, 0x12, 0x22, 0x32, 0x03,
1258         0x13, 0x23, 0x33, 0x04, 0x14, 0x24, 0x34, 0x05, 0x15, 0x25, 0x35, 0x06, 0x16,
1259         0x26, 0x36, 0x07, 0x17, 0x27, 0x37, 0x08, 0x18, 0x28, 0x38, 0x09, 0x19, 0x29,
1260         0x39, 0x0a, 0x1a, 0x2a, 0x3a, 0x0b, 0x1b, 0x2b, 0x3b, 0x0c, 0x1c, 0x2c, 0x3c,
1261         0x0d, 0x1d, 0x2d, 0x3d, 0x0e, 0x1e, 0x2e, 0x3e, 0x0f, 0x1f, 0x2f, 0x3f};
1262     constexpr uint8_t k64bit[64] = {
1263         0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x02, 0x12, 0x22, 0x32, 0x42,
1264         0x52, 0x62, 0x72, 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x06, 0x16,
1265         0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68,
1266         0x78, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x0c, 0x1c, 0x2c, 0x3c,
1267         0x4c, 0x5c, 0x6c, 0x7c, 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e};
1268     int16_t imm = (((uint8_t(kOperandType) & 1) == 0) ? k32bit : k64bit)[raw_imm] << 2;
1269     const StoreArgsTemplate<decltype(kOperandType)> args = {
1270         .operand_type = kOperandType,
1271         .src = 2,
1272         .offset = imm,
1273         .data = rs2,
1274     };
1275     insn_consumer_->Store(args);
1276   }
1277 
DecodeCompressedLuiAddi16sp()1278   void DecodeCompressedLuiAddi16sp() {
1279     uint8_t low_imm = GetBits<2, 5>();
1280     uint8_t high_imm = GetBits<12, 1>();
1281     uint8_t rd = GetBits<7, 5>();
1282     if (rd != 2) {
1283       int32_t imm = SignExtend<18>((high_imm << 17) + (low_imm << 12));
1284       const UpperImmArgs args = {
1285           .dst = rd,
1286           .imm = imm,
1287       };
1288       return insn_consumer_->Lui(args);
1289     }
1290     constexpr uint8_t kAddi16spLow[32] = {0x00, 0x08, 0x20, 0x28, 0x40, 0x48, 0x60, 0x68,
1291                                           0x10, 0x18, 0x30, 0x38, 0x50, 0x58, 0x70, 0x78,
1292                                           0x04, 0x0c, 0x24, 0x2c, 0x44, 0x4c, 0x64, 0x6c,
1293                                           0x14, 0x1c, 0x34, 0x3c, 0x54, 0x5c, 0x74, 0x7c};
1294     int16_t imm = SignExtend<10>((high_imm << 9) + (kAddi16spLow[low_imm] << 2));
1295     const OpImmArgs args = {
1296         .opcode = OpImmOpcode::kAddi,
1297         .dst = 2,
1298         .src = 2,
1299         .imm = imm,
1300     };
1301     insn_consumer_->OpImm(args);
1302   }
1303 
1304   enum class LoadStore { kLoad, kStore };
1305 
1306   template <enum LoadStore kLoadStore, auto kOperandType>
DecodeCompressedLoadStore()1307   void DecodeCompressedLoadStore() {
1308     uint8_t low_imm = GetBits<5, 2>();
1309     uint8_t high_imm = GetBits<10, 3>();
1310     uint8_t imm;
1311     if constexpr ((uint8_t(kOperandType) & 1) == 0) {
1312       constexpr uint8_t kLwLow[4] = {0x0, 0x40, 0x04, 0x44};
1313       imm = (kLwLow[low_imm] | high_imm << 3);
1314     } else {
1315       imm = (low_imm << 6 | high_imm << 3);
1316     }
1317     uint8_t rd = GetBits<2, 3>();
1318     uint8_t rs = GetBits<7, 3>();
1319     if constexpr (kLoadStore == LoadStore::kStore) {
1320       const StoreArgsTemplate<decltype(kOperandType)> args = {
1321           .operand_type = kOperandType,
1322           .src = uint8_t(8 + rs),
1323           .offset = imm,
1324           .data = uint8_t(8 + rd),
1325       };
1326       insn_consumer_->Store(args);
1327     } else {
1328       const LoadArgsTemplate<decltype(kOperandType)> args = {
1329           .operand_type = kOperandType,
1330           .dst = uint8_t(8 + rd),
1331           .src = uint8_t(8 + rs),
1332           .offset = imm,
1333       };
1334       insn_consumer_->Load(args);
1335     }
1336   }
1337 
1338   template <auto kOperandType>
DecodeCompressedLoadsp()1339   void DecodeCompressedLoadsp() {
1340     uint8_t low_imm = GetBits<2, 5>();
1341     uint8_t high_imm = GetBits<12, 1>();
1342     uint8_t rd = GetBits<7, 5>();
1343     constexpr uint8_t k32bitLow[32] = {0x00, 0x10, 0x20, 0x30, 0x01, 0x11, 0x21, 0x31,
1344                                        0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33,
1345                                        0x04, 0x14, 0x24, 0x34, 0x05, 0x15, 0x25, 0x35,
1346                                        0x06, 0x16, 0x26, 0x36, 0x07, 0x17, 0x27, 0x37};
1347     constexpr uint8_t k64bitLow[32] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
1348                                        0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
1349                                        0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
1350                                        0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76};
1351     int16_t imm = (high_imm << 5) +
1352                   ((((uint8_t(kOperandType) & 1) == 0) ? k32bitLow : k64bitLow)[low_imm] << 2);
1353     const LoadArgsTemplate<decltype(kOperandType)> args = {
1354         .operand_type = kOperandType,
1355         .dst = rd,
1356         .src = 2,
1357         .offset = imm,
1358     };
1359     insn_consumer_->Load(args);
1360   }
1361 
DecodeCompressedAddi()1362   void DecodeCompressedAddi() {
1363     uint8_t low_imm = GetBits<2, 5>();
1364     uint8_t high_imm = GetBits<12, 1>();
1365     int8_t imm = SignExtend<6>(high_imm << 5 | low_imm);
1366     uint8_t r = GetBits<7, 5>();
1367     if (r == 0 || imm == 0) {
1368       insn_consumer_->Nop();
1369     }
1370     const OpImmArgs args = {
1371         .opcode = OpImmOpcode::kAddi,
1372         .dst = r,
1373         .src = r,
1374         .imm = imm,
1375     };
1376     insn_consumer_->OpImm(args);
1377   }
1378 
DecodeCompressedAddiw()1379   void DecodeCompressedAddiw() {
1380     uint8_t low_imm = GetBits<2, 5>();
1381     uint8_t high_imm = GetBits<12, 1>();
1382     int8_t imm = SignExtend<6>(high_imm << 5 | low_imm);
1383     uint8_t r = GetBits<7, 5>();
1384     const OpImm32Args args = {
1385         .opcode = OpImm32Opcode::kAddiw,
1386         .dst = r,
1387         .src = r,
1388         .imm = imm,
1389     };
1390     insn_consumer_->OpImm(args);
1391   }
1392 
DecodeCompressedBeqzBnez()1393   void DecodeCompressedBeqzBnez() {
1394     constexpr uint16_t kBHigh[8] = {0x0, 0x8, 0x10, 0x18, 0x100, 0x108, 0x110, 0x118};
1395     constexpr uint8_t kBLow[32] = {0x00, 0x20, 0x02, 0x22, 0x04, 0x24, 0x06, 0x26, 0x40, 0x60, 0x42,
1396                                    0x62, 0x44, 0x64, 0x46, 0x66, 0x80, 0xa0, 0x82, 0xa2, 0x84, 0xa4,
1397                                    0x86, 0xa6, 0xc0, 0xe0, 0xc2, 0xe2, 0xc4, 0xe4, 0xc6, 0xe6};
1398     uint8_t low_imm = GetBits<2, 5>();
1399     uint8_t high_imm = GetBits<10, 3>();
1400     uint8_t rs = GetBits<7, 3>();
1401 
1402     const BranchArgs args = {
1403         .opcode = BranchOpcode{GetBits<13, 1>()},
1404         .src1 = uint8_t(8 + rs),
1405         .src2 = 0,
1406         .offset = static_cast<int16_t>(SignExtend<9>(kBHigh[high_imm] + kBLow[low_imm])),
1407     };
1408     insn_consumer_->CompareAndBranch(args);
1409   }
1410 
DecodeCompressedJ()1411   void DecodeCompressedJ() {
1412     constexpr uint16_t kJHigh[32] = {
1413         0x0,    0x400,  0x100,  0x500,  0x200,  0x600,  0x300,  0x700,  0x10,   0x410,  0x110,
1414         0x510,  0x210,  0x610,  0x310,  0x710,  0xf800, 0xfc00, 0xf900, 0xfd00, 0xfa00, 0xfe00,
1415         0xfb00, 0xff00, 0xf810, 0xfc10, 0xf910, 0xfd10, 0xfa10, 0xfe10, 0xfb10, 0xff10,
1416     };
1417     constexpr uint8_t kJLow[64] = {
1418         0x0,  0x20, 0x2,  0x22, 0x4,  0x24, 0x6,  0x26, 0x8,  0x28, 0xa,  0x2a, 0xc,
1419         0x2c, 0xe,  0x2e, 0x80, 0xa0, 0x82, 0xa2, 0x84, 0xa4, 0x86, 0xa6, 0x88, 0xa8,
1420         0x8a, 0xaa, 0x8c, 0xac, 0x8e, 0xae, 0x40, 0x60, 0x42, 0x62, 0x44, 0x64, 0x46,
1421         0x66, 0x48, 0x68, 0x4a, 0x6a, 0x4c, 0x6c, 0x4e, 0x6e, 0xc0, 0xe0, 0xc2, 0xe2,
1422         0xc4, 0xe4, 0xc6, 0xe6, 0xc8, 0xe8, 0xca, 0xea, 0xcc, 0xec, 0xce, 0xee,
1423     };
1424     const JumpAndLinkArgs args = {
1425         .dst = 0,
1426         .offset = bit_cast<int16_t>(kJHigh[GetBits<8, 5>()]) | kJLow[GetBits<2, 6>()],
1427         .insn_len = 2,
1428     };
1429     insn_consumer_->JumpAndLink(args);
1430   }
1431 
DecodeCompressedAddi4spn()1432   void DecodeCompressedAddi4spn() {
1433     constexpr uint8_t kAddi4spnHigh[16] = {
1434         0x0, 0x40, 0x80, 0xc0, 0x4, 0x44, 0x84, 0xc4, 0x8, 0x48, 0x88, 0xc8, 0xc, 0x4c, 0x8c, 0xcc};
1435     constexpr uint8_t kAddi4spnLow[16] = {
1436         0x0, 0x2, 0x1, 0x3, 0x10, 0x12, 0x11, 0x13, 0x20, 0x22, 0x21, 0x23, 0x30, 0x32, 0x31, 0x33};
1437     int16_t imm = (kAddi4spnHigh[GetBits<9, 4>()] | kAddi4spnLow[GetBits<5, 4>()]) << 2;
1438     // If immediate is zero then this instruction is treated as undefined.
1439     // This includes RISC-V dedicated 16bit “undefined instruction” 0x0000.
1440     if (imm == 0) {
1441       return Undefined();
1442     }
1443     const OpImmArgs args = {
1444         .opcode = OpImmOpcode::kAddi,
1445         .dst = uint8_t(8 + GetBits<2, 3>()),
1446         .src = 2,
1447         .imm = imm,
1448     };
1449     insn_consumer_->OpImm(args);
1450   }
1451 
DecodeCompressedJr_Jalr_Mv_Add()1452   void DecodeCompressedJr_Jalr_Mv_Add() {
1453     uint8_t r = GetBits<7, 5>();
1454     uint8_t rs2 = GetBits<2, 5>();
1455     if (GetBits<12, 1>()) {
1456       if (r == 0 && rs2 == 0) {
1457         const SystemArgs args = {
1458             .opcode = SystemOpcode::kEbreak,
1459         };
1460         return insn_consumer_->System(args);
1461       } else if (rs2 == 0) {
1462         const JumpAndLinkRegisterArgs args = {
1463             .dst = 1,
1464             .base = r,
1465             .offset = 0,
1466             .insn_len = 2,
1467         };
1468         insn_consumer_->JumpAndLinkRegister(args);
1469       } else {
1470         const OpArgs args = {
1471             .opcode = OpOpcode::kAdd,
1472             .dst = r,
1473             .src1 = r,
1474             .src2 = rs2,
1475         };
1476         insn_consumer_->Op(args);
1477       }
1478     } else {
1479       if (rs2 == 0) {
1480         const JumpAndLinkRegisterArgs args = {
1481             .dst = 0,
1482             .base = r,
1483             .offset = 0,
1484             .insn_len = 2,
1485         };
1486         insn_consumer_->JumpAndLinkRegister(args);
1487       } else {
1488         const OpArgs args = {
1489             .opcode = OpOpcode::kAdd,
1490             .dst = r,
1491             .src1 = 0,
1492             .src2 = rs2,
1493         };
1494         insn_consumer_->Op(args);
1495       }
1496     }
1497   }
1498 
DecodeCompressedSlli()1499   void DecodeCompressedSlli() {
1500     uint8_t r = GetBits<7, 5>();
1501     uint8_t low_imm = GetBits<2, 5>();
1502     uint8_t high_imm = GetBits<12, 1>();
1503     uint8_t imm = (high_imm << 5) + low_imm;
1504     const ShiftImmArgs args = {
1505         .opcode = ShiftImmOpcode::kSlli,
1506         .dst = r,
1507         .src = r,
1508         .imm = imm,
1509     };
1510     return insn_consumer_->OpImm(args);
1511   }
1512 
DecodeBaseInstruction()1513   uint8_t DecodeBaseInstruction() {
1514     BaseOpcode opcode_bits{GetBits<2, 5>()};
1515 
1516     switch (opcode_bits) {
1517       case BaseOpcode::kLoad:
1518         DecodeLoad<LoadOperandType>();
1519         break;
1520       case BaseOpcode::kLoadFp:
1521         DecodeLoad<FloatOperandType>();
1522         break;
1523       case BaseOpcode::kMiscMem:
1524         DecodeMiscMem();
1525         break;
1526       case BaseOpcode::kOpImm:
1527         DecodeOp<OpImmOpcode, ShiftImmOpcode, BitmanipImmOpcode, 6>();
1528         break;
1529       case BaseOpcode::kAuipc:
1530         DecodeAuipc();
1531         break;
1532       case BaseOpcode::kOpImm32:
1533         DecodeOp<OpImm32Opcode, ShiftImm32Opcode, BitmanipImm32Opcode, 5>();
1534         break;
1535       case BaseOpcode::kStore:
1536         DecodeStore<MemoryDataOperandType>();
1537         break;
1538       case BaseOpcode::kStoreFp:
1539         DecodeStore<FloatOperandType>();
1540         break;
1541       case BaseOpcode::kAmo:
1542         DecodeAmo();
1543         break;
1544       case BaseOpcode::kOp:
1545         DecodeOp<OpOpcode>();
1546         break;
1547       case BaseOpcode::kLui:
1548         DecodeLui();
1549         break;
1550       case BaseOpcode::kOp32:
1551         DecodeOp<Op32Opcode>();
1552         break;
1553       case BaseOpcode::kMAdd:
1554       case BaseOpcode::kMSub:
1555       case BaseOpcode::kNmSub:
1556       case BaseOpcode::kNmAdd:
1557         DecodeFma();
1558         break;
1559       case BaseOpcode::kOpFp:
1560         DecodeOpFp();
1561         break;
1562       case BaseOpcode::vOpV:
1563         DecodeOpV();
1564         break;
1565       case BaseOpcode::kBranch:
1566         DecodeBranch();
1567         break;
1568       case BaseOpcode::kJalr:
1569         DecodeJumpAndLinkRegister();
1570         break;
1571       case BaseOpcode::kJal:
1572         DecodeJumpAndLink();
1573         break;
1574       case BaseOpcode::kSystem:
1575         DecodeSystem();
1576         break;
1577       default:
1578         insn_consumer_->Undefined();
1579     }
1580     return 4;
1581   }
1582 
1583   // Signextend bits from size to the corresponding signed type of sizeof(Type) size.
1584   // If the result of this function is assigned to a wider signed type it'll automatically
1585   // sign-extend.
1586   template <unsigned size, typename Type>
SignExtend(const Type val)1587   static auto SignExtend(const Type val) {
1588     static_assert(std::is_integral_v<Type>, "Only integral types are supported");
1589     static_assert(size > 0 && size < (sizeof(Type) * CHAR_BIT), "Invalid size value");
1590     using SignedType = std::make_signed_t<Type>;
1591     struct {
1592       SignedType val : size;
1593     } holder = {.val = static_cast<SignedType>(val)};
1594     // Compiler takes care of sign-extension of the field with the specified bit-length.
1595     return static_cast<SignedType>(holder.val);
1596   }
1597 
1598  private:
1599   template <uint32_t start, uint32_t size>
GetBits()1600   auto GetBits() {
1601     static_assert((start + size) <= 32 && size > 0, "Invalid start or size value");
1602     using ResultType = std::conditional_t<
1603         size == 1,
1604         bool,
1605         std::conditional_t<size <= 8, uint8_t, std::conditional_t<size <= 16, uint16_t, uint32_t>>>;
1606     uint32_t shifted_val = code_ << (32 - start - size);
1607     return static_cast<ResultType>(shifted_val >> (32 - size));
1608   }
1609 
Undefined()1610   void Undefined() { insn_consumer_->Undefined(); }
1611 
DecodeMiscMem()1612   void DecodeMiscMem() {
1613     uint8_t low_opcode = GetBits<12, 3>();
1614     switch (low_opcode) {
1615       case 0b000: {
1616         uint8_t high_opcode = GetBits<28, 4>();
1617         FenceOpcode opcode = FenceOpcode{high_opcode};
1618         const FenceArgs args = {
1619             .opcode = opcode,
1620             .dst = GetBits<7, 5>(),
1621             .src = GetBits<15, 5>(),
1622             .sw = GetBits<20, 1>(),
1623             .sr = GetBits<21, 1>(),
1624             .so = GetBits<22, 1>(),
1625             .si = GetBits<23, 1>(),
1626             .pw = GetBits<24, 1>(),
1627             .pr = GetBits<25, 1>(),
1628             .po = GetBits<26, 1>(),
1629             .pi = GetBits<27, 1>(),
1630         };
1631         insn_consumer_->Fence(args);
1632         break;
1633       }
1634       case 0b001: {
1635         uint16_t imm = GetBits<20, 12>();
1636         const FenceIArgs args = {
1637             .dst = GetBits<7, 5>(),
1638             .src = GetBits<15, 5>(),
1639             .imm = SignExtend<12>(imm),
1640         };
1641         insn_consumer_->FenceI(args);
1642         break;
1643       }
1644       default:
1645         return Undefined();
1646     }
1647   }
1648 
1649   template <typename OpcodeType>
DecodeOp()1650   void DecodeOp() {
1651     uint8_t low_opcode = GetBits<12, 3>();
1652     uint8_t high_opcode = GetBits<25, 7>();
1653     uint16_t opcode_bits = static_cast<int16_t>(low_opcode | (high_opcode << 3));
1654     OpcodeType opcode{opcode_bits};
1655     OpSingleInputOpcode single_input_opcode{opcode_bits};
1656 
1657     switch (single_input_opcode) {
1658       case OpSingleInputOpcode::kZexth: {
1659         DecodeSingleInputOp(single_input_opcode);
1660         return;
1661       }
1662       default:
1663         break;
1664     }
1665     const OpArgsTemplate<OpcodeType> args = {
1666         .opcode = opcode,
1667         .dst = GetBits<7, 5>(),
1668         .src1 = GetBits<15, 5>(),
1669         .src2 = GetBits<20, 5>(),
1670     };
1671     insn_consumer_->Op(args);
1672   }
1673 
DecodeSingleInputOp(OpSingleInputOpcode opcode)1674   void DecodeSingleInputOp(OpSingleInputOpcode opcode) {
1675     uint8_t src1 = GetBits<15, 5>();
1676     uint8_t src2 = GetBits<20, 5>();
1677 
1678     if (src2 != 0) {
1679       return Undefined();
1680     }
1681     const OpSingleInputArgs args = {.opcode = opcode, .dst = GetBits<7, 5>(), .src = src1};
1682     insn_consumer_->OpSingleInput(args);
1683   }
1684 
DecodeAmo()1685   void DecodeAmo() {
1686     uint8_t low_opcode = GetBits<12, 3>();
1687     uint8_t high_opcode = GetBits<27, 5>();
1688     // lr instruction must have rs2 == 0
1689     if (high_opcode == 0b00010 && GetBits<20, 5>() != 0) {
1690       return Undefined();
1691     }
1692     AmoOpcode opcode = AmoOpcode{high_opcode};
1693     MemoryDataOperandType operand_type = MemoryDataOperandType{low_opcode};
1694     const AmoArgs args = {
1695         .opcode = opcode,
1696         .operand_type = operand_type,
1697         .dst = GetBits<7, 5>(),
1698         .src1 = GetBits<15, 5>(),
1699         .src2 = GetBits<20, 5>(),
1700         .rl = GetBits<25, 1>(),
1701         .aq = GetBits<26, 1>(),
1702     };
1703     insn_consumer_->Amo(args);
1704   }
1705 
DecodeFma()1706   void DecodeFma() {
1707     uint8_t operand_type = GetBits<25, 2>();
1708     uint8_t opcode_bits = GetBits<2, 2>();
1709     const FmaArgs args = {
1710         .opcode = FmaOpcode{opcode_bits},
1711         .operand_type = FloatOperandType{operand_type},
1712         .dst = GetBits<7, 5>(),
1713         .src1 = GetBits<15, 5>(),
1714         .src2 = GetBits<20, 5>(),
1715         .src3 = GetBits<27, 5>(),
1716         .rm = GetBits<12, 3>(),
1717     };
1718     insn_consumer_->Fma(args);
1719   }
1720 
DecodeLui()1721   void DecodeLui() {
1722     int32_t imm = GetBits<12, 20>();
1723     const UpperImmArgs args = {
1724         .dst = GetBits<7, 5>(),
1725         .imm = imm << 12,
1726     };
1727     insn_consumer_->Lui(args);
1728   }
1729 
DecodeAuipc()1730   void DecodeAuipc() {
1731     int32_t imm = GetBits<12, 20>();
1732     const UpperImmArgs args = {
1733         .dst = GetBits<7, 5>(),
1734         .imm = imm << 12,
1735     };
1736     insn_consumer_->Auipc(args);
1737   }
1738 
1739   template <typename OperandTypeEnum>
DecodeLoad()1740   void DecodeLoad() {
1741     OperandTypeEnum operand_type;
1742     if constexpr (std::is_same_v<OperandTypeEnum, FloatOperandType>) {
1743       auto decoded_operand_type = kLoadStoreWidthToOperandType[GetBits<12, 3>()];
1744       if (decoded_operand_type.is_vector_instruction) {
1745         if (GetBits<28, 1>() == 1) {
1746           return Undefined();
1747         }
1748         switch (GetBits<26, 2>()) {
1749           case 0b00: {
1750             const VLoadUnitStrideArgs args = {
1751                 .opcode = VLUmOpOpcode{GetBits<20, 5>()},
1752                 .width = decoded_operand_type.eew,
1753                 .vm = GetBits<25, 1>(),
1754                 .nf = GetBits<29, 3>(),
1755                 .dst = GetBits<7, 5>(),
1756                 .src = GetBits<15, 5>(),
1757             };
1758             return insn_consumer_->OpVector(args);
1759           }
1760           case 0b01:
1761           case 0b11: {
1762             const VLoadIndexedArgs args = {
1763                 .width = decoded_operand_type.eew,
1764                 .vm = GetBits<25, 1>(),
1765                 .ordered = GetBits<27, 1>(),
1766                 .nf = GetBits<29, 3>(),
1767                 .dst = GetBits<7, 5>(),
1768                 .src = GetBits<15, 5>(),
1769                 .idx = GetBits<20, 5>(),
1770             };
1771             return insn_consumer_->OpVector(args);
1772           }
1773           case 0b10: {
1774             const VLoadStrideArgs args = {
1775                 .width = decoded_operand_type.eew,
1776                 .vm = GetBits<25, 1>(),
1777                 .ordered = GetBits<27, 1>(),
1778                 .nf = GetBits<29, 3>(),
1779                 .dst = GetBits<7, 5>(),
1780                 .src = GetBits<15, 5>(),
1781                 .std = GetBits<20, 5>(),
1782             };
1783             return insn_consumer_->OpVector(args);
1784           }
1785           default:
1786             return Undefined();
1787         }
1788         return Undefined();
1789       }
1790       operand_type = decoded_operand_type.size;
1791     } else {
1792       operand_type = OperandTypeEnum{GetBits<12, 3>()};
1793     }
1794     const LoadArgsTemplate<OperandTypeEnum> args = {
1795         .operand_type = operand_type,
1796         .dst = GetBits<7, 5>(),
1797         .src = GetBits<15, 5>(),
1798         .offset = SignExtend<12>(GetBits<20, 12>()),
1799     };
1800     insn_consumer_->Load(args);
1801   }
1802 
1803   template <typename OperandTypeEnum>
DecodeStore()1804   void DecodeStore() {
1805     OperandTypeEnum operand_type;
1806     if constexpr (std::is_same_v<OperandTypeEnum, FloatOperandType>) {
1807       auto decoded_operand_type = kLoadStoreWidthToOperandType[GetBits<12, 3>()];
1808       if (decoded_operand_type.is_vector_instruction) {
1809         if (GetBits<28, 1>() == 1) {
1810           return Undefined();
1811         }
1812         switch (GetBits<26, 2>()) {
1813           case 0b00: {
1814             const VStoreUnitStrideArgs args = {
1815                 .opcode = VSUmOpOpcode{GetBits<20, 5>()},
1816                 .width = decoded_operand_type.eew,
1817                 .vm = GetBits<25, 1>(),
1818                 .nf = GetBits<29, 3>(),
1819                 .src = GetBits<15, 5>(),
1820                 .data = GetBits<7, 5>(),
1821             };
1822             return insn_consumer_->OpVector(args);
1823           }
1824           case 0b01:
1825           case 0b11: {
1826             const VStoreIndexedArgs args = {
1827                 .width = decoded_operand_type.eew,
1828                 .vm = GetBits<25, 1>(),
1829                 .ordered = GetBits<27, 1>(),
1830                 .nf = GetBits<29, 3>(),
1831                 .src = GetBits<15, 5>(),
1832                 .idx = GetBits<20, 5>(),
1833                 .data = GetBits<7, 5>(),
1834             };
1835             return insn_consumer_->OpVector(args);
1836           }
1837           case 0b10: {
1838             const VStoreStrideArgs args = {
1839                 .width = decoded_operand_type.eew,
1840                 .vm = GetBits<25, 1>(),
1841                 .ordered = GetBits<27, 1>(),
1842                 .nf = GetBits<29, 3>(),
1843                 .src = GetBits<15, 5>(),
1844                 .std = GetBits<20, 5>(),
1845                 .data = GetBits<7, 5>(),
1846             };
1847             return insn_consumer_->OpVector(args);
1848           }
1849           default:
1850             return Undefined();
1851         }
1852         return Undefined();
1853       }
1854 
1855       operand_type = decoded_operand_type.size;
1856     } else {
1857       operand_type = OperandTypeEnum{GetBits<12, 3>()};
1858     }
1859 
1860     uint16_t low_imm = GetBits<7, 5>();
1861     uint16_t high_imm = GetBits<25, 7>();
1862 
1863     const StoreArgsTemplate<OperandTypeEnum> args = {
1864         .operand_type = operand_type,
1865         .src = GetBits<15, 5>(),
1866         .offset = SignExtend<12>(static_cast<int16_t>(low_imm | (high_imm << 5))),
1867         .data = GetBits<20, 5>(),
1868     };
1869     insn_consumer_->Store(args);
1870   }
1871 
1872   template <typename OpOpcodeType,
1873             typename ShiftOpcodeType,
1874             typename BitmanipOpcodeType,
1875             uint32_t kShiftFieldSize>
DecodeOp()1876   void DecodeOp() {
1877     uint8_t low_opcode = GetBits<12, 3>();
1878     if (low_opcode != 0b001 && low_opcode != 0b101) {
1879       OpOpcodeType opcode{low_opcode};
1880 
1881       uint16_t imm = GetBits<20, 12>();
1882 
1883       const OpImmArgsTemplate<OpOpcodeType> args = {
1884           .opcode = opcode,
1885           .dst = GetBits<7, 5>(),
1886           .src = GetBits<15, 5>(),
1887           .imm = SignExtend<12>(imm),
1888       };
1889       insn_consumer_->OpImm(args);
1890     } else if ((GetBits<31, 1>() + GetBits<20 + kShiftFieldSize, 10 - kShiftFieldSize>()) ==
1891                0) {  // For Canonical Shift Instructions from RV64G the opcode contains all
1892                      // zeros except for the 30th (second highest) bit.
1893       uint16_t high_opcode = GetBits<20 + kShiftFieldSize, 12 - kShiftFieldSize>();
1894       ShiftOpcodeType opcode{
1895           static_cast<std::underlying_type_t<ShiftOpcodeType>>(low_opcode | (high_opcode << 3))};
1896 
1897       const ShiftImmArgsTemplate<ShiftOpcodeType> args = {
1898           .opcode = opcode,
1899           .dst = GetBits<7, 5>(),
1900           .src = GetBits<15, 5>(),
1901           .imm = GetBits<20, kShiftFieldSize>(),
1902       };
1903       insn_consumer_->OpImm(args);
1904     } else {
1905       uint8_t shamt = GetBits<20, kShiftFieldSize>();
1906       uint16_t high_opcode = GetBits<20 + kShiftFieldSize, 12 - kShiftFieldSize>();
1907       BitmanipOpcodeType opcode{static_cast<uint16_t>(low_opcode | (high_opcode << 3))};
1908       bool has_shamt = false;
1909 
1910       switch ((BitmanipImmOpcode)opcode) {
1911         case BitmanipImmOpcode::kRori:
1912         case BitmanipImmOpcode::kBclri:
1913         case BitmanipImmOpcode::kBexti:
1914         case BitmanipImmOpcode::kBinvi:
1915         case BitmanipImmOpcode::kBseti:
1916           has_shamt = true;
1917           break;
1918         default:
1919           break;
1920       }
1921 
1922       switch ((BitmanipImm32Opcode)opcode) {
1923         case BitmanipImm32Opcode::kRoriw:
1924         case BitmanipImm32Opcode::kSlliuw:
1925           has_shamt = true;
1926           break;
1927         default:
1928           break;
1929       }
1930       // TODO(b/291851792): Refactor instructions with shamt into ShiftImmArgs
1931       if (!has_shamt) {
1932         high_opcode = GetBits<20, 12>();
1933         opcode = BitmanipOpcodeType{static_cast<uint16_t>(low_opcode | (high_opcode << 3))};
1934         shamt = 0;
1935       }
1936       const BitmanipImmArgsTemplate<BitmanipOpcodeType> args = {
1937           .opcode = opcode,
1938           .dst = GetBits<7, 5>(),
1939           .src = GetBits<15, 5>(),
1940           .shamt = shamt,
1941       };
1942       insn_consumer_->OpImm(args);
1943     }
1944   }
1945 
DecodeBranch()1946   void DecodeBranch() {
1947     BranchOpcode opcode{GetBits<12, 3>()};
1948 
1949     // Decode the offset.
1950     auto low_imm = GetBits<8, 4>();
1951     auto mid_imm = GetBits<25, 6>();
1952     auto bit11_imm = GetBits<7, 1>();
1953     auto bit12_imm = GetBits<31, 1>();
1954     auto offset =
1955         static_cast<int16_t>(low_imm | (mid_imm << 4) | (bit11_imm << 10) | (bit12_imm << 11));
1956 
1957     const BranchArgs args = {
1958         .opcode = opcode,
1959         .src1 = GetBits<15, 5>(),
1960         .src2 = GetBits<20, 5>(),
1961         // The offset is encoded as 2-byte units, we need to multiply by 2.
1962         .offset = SignExtend<13>(static_cast<int16_t>(offset * 2)),
1963     };
1964     insn_consumer_->CompareAndBranch(args);
1965   }
1966 
DecodeJumpAndLink()1967   void DecodeJumpAndLink() {
1968     // Decode the offset.
1969     auto low_imm = GetBits<21, 10>();
1970     auto mid_imm = GetBits<12, 8>();
1971     auto bit11_imm = GetBits<20, 1>();
1972     auto bit20_imm = GetBits<31, 1>();
1973     auto offset =
1974         static_cast<int32_t>(low_imm | (bit11_imm << 10) | (mid_imm << 11) | (bit20_imm << 19));
1975 
1976     const JumpAndLinkArgs args = {
1977         .dst = GetBits<7, 5>(),
1978         // The offset is encoded as 2-byte units, we need to multiply by 2.
1979         .offset = SignExtend<21>(offset * 2),
1980         .insn_len = 4,
1981     };
1982     insn_consumer_->JumpAndLink(args);
1983   }
1984 
DecodeOpFp()1985   void DecodeOpFp() {
1986     // Bit #29 = 1: means rm is an opcode extension and not operand.
1987     // Bit #30 = 1: means rs2 is an opcode extension and not operand.
1988     // Bit #31 = 1: selects general purpose register instead of floating point register as target.
1989     uint8_t operand_type = GetBits<25, 2>();
1990     uint8_t opcode_bits = GetBits<27, 2>();
1991     uint8_t rd = GetBits<7, 5>();
1992     uint8_t rs1 = GetBits<15, 5>();
1993     uint8_t rs2 = GetBits<20, 5>();
1994     uint8_t rm = GetBits<12, 3>();
1995     switch (GetBits<29, 3>()) {
1996       case 0b000: {
1997         const OpFpArgs args = {
1998             .opcode = OpFpOpcode{opcode_bits},
1999             .operand_type = FloatOperandType{operand_type},
2000             .dst = rd,
2001             .src1 = rs1,
2002             .src2 = rs2,
2003             .rm = rm,
2004         };
2005         return insn_consumer_->OpFp(args);
2006       }
2007       case 0b001: {
2008         uint8_t no_rounding_opcode_bits = (opcode_bits << 3) + rm;
2009         OpFpNoRoundingOpcode no_rounding_opcode = OpFpNoRoundingOpcode{no_rounding_opcode_bits};
2010         if (no_rounding_opcode == Decoder::OpFpNoRoundingOpcode::kFSgnj && rs1 == rs2) {
2011           const OpFpSingleInputNoRoundingArgs args = {
2012               .opcode = OpFpSingleInputNoRoundingOpcode::kFmv,
2013               .operand_type = FloatOperandType{operand_type},
2014               .dst = rd,
2015               .src = rs1,
2016           };
2017           return insn_consumer_->OpFpSingleInputNoRounding(args);
2018         }
2019         const OpFpNoRoundingArgs args = {
2020             .opcode = no_rounding_opcode,
2021             .operand_type = FloatOperandType{operand_type},
2022             .dst = rd,
2023             .src1 = rs1,
2024             .src2 = rs2,
2025         };
2026         return insn_consumer_->OpFpNoRounding(args);
2027       }
2028       case 0b010: {
2029         if (opcode_bits == 0) {
2030           // Conversion from one float to the same float type is not supported.
2031           if (operand_type == rs2) {
2032             return Undefined();
2033           }
2034           // Values larger than 0b11 are reserved in Fcvt.
2035           if (rs2 > 0b11) {
2036             return Undefined();
2037           }
2038           const FcvtFloatToFloatArgs args = {
2039               .dst_type = FloatOperandType{operand_type},
2040               .src_type = FloatOperandType{rs2},
2041               .dst = rd,
2042               .src = rs1,
2043               .rm = rm,
2044           };
2045           return insn_consumer_->Fcvt(args);
2046         }
2047         uint8_t opcode = (opcode_bits << 5) + rs2;
2048         const OpFpSingleInputArgs args = {
2049             .opcode = OpFpSingleInputOpcode{opcode},
2050             .operand_type = FloatOperandType{operand_type},
2051             .dst = rd,
2052             .src = rs1,
2053             .rm = rm,
2054         };
2055         return insn_consumer_->OpFpSingleInput(args);
2056       }
2057       case 0b101: {
2058         uint8_t opcode = (opcode_bits << 3) + rm;
2059         const OpFpGpRegisterTargetNoRoundingArgs args = {
2060             .opcode = OpFpGpRegisterTargetNoRoundingOpcode{opcode},
2061             .operand_type = FloatOperandType{operand_type},
2062             .dst = rd,
2063             .src1 = rs1,
2064             .src2 = rs2,
2065         };
2066         return insn_consumer_->OpFpGpRegisterTargetNoRounding(args);
2067       }
2068       case 0b110:
2069         switch (opcode_bits) {
2070           case 0b00: {
2071             const FcvtFloatToIntegerArgs args = {
2072                 .dst_type = FcvtOperandType{rs2},
2073                 .src_type = FloatOperandType{operand_type},
2074                 .dst = rd,
2075                 .src = rs1,
2076                 .rm = rm,
2077             };
2078             return insn_consumer_->Fcvt(args);
2079           }
2080           case 0b10: {
2081             const FcvtIntegerToFloatArgs args = {
2082                 .dst_type = FloatOperandType{operand_type},
2083                 .src_type = FcvtOperandType{rs2},
2084                 .dst = rd,
2085                 .src = rs1,
2086                 .rm = rm,
2087             };
2088             return insn_consumer_->Fcvt(args);
2089           }
2090           default:
2091             return Undefined();
2092         }
2093       case 0b111: {
2094         uint16_t opcode = (opcode_bits << 8) + (rs2 << 3) + rm;
2095         switch (rm) {
2096           case 0b001: {
2097             const OpFpGpRegisterTargetSingleInputNoRoundingArgs args = {
2098                 .opcode = OpFpGpRegisterTargetSingleInputNoRoundingOpcode{opcode},
2099                 .operand_type = FloatOperandType{operand_type},
2100                 .dst = rd,
2101                 .src = rs1,
2102             };
2103             return insn_consumer_->OpFpGpRegisterTargetSingleInputNoRounding(args);
2104           }
2105           case 0b000: {
2106             if (opcode_bits == 0b00) {
2107               const FmvFloatToIntegerArgs args = {
2108                   .operand_type = FloatOperandType{operand_type},
2109                   .dst = rd,
2110                   .src = rs1,
2111               };
2112               return insn_consumer_->FmvFloatToInteger(args);
2113             } else if (opcode_bits == 0b10) {
2114               const FmvIntegerToFloatArgs args = {
2115                   .operand_type = FloatOperandType{operand_type},
2116                   .dst = rd,
2117                   .src = rs1,
2118               };
2119               return insn_consumer_->FmvIntegerToFloat(args);
2120             } else {
2121               return Undefined();
2122             }
2123           }
2124           default:
2125             return Undefined();
2126         }
2127       }
2128       default:
2129         return Undefined();
2130     }
2131   }
2132 
DecodeOpV()2133   void DecodeOpV() {
2134     uint8_t low_opcode = GetBits<12, 3>();
2135     bool vm = GetBits<25, 1>();
2136     uint8_t opcode = GetBits<26, 6>();
2137     uint8_t dst = GetBits<7, 5>();
2138     // Note: in vector instructions vs2 field is 2nd operand while vs1 field is 3rd operand.
2139     // FMA instructions are exception, but there are not that many of these.
2140     uint8_t src1 = GetBits<20, 5>();
2141     uint8_t src2 = GetBits<15, 5>();
2142     switch (low_opcode) {
2143       case 0b000: {
2144         const VOpIVvArgs args = {
2145             .opcode = VOpIVvOpcode{opcode},
2146             .vm = vm,
2147             .dst = dst,
2148             .src1 = src1,
2149             .src2 = src2,
2150         };
2151         return insn_consumer_->OpVector(args);
2152       }
2153       case 0b001: {
2154         const VOpFVvArgs args = {
2155             .opcode = VOpFVvOpcode{opcode},
2156             .vm = vm,
2157             .dst = dst,
2158             .src1 = src1,
2159             .src2 = src2,
2160         };
2161         return insn_consumer_->OpVector(args);
2162       }
2163       case 0b010: {
2164         const VOpMVvArgs args = {
2165             .opcode = VOpMVvOpcode{opcode},
2166             .vm = vm,
2167             .dst = dst,
2168             .src1 = src1,
2169             .src2 = src2,
2170         };
2171         return insn_consumer_->OpVector(args);
2172       }
2173       case 0b011: {
2174         const VOpIViArgs args = {
2175             .opcode = VOpIViOpcode{opcode},
2176             .vm = vm,
2177             .dst = dst,
2178             .src = src1,
2179             .uimm = src2,
2180         };
2181         return insn_consumer_->OpVector(args);
2182       }
2183       case 0b100: {
2184         const VOpIVxArgs args = {
2185             .opcode = VOpIVxOpcode{opcode},
2186             .vm = vm,
2187             .dst = dst,
2188             .src1 = src1,
2189             .src2 = src2,
2190         };
2191         return insn_consumer_->OpVector(args);
2192       }
2193       case 0b101: {
2194         const VOpFVfArgs args = {
2195             .opcode = VOpFVfOpcode{opcode},
2196             .vm = vm,
2197             .dst = dst,
2198             .src1 = src1,
2199             .src2 = src2,
2200         };
2201         return insn_consumer_->OpVector(args);
2202       }
2203       case 0b110: {
2204         const VOpMVxArgs args = {
2205             .opcode = VOpMVxOpcode{opcode},
2206             .vm = vm,
2207             .dst = dst,
2208             .src1 = src1,
2209             .src2 = src2,
2210         };
2211         return insn_consumer_->OpVector(args);
2212       }
2213       case 0b111:
2214         if (GetBits<31, 1>() == 0) {
2215           const VsetvliArgs args = {
2216               .dst = GetBits<7, 5>(),
2217               .src = GetBits<15, 5>(),
2218               .vtype = GetBits<20, 11>(),
2219           };
2220           return insn_consumer_->Vsetvli(args);
2221         } else if (GetBits<30, 1>() == 1) {
2222           const VsetivliArgs args = {
2223               .dst = GetBits<7, 5>(),
2224               .avl = GetBits<15, 5>(),
2225               .vtype = GetBits<20, 10>(),
2226           };
2227           return insn_consumer_->Vsetivli(args);
2228         } else if (GetBits<25, 6>() == 0) {
2229           const VsetvlArgs args = {
2230               .dst = GetBits<7, 5>(),
2231               .src1 = GetBits<15, 5>(),
2232               .src2 = GetBits<20, 5>(),
2233           };
2234           return insn_consumer_->Vsetvl(args);
2235         }
2236     }
2237   }
2238 
DecodeSystem()2239   void DecodeSystem() {
2240     uint8_t low_opcode = GetBits<12, 2>();
2241     if (low_opcode == 0b00) {
2242       uint32_t opcode = GetBits<7, 25>();
2243       const SystemArgs args = {
2244           .opcode = SystemOpcode{opcode},
2245       };
2246       return insn_consumer_->System(args);
2247     }
2248     if (GetBits<14, 1>()) {
2249       CsrImmOpcode opcode = CsrImmOpcode{low_opcode};
2250       const CsrImmArgs args = {
2251           .opcode = opcode,
2252           .dst = GetBits<7, 5>(),
2253           .imm = GetBits<15, 5>(),
2254           .csr = GetBits<20, 12>(),
2255       };
2256       return insn_consumer_->Csr(args);
2257     }
2258     CsrOpcode opcode = CsrOpcode{low_opcode};
2259     const CsrArgs args = {
2260         .opcode = opcode,
2261         .dst = GetBits<7, 5>(),
2262         .src = GetBits<15, 5>(),
2263         .csr = GetBits<20, 12>(),
2264     };
2265     return insn_consumer_->Csr(args);
2266   }
2267 
DecodeJumpAndLinkRegister()2268   void DecodeJumpAndLinkRegister() {
2269     if (GetBits<12, 3>() != 0b000) {
2270       Undefined();
2271       return;
2272     }
2273     // Decode sign-extend offset.
2274     int16_t offset = GetBits<20, 12>();
2275     offset = static_cast<int16_t>(offset << 4) >> 4;
2276 
2277     const JumpAndLinkRegisterArgs args = {
2278         .dst = GetBits<7, 5>(),
2279         .base = GetBits<15, 5>(),
2280         .offset = offset,
2281         .insn_len = 4,
2282     };
2283     insn_consumer_->JumpAndLinkRegister(args);
2284   }
2285 
2286   enum class BaseOpcode {
2287     kLoad = 0b00'000,
2288     kLoadFp = 0b00'001,
2289     kCustom0 = 0b00'010,
2290     kMiscMem = 0b00'011,
2291     kOpImm = 0b00'100,
2292     kAuipc = 0b00'101,
2293     kOpImm32 = 0b00'110,
2294     // Reserved 0b00'111,
2295     kStore = 0b01'000,
2296     kStoreFp = 0b01'001,
2297     kCustom1 = 0b01'010,
2298     kAmo = 0b01'011,
2299     kOp = 0b01'100,
2300     kLui = 0b01'101,
2301     kOp32 = 0b01'110,
2302     // Reserved 0b01'111,
2303     kMAdd = 0b10'000,
2304     kMSub = 0b10'001,
2305     kNmSub = 0b10'010,
2306     kNmAdd = 0b10'011,
2307     kOpFp = 0b10'100,
2308     vOpV = 0b10'101,
2309     kCustom2 = 0b10'110,
2310     // Reserved 0b10'111,
2311     kBranch = 0b11'000,
2312     kJalr = 0b11'001,
2313     // Reserved 0b11'010,
2314     kJal = 0b11'011,
2315     kSystem = 0b11'100,
2316     // Reserved 0b11'101,
2317     kCustom3 = 0b11'110,
2318     // Reserved 0b11'111,
2319   };
2320 
2321   enum class CompressedOpcode {
2322     kAddi4spn = 0b00'000,
2323     kFld = 0b001'00,
2324     kLw = 0b010'00,
2325     kLd = 0b011'00,
2326     // Reserved 0b00'100
2327     kFsd = 0b101'00,
2328     kSw = 0b110'00,
2329     kSd = 0b111'00,
2330     kAddi = 0b000'01,
2331     kAddiw = 0b001'01,
2332     kLi = 0b010'01,
2333     kLui_Addi16sp = 0b011'01,
2334     kMisc_Alu = 0b100'01,
2335     kJ = 0b101'01,
2336     kBeqz = 0b110'01,
2337     kBnez = 0b111'01,
2338     kSlli = 0b000'10,
2339     kFldsp = 0b001'10,
2340     kLwsp = 0b010'10,
2341     kLdsp = 0b011'10,
2342     kJr_Jalr_Mv_Add = 0b100'10,
2343     kFsdsp = 0b101'10,
2344     kSwsp = 0b110'10,
2345     kSdsp = 0b111'10,
2346     // instruction with 0bxxx'11 opcodes are not compressed instruction and can not be in this
2347     // table.
2348   };
2349 
2350   static constexpr struct {
2351     bool is_vector_instruction;
2352     union {
2353       FloatOperandType size;
2354       MemoryDataOperandType eew;
2355     };
2356   } kLoadStoreWidthToOperandType[8] = {
2357       {.is_vector_instruction = true, .eew = MemoryDataOperandType::k8bit},
2358       {.is_vector_instruction = false, .size = FloatOperandType::kHalf},
2359       {.is_vector_instruction = false, .size = FloatOperandType::kFloat},
2360       {.is_vector_instruction = false, .size = FloatOperandType::kDouble},
2361       {.is_vector_instruction = false, .size = FloatOperandType::kQuad},
2362       {.is_vector_instruction = true, .eew = MemoryDataOperandType::k16bit},
2363       {.is_vector_instruction = true, .eew = MemoryDataOperandType::k32bit},
2364       {.is_vector_instruction = true, .eew = MemoryDataOperandType::k64bit}};
2365 
2366   InsnConsumer* insn_consumer_;
2367   uint32_t code_;
2368 };
2369 
2370 }  // namespace berberis
2371 
2372 #endif  // BERBERIS_DECODER_RISCV64_DECODER_H_
2373