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