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_SEMANTICS_PLAYER_H_
18 #define BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_
19 
20 #include "berberis/base/overloaded.h"
21 #include "berberis/decoder/riscv64/decoder.h"
22 
23 namespace berberis {
24 
25 // This class expresses the semantics of instructions by calling a sequence of SemanticsListener
26 // callbacks.
27 template <class SemanticsListener>
28 class SemanticsPlayer {
29  public:
30   using CsrName = typename SemanticsListener::CsrName;
31   using Decoder = Decoder<SemanticsPlayer>;
32   using Register = typename SemanticsListener::Register;
33   using Float32 = typename SemanticsListener::Float32;
34   using Float64 = typename SemanticsListener::Float64;
35   using FpRegister = typename SemanticsListener::FpRegister;
36 
SemanticsPlayer(SemanticsListener * listener)37   explicit SemanticsPlayer(SemanticsListener* listener) : listener_(listener) {}
38 
39   // Decoder's InsnConsumer implementation.
40 
Amo(const typename Decoder::AmoArgs & args)41   void Amo(const typename Decoder::AmoArgs& args) {
42     Register arg1 = GetRegOrZero(args.src1);
43     Register arg2 = GetRegOrZero(args.src2);
44     Register result;
45     switch (args.operand_type) {
46       case Decoder::MemoryDataOperandType::k32bit:
47         result = Amo<int32_t>(args.opcode, arg1, arg2, args.aq, args.rl);
48         break;
49       case Decoder::MemoryDataOperandType::k64bit:
50         result = Amo<int64_t>(args.opcode, arg1, arg2, args.aq, args.rl);
51         break;
52       default:
53         Undefined();
54         return;
55     }
56     SetRegOrIgnore(args.dst, result);
57   }
58 
59   template <typename IntType>
Amo(typename Decoder::AmoOpcode opcode,Register arg1,Register arg2,bool aq,bool rl)60   Register Amo(typename Decoder::AmoOpcode opcode, Register arg1, Register arg2, bool aq, bool rl) {
61     if (aq) {
62       if (rl) {
63         return Amo<IntType, true, true>(opcode, arg1, arg2);
64       } else {
65         return Amo<IntType, true, false>(opcode, arg1, arg2);
66       }
67     } else {
68       if (rl) {
69         return Amo<IntType, false, true>(opcode, arg1, arg2);
70       } else {
71         return Amo<IntType, false, false>(opcode, arg1, arg2);
72       }
73     }
74   }
75 
76   template <typename IntType, bool aq, bool rl>
Amo(typename Decoder::AmoOpcode opcode,Register arg1,Register arg2)77   Register Amo(typename Decoder::AmoOpcode opcode, Register arg1, Register arg2) {
78     switch (opcode) {
79       case Decoder::AmoOpcode::kLr:
80         return listener_->template Lr<IntType, aq, rl>(arg1);
81       case Decoder::AmoOpcode::kSc:
82         return listener_->template Sc<IntType, aq, rl>(arg1, arg2);
83       case Decoder::AmoOpcode::kAmoswap:
84         return listener_->template AmoSwap<IntType, aq, rl>(arg1, arg2);
85       case Decoder::AmoOpcode::kAmoadd:
86         return listener_->template AmoAdd<IntType, aq, rl>(arg1, arg2);
87       case Decoder::AmoOpcode::kAmoxor:
88         return listener_->template AmoXor<IntType, aq, rl>(arg1, arg2);
89       case Decoder::AmoOpcode::kAmoand:
90         return listener_->template AmoAnd<IntType, aq, rl>(arg1, arg2);
91       case Decoder::AmoOpcode::kAmoor:
92         return listener_->template AmoOr<IntType, aq, rl>(arg1, arg2);
93       case Decoder::AmoOpcode::kAmomin:
94         return listener_->template AmoMin<std::make_signed_t<IntType>, aq, rl>(arg1, arg2);
95       case Decoder::AmoOpcode::kAmomax:
96         return listener_->template AmoMax<std::make_signed_t<IntType>, aq, rl>(arg1, arg2);
97       case Decoder::AmoOpcode::kAmominu:
98         return listener_->template AmoMin<std::make_unsigned_t<IntType>, aq, rl>(arg1, arg2);
99       case Decoder::AmoOpcode::kAmomaxu:
100         return listener_->template AmoMax<std::make_unsigned_t<IntType>, aq, rl>(arg1, arg2);
101       default:
102         Undefined();
103         return {};
104     }
105   }
106 
Auipc(const typename Decoder::UpperImmArgs & args)107   void Auipc(const typename Decoder::UpperImmArgs& args) {
108     Register result = listener_->Auipc(args.imm);
109     SetRegOrIgnore(args.dst, result);
110   }
111 
CompareAndBranch(const typename Decoder::BranchArgs & args)112   void CompareAndBranch(const typename Decoder::BranchArgs& args) {
113     Register arg1 = GetRegOrZero(args.src1);
114     Register arg2 = GetRegOrZero(args.src2);
115     listener_->CompareAndBranch(args.opcode, arg1, arg2, args.offset);
116   }
117 
Csr(const typename Decoder::CsrArgs & args)118   void Csr(const typename Decoder::CsrArgs& args) {
119     if (args.opcode == Decoder::CsrOpcode::kCsrrw) {
120       if (args.dst != 0) {
121         auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr));
122         if (!csr_supported) {
123           return Undefined();
124         }
125         Register arg = listener_->GetReg(args.src);
126         SetCsr(static_cast<CsrName>(args.csr), arg);
127         listener_->SetReg(args.dst, csr);
128         return;
129       }
130       Register arg = listener_->GetReg(args.src);
131       if (!SetCsr(static_cast<CsrName>(args.csr), arg)) {
132         return Undefined();
133       }
134       return;
135     }
136     auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr));
137     if (!csr_supported) {
138       return Undefined();
139     }
140     if (args.src != 0) {
141       Register arg = listener_->GetReg(args.src);
142       if (!SetCsr(static_cast<CsrName>(args.csr), listener_->UpdateCsr(args.opcode, arg, csr))) {
143         return Undefined();
144       }
145     }
146     SetRegOrIgnore(args.dst, csr);
147   }
148 
Csr(const typename Decoder::CsrImmArgs & args)149   void Csr(const typename Decoder::CsrImmArgs& args) {
150     if (args.opcode == Decoder::CsrImmOpcode::kCsrrwi) {
151       if (args.dst != 0) {
152         auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr));
153         if (!csr_supported) {
154           return Undefined();
155         }
156         if (!SetCsr(static_cast<CsrName>(args.csr), csr)) {
157           return Undefined();
158         }
159         listener_->SetReg(args.dst, csr);
160       }
161       SetCsr(static_cast<CsrName>(args.csr), args.imm);
162       return;
163     }
164     auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr));
165     if (!csr_supported) {
166       return Undefined();
167     }
168     if (args.imm != 0) {
169       if (!SetCsr(static_cast<CsrName>(args.csr),
170                   listener_->UpdateCsr(args.opcode, args.imm, csr))) {
171         return Undefined();
172       }
173     }
174     SetRegOrIgnore(args.dst, csr);
175   }
176 
Fcvt(const typename Decoder::FcvtFloatToFloatArgs & args)177   void Fcvt(const typename Decoder::FcvtFloatToFloatArgs& args) {
178     if (args.dst_type == Decoder::FloatOperandType::kFloat &&
179         args.src_type == Decoder::FloatOperandType::kDouble) {
180       FpRegister arg = GetFRegAndUnboxNan<Float64>(args.src);
181       Register frm = listener_->template GetCsr<CsrName::kFrm>();
182       FpRegister result = listener_->template FCvtFloatToFloat<Float32, Float64>(args.rm, frm, arg);
183       NanBoxAndSetFpReg<Float32>(args.dst, result);
184     } else if (args.dst_type == Decoder::FloatOperandType::kDouble &&
185                args.src_type == Decoder::FloatOperandType::kFloat) {
186       FpRegister arg = GetFRegAndUnboxNan<Float32>(args.src);
187       Register frm = listener_->template GetCsr<CsrName::kFrm>();
188       FpRegister result = listener_->template FCvtFloatToFloat<Float64, Float32>(args.rm, frm, arg);
189       NanBoxAndSetFpReg<Float64>(args.dst, result);
190     } else {
191       Undefined();
192       return;
193     }
194   }
195 
Fcvt(const typename Decoder::FcvtFloatToIntegerArgs & args)196   void Fcvt(const typename Decoder::FcvtFloatToIntegerArgs& args) {
197     switch (args.src_type) {
198       case Decoder::FloatOperandType::kFloat:
199         return FcvtloatToInteger<Float32>(args.dst_type, args.rm, args.dst, args.src);
200       case Decoder::FloatOperandType::kDouble:
201         return FcvtloatToInteger<Float64>(args.dst_type, args.rm, args.dst, args.src);
202       default:
203         return Undefined();
204     }
205   }
206 
207   template <typename FLoatType>
FcvtloatToInteger(typename Decoder::FcvtOperandType dst_type,int8_t rm,int8_t dst,int8_t src)208   void FcvtloatToInteger(typename Decoder::FcvtOperandType dst_type,
209                          int8_t rm,
210                          int8_t dst,
211                          int8_t src) {
212     FpRegister arg = GetFRegAndUnboxNan<FLoatType>(src);
213     Register frm = listener_->template GetCsr<CsrName::kFrm>();
214     Register result;
215     switch (dst_type) {
216       case Decoder::FcvtOperandType::k32bitSigned:
217         result = listener_->template FCvtFloatToInteger<int32_t, FLoatType>(rm, frm, arg);
218         break;
219       case Decoder::FcvtOperandType::k32bitUnsigned:
220         result = listener_->template FCvtFloatToInteger<uint32_t, FLoatType>(rm, frm, arg);
221         break;
222       case Decoder::FcvtOperandType::k64bitSigned:
223         result = listener_->template FCvtFloatToInteger<int64_t, FLoatType>(rm, frm, arg);
224         break;
225       case Decoder::FcvtOperandType::k64bitUnsigned:
226         result = listener_->template FCvtFloatToInteger<uint64_t, FLoatType>(rm, frm, arg);
227         break;
228       default:
229         return Undefined();
230     }
231     SetRegOrIgnore(dst, result);
232   }
233 
Fcvt(const typename Decoder::FcvtIntegerToFloatArgs & args)234   void Fcvt(const typename Decoder::FcvtIntegerToFloatArgs& args) {
235     switch (args.dst_type) {
236       case Decoder::FloatOperandType::kFloat:
237         return FcvtIntegerToFloat<Float32>(args.src_type, args.rm, args.dst, args.src);
238       case Decoder::FloatOperandType::kDouble:
239         return FcvtIntegerToFloat<Float64>(args.src_type, args.rm, args.dst, args.src);
240       default:
241         return Undefined();
242     }
243   }
244 
245   template <typename FloatType>
FcvtIntegerToFloat(typename Decoder::FcvtOperandType src_type,int8_t rm,int8_t dst,int8_t src)246   void FcvtIntegerToFloat(typename Decoder::FcvtOperandType src_type,
247                           int8_t rm,
248                           int8_t dst,
249                           int8_t src) {
250     Register arg = GetRegOrZero(src);
251     Register frm = listener_->template GetCsr<CsrName::kFrm>();
252     FpRegister result;
253     switch (src_type) {
254       case Decoder::FcvtOperandType::k32bitSigned:
255         result = listener_->template FCvtIntegerToFloat<FloatType, int32_t>(rm, frm, arg);
256         break;
257       case Decoder::FcvtOperandType::k32bitUnsigned:
258         result = listener_->template FCvtIntegerToFloat<FloatType, uint32_t>(rm, frm, arg);
259         break;
260       case Decoder::FcvtOperandType::k64bitSigned:
261         result = listener_->template FCvtIntegerToFloat<FloatType, int64_t>(rm, frm, arg);
262         break;
263       case Decoder::FcvtOperandType::k64bitUnsigned:
264         result = listener_->template FCvtIntegerToFloat<FloatType, uint64_t>(rm, frm, arg);
265         break;
266       default:
267         Undefined();
268         return;
269     }
270     NanBoxAndSetFpReg<FloatType>(dst, result);
271   }
272 
Fma(const typename Decoder::FmaArgs & args)273   void Fma(const typename Decoder::FmaArgs& args) {
274     switch (args.operand_type) {
275       case Decoder::FloatOperandType::kFloat:
276         return Fma<Float32>(args.opcode, args.rm, args.dst, args.src1, args.src2, args.src3);
277         break;
278       case Decoder::FloatOperandType::kDouble:
279         return Fma<Float64>(args.opcode, args.rm, args.dst, args.src1, args.src2, args.src3);
280         break;
281       default:
282         return Undefined();
283     }
284   }
285 
286   template <typename FloatType>
Fma(typename Decoder::FmaOpcode opcode,int8_t rm,int8_t dst,int8_t src1,int8_t src2,int8_t src3)287   void Fma(typename Decoder::FmaOpcode opcode,
288            int8_t rm,
289            int8_t dst,
290            int8_t src1,
291            int8_t src2,
292            int8_t src3) {
293     FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1);
294     FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2);
295     FpRegister arg3 = GetFRegAndUnboxNan<FloatType>(src3);
296     Register frm = listener_->template GetCsr<CsrName::kFrm>();
297     FpRegister result;
298     switch (opcode) {
299       case Decoder::FmaOpcode::kFmadd:
300         result = listener_->template FMAdd<FloatType>(rm, frm, arg1, arg2, arg3);
301         break;
302       case Decoder::FmaOpcode::kFmsub:
303         result = listener_->template FMSub<FloatType>(rm, frm, arg1, arg2, arg3);
304         break;
305       // Note (from RISC-V manual): The FNMSUB and FNMADD instructions are counterintuitively named,
306       // owing to the naming of the corresponding instructions in MIPS-IV. The MIPS instructions
307       // were defined to negate the sum, rather than negating the product as the RISC-V instructions
308       // do, so the naming scheme was more rational at the time. The two definitions differ with
309       // respect to signed-zero results. The RISC-V definition matches the behavior of the x86 and
310       // ARM fused multiply-add instructions, but unfortunately the RISC-V FNMSUB and FNMADD
311       // instruction names are swapped compared to x86 and ARM.
312       //
313       // Since even official documentation calls the names “counterintuitive” it's better to use x86
314       // ones for intrinsics.
315       case Decoder::FmaOpcode::kFnmsub:
316         result = listener_->template FNMAdd<FloatType>(rm, frm, arg1, arg2, arg3);
317         break;
318       case Decoder::FmaOpcode::kFnmadd:
319         result = listener_->template FNMSub<FloatType>(rm, frm, arg1, arg2, arg3);
320         break;
321       default:
322         return Undefined();
323     }
324     result = CanonicalizeNan<FloatType>(result);
325     NanBoxAndSetFpReg<FloatType>(dst, result);
326   }
327 
Fence(const typename Decoder::FenceArgs & args)328   void Fence(const typename Decoder::FenceArgs& args) {
329     listener_->Fence(args.opcode,
330                      // args.src is currently unused - read below.
331                      Register{},
332                      args.sw,
333                      args.sr,
334                      args.so,
335                      args.si,
336                      args.pw,
337                      args.pr,
338                      args.po,
339                      args.pi);
340     // The unused fields in the FENCE instructions — args.src and args.dst — are reserved for
341     // finer-grain fences in future extensions. For forward compatibility, base implementations
342     // shall ignore these fields, and standard software shall zero these fields. Likewise, many
343     // args.opcode and predecessor/successor set settings are also reserved for future use. Base
344     // implementations shall treat all such reserved configurations as normal fences with
345     // args.opcode=0000, and standard software shall use only non-reserved configurations.
346   }
347 
FenceI(const typename Decoder::FenceIArgs &)348   void FenceI(const typename Decoder::FenceIArgs& /* args */) {
349     // This instruction is not supported on linux. The recommendation is to use the
350     // riscv_flush_icache syscall instead.
351     Undefined();
352     // The unused fields in the FENCE.I instruction, imm[11:0], rs1, and rd, are reserved for
353     // finer-grain fences in future extensions. For forward compatibility, base implementations
354     // shall ignore these fields, and standard software shall zero these fields.
355   }
356 
JumpAndLink(const typename Decoder::JumpAndLinkArgs & args)357   void JumpAndLink(const typename Decoder::JumpAndLinkArgs& args) {
358     Register result = listener_->GetImm(listener_->GetInsnAddr() + args.insn_len);
359     SetRegOrIgnore(args.dst, result);
360     listener_->Branch(args.offset);
361   }
362 
JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs & args)363   void JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs& args) {
364     Register base = GetRegOrZero(args.base);
365     if (args.base == args.dst) {
366       // If base and dst are the same register and the listener implements register mapping
367       // SetRegOrIgnore below will overwrite the original base register and make it invalid for
368       // BranchRegister call. Note that this issue only exists for JumpAndLinkRegister since we
369       // need to write the result before consuming all the arguments.
370       base = listener_->Copy(base);
371     }
372     Register next_insn_addr = listener_->GetImm(listener_->GetInsnAddr() + args.insn_len);
373     SetRegOrIgnore(args.dst, next_insn_addr);
374     listener_->BranchRegister(base, args.offset);
375   }
376 
Load(const typename Decoder::LoadArgs & args)377   void Load(const typename Decoder::LoadArgs& args) {
378     Register arg = GetRegOrZero(args.src);
379     Register result = listener_->Load(args.operand_type, arg, args.offset);
380     SetRegOrIgnore(args.dst, result);
381   }
382 
Load(const typename Decoder::LoadFpArgs & args)383   void Load(const typename Decoder::LoadFpArgs& args) {
384     switch (args.operand_type) {
385       case Decoder::FloatOperandType::kFloat:
386         return Load<Float32>(args.dst, args.src, args.offset);
387       case Decoder::FloatOperandType::kDouble:
388         return Load<Float64>(args.dst, args.src, args.offset);
389       default:
390         return Undefined();
391     }
392   }
393 
394   template <typename FloatType>
Load(int8_t dst,int8_t src,int16_t offset)395   void Load(int8_t dst, int8_t src, int16_t offset) {
396     Register arg = GetRegOrZero(src);
397     FpRegister result = listener_->template LoadFp<FloatType>(arg, offset);
398     NanBoxAndSetFpReg<FloatType>(dst, result);
399   }
400 
Lui(const typename Decoder::UpperImmArgs & args)401   void Lui(const typename Decoder::UpperImmArgs& args) {
402     Register result = listener_->Lui(args.imm);
403     SetRegOrIgnore(args.dst, result);
404   }
405 
Nop()406   void Nop() { listener_->Nop(); }
407 
408   template <typename OpArgs>
Op(OpArgs && args)409   void Op(OpArgs&& args) {
410     Register arg1 = GetRegOrZero(args.src1);
411     Register arg2 = GetRegOrZero(args.src2);
412     Register result = Overloaded{[&](const typename Decoder::OpArgs& args) {
413                                    switch (args.opcode) {
414                                      case Decoder::OpOpcode::kDiv:
415                                        return listener_->template Div<int64_t>(arg1, arg2);
416                                      case Decoder::OpOpcode::kDivu:
417                                        return listener_->template Div<uint64_t>(arg1, arg2);
418                                      case Decoder::OpOpcode::kRem:
419                                        return listener_->template Rem<int64_t>(arg1, arg2);
420                                      case Decoder::OpOpcode::kRemu:
421                                        return listener_->template Rem<uint64_t>(arg1, arg2);
422                                      case Decoder::OpOpcode::kMax:
423                                        return listener_->template Max<int64_t>(arg1, arg2);
424                                      case Decoder::OpOpcode::kMaxu:
425                                        return listener_->template Max<uint64_t>(arg1, arg2);
426                                      case Decoder::OpOpcode::kMin:
427                                        return listener_->template Min<int64_t>(arg1, arg2);
428                                      case Decoder::OpOpcode::kMinu:
429                                        return listener_->template Min<uint64_t>(arg1, arg2);
430                                      case Decoder::OpOpcode::kRol:
431                                        return listener_->template Rol<int64_t>(arg1, arg2);
432                                      case Decoder::OpOpcode::kRor:
433                                        return listener_->template Ror<int64_t>(arg1, arg2);
434                                      case Decoder::OpOpcode::kSh1add:
435                                        return listener_->Sh1add(arg1, arg2);
436                                      case Decoder::OpOpcode::kSh2add:
437                                        return listener_->Sh2add(arg1, arg2);
438                                      case Decoder::OpOpcode::kSh3add:
439                                        return listener_->Sh3add(arg1, arg2);
440                                      case Decoder::OpOpcode::kBclr:
441                                        return listener_->Bclr(arg1, arg2);
442                                      case Decoder::OpOpcode::kBext:
443                                        return listener_->Bext(arg1, arg2);
444                                      case Decoder::OpOpcode::kBinv:
445                                        return listener_->Binv(arg1, arg2);
446                                      case Decoder::OpOpcode::kBset:
447                                        return listener_->Bset(arg1, arg2);
448                                      default:
449                                        return listener_->Op(args.opcode, arg1, arg2);
450                                    }
451                                  },
452                                  [&](const typename Decoder::Op32Args& args) {
453                                    switch (args.opcode) {
454                                      case Decoder::Op32Opcode::kAdduw:
455                                        return listener_->Adduw(arg1, arg2);
456                                      case Decoder::Op32Opcode::kDivw:
457                                        return listener_->template Div<int32_t>(arg1, arg2);
458                                      case Decoder::Op32Opcode::kDivuw:
459                                        return listener_->template Div<uint32_t>(arg1, arg2);
460                                      case Decoder::Op32Opcode::kRemw:
461                                        return listener_->template Rem<int32_t>(arg1, arg2);
462                                      case Decoder::Op32Opcode::kRemuw:
463                                        return listener_->template Rem<uint32_t>(arg1, arg2);
464                                      case Decoder::Op32Opcode::kRolw:
465                                        return listener_->template Rol<int32_t>(arg1, arg2);
466                                      case Decoder::Op32Opcode::kRorw:
467                                        return listener_->template Ror<int32_t>(arg1, arg2);
468                                      case Decoder::Op32Opcode::kSh1adduw:
469                                        return listener_->Sh1adduw(arg1, arg2);
470                                      case Decoder::Op32Opcode::kSh2adduw:
471                                        return listener_->Sh2adduw(arg1, arg2);
472                                      case Decoder::Op32Opcode::kSh3adduw:
473                                        return listener_->Sh3adduw(arg1, arg2);
474                                      default:
475                                        return listener_->Op32(args.opcode, arg1, arg2);
476                                    }
477                                  }}(args);
478     SetRegOrIgnore(args.dst, result);
479   }
480 
OpSingleInput(const typename Decoder::OpSingleInputArgs & args)481   void OpSingleInput(const typename Decoder::OpSingleInputArgs& args) {
482     Register arg = GetRegOrZero(args.src);
483     Register result;
484     switch (args.opcode) {
485       case Decoder::OpSingleInputOpcode::kZexth:
486         result = listener_->Zexth(arg);
487         break;
488       default:
489         Undefined();
490         return;
491     }
492     SetRegOrIgnore(args.dst, result);
493   }
494 
OpFp(const typename Decoder::OpFpArgs & args)495   void OpFp(const typename Decoder::OpFpArgs& args) {
496     switch (args.operand_type) {
497       case Decoder::FloatOperandType::kFloat:
498         return OpFp<Float32>(args.opcode, args.rm, args.dst, args.src1, args.src2);
499       case Decoder::FloatOperandType::kDouble:
500         return OpFp<Float64>(args.opcode, args.rm, args.dst, args.src1, args.src2);
501       default:
502         return Undefined();
503     }
504   }
505 
506   template <typename FloatType>
OpFp(typename Decoder::OpFpOpcode opcode,int8_t rm,int8_t dst,int8_t src1,int8_t src2)507   void OpFp(typename Decoder::OpFpOpcode opcode, int8_t rm, int8_t dst, int8_t src1, int8_t src2) {
508     FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1);
509     FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2);
510     Register frm = listener_->template GetCsr<CsrName::kFrm>();
511     FpRegister result;
512     switch (opcode) {
513       case Decoder::OpFpOpcode::kFAdd:
514         result = listener_->template FAdd<FloatType>(rm, frm, arg1, arg2);
515         break;
516       case Decoder::OpFpOpcode::kFSub:
517         result = listener_->template FSub<FloatType>(rm, frm, arg1, arg2);
518         break;
519       case Decoder::OpFpOpcode::kFMul:
520         result = listener_->template FMul<FloatType>(rm, frm, arg1, arg2);
521         break;
522       case Decoder::OpFpOpcode::kFDiv:
523         result = listener_->template FDiv<FloatType>(rm, frm, arg1, arg2);
524         break;
525       default:
526         return Undefined();
527     }
528     result = CanonicalizeNan<FloatType>(result);
529     NanBoxAndSetFpReg<FloatType>(dst, result);
530   }
531 
OpFpGpRegisterTargetNoRounding(const typename Decoder::OpFpGpRegisterTargetNoRoundingArgs & args)532   void OpFpGpRegisterTargetNoRounding(
533       const typename Decoder::OpFpGpRegisterTargetNoRoundingArgs& args) {
534     switch (args.operand_type) {
535       case Decoder::FloatOperandType::kFloat:
536         return OpFpGpRegisterTargetNoRounding<Float32>(args.opcode, args.dst, args.src1, args.src2);
537       case Decoder::FloatOperandType::kDouble:
538         return OpFpGpRegisterTargetNoRounding<Float64>(args.opcode, args.dst, args.src1, args.src2);
539       default:
540         return Undefined();
541     }
542   }
543 
544   template <typename FloatType>
OpFpGpRegisterTargetNoRounding(typename Decoder::OpFpGpRegisterTargetNoRoundingOpcode opcode,int8_t dst,int8_t src1,int8_t src2)545   void OpFpGpRegisterTargetNoRounding(typename Decoder::OpFpGpRegisterTargetNoRoundingOpcode opcode,
546                                       int8_t dst,
547                                       int8_t src1,
548                                       int8_t src2) {
549     FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1);
550     FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2);
551     Register result;
552     switch (opcode) {
553       case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFle:
554         result = listener_->template Fle<FloatType>(arg1, arg2);
555         break;
556       case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFlt:
557         result = listener_->template Flt<FloatType>(arg1, arg2);
558         break;
559       case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFeq:
560         result = listener_->template Feq<FloatType>(arg1, arg2);
561         break;
562       default:
563         return Undefined();
564     }
565     SetRegOrIgnore(dst, result);
566   }
567 
OpFpGpRegisterTargetSingleInputNoRounding(const typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingArgs & args)568   void OpFpGpRegisterTargetSingleInputNoRounding(
569       const typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingArgs& args) {
570     switch (args.operand_type) {
571       case Decoder::FloatOperandType::kFloat:
572         return OpFpGpRegisterTargetSingleInputNoRounding<Float32>(args.opcode, args.dst, args.src);
573       case Decoder::FloatOperandType::kDouble:
574         return OpFpGpRegisterTargetSingleInputNoRounding<Float64>(args.opcode, args.dst, args.src);
575       default:
576         return Undefined();
577     }
578   }
579 
580   template <typename FloatType>
OpFpGpRegisterTargetSingleInputNoRounding(typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode,int8_t dst,int8_t src)581   void OpFpGpRegisterTargetSingleInputNoRounding(
582       typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode,
583       int8_t dst,
584       int8_t src) {
585     FpRegister arg = GetFRegAndUnboxNan<FloatType>(src);
586     Register result;
587     switch (opcode) {
588       case Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode::kFclass:
589         result = listener_->template FClass<FloatType>(arg);
590         break;
591       default:
592         return Undefined();
593     }
594     SetRegOrIgnore(dst, result);
595   }
596 
OpFpNoRounding(const typename Decoder::OpFpNoRoundingArgs & args)597   void OpFpNoRounding(const typename Decoder::OpFpNoRoundingArgs& args) {
598     switch (args.operand_type) {
599       case Decoder::FloatOperandType::kFloat:
600         return OpFpNoRounding<Float32>(args.opcode, args.dst, args.src1, args.src2);
601       case Decoder::FloatOperandType::kDouble:
602         return OpFpNoRounding<Float64>(args.opcode, args.dst, args.src1, args.src2);
603       default:
604         return Undefined();
605     }
606   }
607 
608   template <typename FloatType>
OpFpNoRounding(const typename Decoder::OpFpNoRoundingOpcode opcode,int8_t dst,int8_t src1,int8_t src2)609   void OpFpNoRounding(const typename Decoder::OpFpNoRoundingOpcode opcode,
610                       int8_t dst,
611                       int8_t src1,
612                       int8_t src2) {
613     FpRegister arg1;
614     FpRegister arg2;
615     FpRegister result;
616     // The sign-injection instructions (FSGNJ, FSGNJN, FSGNJX) do not canonicalize NaNs;
617     // they manipulate the underlying bit patterns directly.
618     bool canonicalize_nan = true;
619     switch (opcode) {
620       case Decoder::OpFpNoRoundingOpcode::kFSgnj:
621       case Decoder::OpFpNoRoundingOpcode::kFSgnjn:
622       case Decoder::OpFpNoRoundingOpcode::kFSgnjx:
623         arg1 = GetFpReg(src1);
624         arg2 = GetFpReg(src2);
625         canonicalize_nan = false;
626         break;
627       default:
628         // Unboxing canonicalizes NaNs.
629         arg1 = GetFRegAndUnboxNan<FloatType>(src1);
630         arg2 = GetFRegAndUnboxNan<FloatType>(src2);
631     }
632     switch (opcode) {
633       case Decoder::OpFpNoRoundingOpcode::kFSgnj:
634         result = listener_->template FSgnj<FloatType>(arg1, arg2);
635         break;
636       case Decoder::OpFpNoRoundingOpcode::kFSgnjn:
637         result = listener_->template FSgnjn<FloatType>(arg1, arg2);
638         break;
639       case Decoder::OpFpNoRoundingOpcode::kFSgnjx:
640         result = listener_->template FSgnjx<FloatType>(arg1, arg2);
641         break;
642       case Decoder::OpFpNoRoundingOpcode::kFMin:
643         result = listener_->template FMin<FloatType>(arg1, arg2);
644         break;
645       case Decoder::OpFpNoRoundingOpcode::kFMax:
646         result = listener_->template FMax<FloatType>(arg1, arg2);
647         break;
648       default:
649         Undefined();
650         return;
651     }
652     if (canonicalize_nan) {
653       result = CanonicalizeNan<FloatType>(result);
654     }
655     NanBoxAndSetFpReg<FloatType>(dst, result);
656   }
657 
FmvFloatToInteger(const typename Decoder::FmvFloatToIntegerArgs & args)658   void FmvFloatToInteger(const typename Decoder::FmvFloatToIntegerArgs& args) {
659     FpRegister arg = GetFpReg(args.src);
660     Register result;
661     switch (args.operand_type) {
662       case Decoder::FloatOperandType::kFloat:
663         result = listener_->template FmvFloatToInteger<int32_t, Float32>(arg);
664         break;
665       case Decoder::FloatOperandType::kDouble:
666         result = listener_->template FmvFloatToInteger<int64_t, Float64>(arg);
667         break;
668       default:
669         Undefined();
670         return;
671     }
672     SetRegOrIgnore(args.dst, result);
673   }
674 
FmvIntegerToFloat(const typename Decoder::FmvIntegerToFloatArgs & args)675   void FmvIntegerToFloat(const typename Decoder::FmvIntegerToFloatArgs& args) {
676     Register arg = GetRegOrZero(args.src);
677     FpRegister result;
678     switch (args.operand_type) {
679       case Decoder::FloatOperandType::kFloat:
680         result = listener_->template FmvIntegerToFloat<Float32, int32_t>(arg);
681         NanBoxAndSetFpReg<Float32>(args.dst, result);
682         break;
683       case Decoder::FloatOperandType::kDouble:
684         result = listener_->template FmvIntegerToFloat<Float64, int64_t>(arg);
685         NanBoxAndSetFpReg<Float64>(args.dst, result);
686         break;
687       default:
688         Undefined();
689         return;
690     }
691   }
692 
OpFpSingleInput(const typename Decoder::OpFpSingleInputArgs & args)693   void OpFpSingleInput(const typename Decoder::OpFpSingleInputArgs& args) {
694     switch (args.operand_type) {
695       case Decoder::FloatOperandType::kFloat:
696         return OpFpSingleInput<Float32>(args.opcode, args.rm, args.dst, args.src);
697       case Decoder::FloatOperandType::kDouble:
698         return OpFpSingleInput<Float64>(args.opcode, args.rm, args.dst, args.src);
699       default:
700         return Undefined();
701     }
702   }
703 
704   template <typename FloatType>
OpFpSingleInput(typename Decoder::OpFpSingleInputOpcode opcode,int8_t rm,int8_t dst,int8_t src)705   void OpFpSingleInput(typename Decoder::OpFpSingleInputOpcode opcode,
706                        int8_t rm,
707                        int8_t dst,
708                        int8_t src) {
709     FpRegister arg = GetFRegAndUnboxNan<FloatType>(src);
710     FpRegister result;
711     Register frm = listener_->template GetCsr<CsrName::kFrm>();
712     switch (opcode) {
713       case Decoder::OpFpSingleInputOpcode::kFSqrt:
714         result = listener_->template FSqrt<FloatType>(rm, frm, arg);
715         break;
716       default:
717         return Undefined();
718     }
719     result = CanonicalizeNan<FloatType>(result);
720     NanBoxAndSetFpReg<FloatType>(dst, result);
721   }
722 
OpFpSingleInputNoRounding(const typename Decoder::OpFpSingleInputNoRoundingArgs & args)723   void OpFpSingleInputNoRounding(const typename Decoder::OpFpSingleInputNoRoundingArgs& args) {
724     switch (args.operand_type) {
725       case Decoder::FloatOperandType::kFloat:
726         return OpFpSingleInputNoRounding<Float32>(args.opcode, args.dst, args.src);
727       case Decoder::FloatOperandType::kDouble:
728         return OpFpSingleInputNoRounding<Float64>(args.opcode, args.dst, args.src);
729       default:
730         return Undefined();
731     }
732   }
733 
734   template <typename FloatType>
OpFpSingleInputNoRounding(typename Decoder::OpFpSingleInputNoRoundingOpcode opcode,int8_t dst,int8_t src)735   void OpFpSingleInputNoRounding(typename Decoder::OpFpSingleInputNoRoundingOpcode opcode,
736                                  int8_t dst,
737                                  int8_t src) {
738     FpRegister arg = GetFRegAndUnboxNan<FloatType>(src);
739     FpRegister result;
740     switch (opcode) {
741       case Decoder::OpFpSingleInputNoRoundingOpcode::kFmv:
742         result = listener_->Fmv(arg);
743         break;
744       default:
745         Undefined();
746         return;
747     }
748     result = CanonicalizeNan<FloatType>(result);
749     NanBoxAndSetFpReg<FloatType>(dst, result);
750   }
751 
752   template <typename OpImmArgs>
OpImm(OpImmArgs && args)753   void OpImm(OpImmArgs&& args) {
754     Register arg = GetRegOrZero(args.src);
755     Register result = Overloaded{[&](const typename Decoder::OpImmArgs& args) {
756                                    return listener_->OpImm(args.opcode, arg, args.imm);
757                                  },
758                                  [&](const typename Decoder::OpImm32Args& args) {
759                                    return listener_->OpImm32(args.opcode, arg, args.imm);
760                                  },
761                                  [&](const typename Decoder::ShiftImmArgs& args) {
762                                    switch (args.opcode) {
763                                      case Decoder::ShiftImmOpcode::kSlli:
764                                        return listener_->Slli(arg, args.imm);
765                                      case Decoder::ShiftImmOpcode::kSrli:
766                                        return listener_->Srli(arg, args.imm);
767                                      case Decoder::ShiftImmOpcode::kSrai:
768                                        return listener_->Srai(arg, args.imm);
769                                      default:
770                                        Undefined();
771                                        return Register{};
772                                    }
773                                  },
774                                  [&](const typename Decoder::ShiftImm32Args& args) {
775                                    return listener_->ShiftImm32(args.opcode, arg, args.imm);
776                                  },
777                                  [&](const typename Decoder::BitmanipImmArgs& args) {
778                                    switch (args.opcode) {
779                                      case Decoder::BitmanipImmOpcode::kClz:
780                                        return listener_->template Clz<int64_t>(arg);
781                                      case Decoder::BitmanipImmOpcode::kCpop:
782                                        return listener_->template Cpop<int64_t>(arg);
783                                      case Decoder::BitmanipImmOpcode::kCtz:
784                                        return listener_->template Ctz<int64_t>(arg);
785                                      case Decoder::BitmanipImmOpcode::kSextb:
786                                        return listener_->template Sext<int8_t>(arg);
787                                      case Decoder::BitmanipImmOpcode::kSexth:
788                                        return listener_->template Sext<int16_t>(arg);
789                                      case Decoder::BitmanipImmOpcode::kOrcb:
790                                        return listener_->Orcb(arg);
791                                      case Decoder::BitmanipImmOpcode::kRev8:
792                                        return listener_->Rev8(arg);
793                                      case Decoder::BitmanipImmOpcode::kRori:
794                                        return listener_->Rori(arg, args.shamt);
795                                      case Decoder::BitmanipImmOpcode::kBclri:
796                                        return listener_->Bclri(arg, args.shamt);
797                                      case Decoder::BitmanipImmOpcode::kBexti:
798                                        return listener_->Bexti(arg, args.shamt);
799                                      case Decoder::BitmanipImmOpcode::kBinvi:
800                                        return listener_->Binvi(arg, args.shamt);
801                                      case Decoder::BitmanipImmOpcode::kBseti:
802                                        return listener_->Bseti(arg, args.shamt);
803                                      default:
804                                        Undefined();
805                                        return Register{};
806                                    }
807                                  },
808                                  [&](const typename Decoder::BitmanipImm32Args& args) {
809                                    switch (args.opcode) {
810                                      case Decoder::BitmanipImm32Opcode::kClzw:
811                                        return listener_->template Clz<int32_t>(arg);
812                                      case Decoder::BitmanipImm32Opcode::kCpopw:
813                                        return listener_->template Cpop<int32_t>(arg);
814                                      case Decoder::BitmanipImm32Opcode::kCtzw:
815                                        return listener_->template Ctz<int32_t>(arg);
816                                      case Decoder::BitmanipImm32Opcode::kRoriw:
817                                        return listener_->Roriw(arg, args.shamt);
818                                      case Decoder::BitmanipImm32Opcode::kSlliuw:
819                                        return listener_->Slliuw(arg, args.shamt);
820                                      default:
821                                        Undefined();
822                                        return Register{};
823                                    }
824                                  }}(args);
825     SetRegOrIgnore(args.dst, result);
826   }
827 
828   // TODO(b/300690740): develop and implement strategy which would allow us to support vector
829   // intrinsics not just in the interpreter.
830 
OpVector(const typename Decoder::VLoadIndexedArgs & args)831   void OpVector(const typename Decoder::VLoadIndexedArgs& args) {
832     Register arg2 = GetRegOrZero(args.src);
833     listener_->OpVector(args, arg2);
834   }
835 
OpVector(const typename Decoder::VLoadStrideArgs & args)836   void OpVector(const typename Decoder::VLoadStrideArgs& args) {
837     Register arg2 = GetRegOrZero(args.src);
838     Register arg3 = GetRegOrZero(args.std);
839     listener_->OpVector(args, arg2, arg3);
840   }
841 
OpVector(const typename Decoder::VLoadUnitStrideArgs & args)842   void OpVector(const typename Decoder::VLoadUnitStrideArgs& args) {
843     Register arg2 = GetRegOrZero(args.src);
844     listener_->OpVector(args, arg2);
845   }
846 
OpVector(const typename Decoder::VOpFVfArgs & args)847   void OpVector(const typename Decoder::VOpFVfArgs& args) {
848     // Note: we don't have information here to chosee between GetFRegAndUnboxNan<Float32> and
849     // GetFRegAndUnboxNan<Float64> because that depends on vtype.
850     FpRegister arg2 = GetFpReg(args.src2);
851     listener_->OpVector(args, arg2);
852   }
853 
OpVector(const typename Decoder::VOpFVvArgs & args)854   void OpVector(const typename Decoder::VOpFVvArgs& args) { listener_->OpVector(args); }
855 
OpVector(const typename Decoder::VOpIViArgs & args)856   void OpVector(const typename Decoder::VOpIViArgs& args) { listener_->OpVector(args); }
857 
OpVector(const typename Decoder::VOpIVvArgs & args)858   void OpVector(const typename Decoder::VOpIVvArgs& args) { listener_->OpVector(args); }
859 
OpVector(const typename Decoder::VOpMVvArgs & args)860   void OpVector(const typename Decoder::VOpMVvArgs& args) { listener_->OpVector(args); }
861 
OpVector(const typename Decoder::VOpIVxArgs & args)862   void OpVector(const typename Decoder::VOpIVxArgs& args) {
863     Register arg2 = GetRegOrZero(args.src2);
864     listener_->OpVector(args, arg2);
865   }
866 
OpVector(const typename Decoder::VOpMVxArgs & args)867   void OpVector(const typename Decoder::VOpMVxArgs& args) {
868     Register arg2 = GetRegOrZero(args.src2);
869     listener_->OpVector(args, arg2);
870   }
871 
OpVector(const typename Decoder::VStoreIndexedArgs & args)872   void OpVector(const typename Decoder::VStoreIndexedArgs& args) {
873     Register arg2 = GetRegOrZero(args.src);
874     listener_->OpVector(args, arg2);
875   }
876 
OpVector(const typename Decoder::VStoreStrideArgs & args)877   void OpVector(const typename Decoder::VStoreStrideArgs& args) {
878     Register arg2 = GetRegOrZero(args.src);
879     Register arg3 = GetRegOrZero(args.std);
880     listener_->OpVector(args, arg2, arg3);
881   }
882 
OpVector(const typename Decoder::VStoreUnitStrideArgs & args)883   void OpVector(const typename Decoder::VStoreUnitStrideArgs& args) {
884     Register arg2 = GetRegOrZero(args.src);
885     listener_->OpVector(args, arg2);
886   }
887 
Vsetivli(const typename Decoder::VsetivliArgs & args)888   void Vsetivli(const typename Decoder::VsetivliArgs& args) {
889     // Note: it's unclear whether args.avl should be treated similarly to x0 in Vsetvli or not.
890     // Keep implementation separate from Vsetvli to make it easier to adjust that code.
891     if (args.avl == 0) {
892       if (args.dst == 0) {
893         auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr();
894         auto [vl, vtype] = listener_->Vtestvli(vl_orig, vtype_orig, args.vtype);
895         SetVlAndVtypeCsr(vl, vtype);
896       } else {
897         auto [vl, vtype] = listener_->Vsetvlimax(args.vtype);
898         SetVlAndVtypeCsr(vl, vtype);
899         listener_->SetReg(args.dst, vl);
900       }
901     } else {
902       auto [vl, vtype] = listener_->Vsetivli(args.avl, args.vtype);
903       SetVlAndVtypeCsr(vl, vtype);
904       SetRegOrIgnore(args.dst, vl);
905     }
906   }
907 
Vsetvl(const typename Decoder::VsetvlArgs & args)908   void Vsetvl(const typename Decoder::VsetvlArgs& args) {
909     Register vtype_new = listener_->GetReg(args.src2);
910     if (args.src1 == 0) {
911       if (args.dst == 0) {
912         auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr();
913         auto [vl, vtype] = listener_->Vtestvl(vl_orig, vtype_orig, vtype_new);
914         SetVlAndVtypeCsr(vl, vtype);
915       } else {
916         auto [vl, vtype] = listener_->Vsetvlmax(vtype_new);
917         SetVlAndVtypeCsr(vl, vtype);
918         listener_->SetReg(args.dst, vl);
919       }
920     } else {
921       Register avl = listener_->GetReg(args.src1);
922       auto [vl, vtype] = listener_->Vsetvl(avl, vtype_new);
923       SetVlAndVtypeCsr(vl, vtype);
924       SetRegOrIgnore(args.dst, vl);
925     }
926   }
927 
Vsetvli(const typename Decoder::VsetvliArgs & args)928   void Vsetvli(const typename Decoder::VsetvliArgs& args) {
929     if (args.src == 0) {
930       if (args.dst == 0) {
931         auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr();
932         auto [vl, vtype] = listener_->Vtestvli(vl_orig, vtype_orig, args.vtype);
933         SetVlAndVtypeCsr(vl, vtype);
934       } else {
935         auto [vl, vtype] = listener_->Vsetvlimax(args.vtype);
936         SetVlAndVtypeCsr(vl, vtype);
937         listener_->SetReg(args.dst, vl);
938       }
939     } else {
940       Register avl = listener_->GetReg(args.src);
941       auto [vl, vtype] = listener_->Vsetvli(avl, args.vtype);
942       SetVlAndVtypeCsr(vl, vtype);
943       SetRegOrIgnore(args.dst, vl);
944     }
945   }
946 
Store(const typename Decoder::StoreArgs & args)947   void Store(const typename Decoder::StoreArgs& args) {
948     Register arg = GetRegOrZero(args.src);
949     Register data = GetRegOrZero(args.data);
950     listener_->Store(args.operand_type, arg, args.offset, data);
951   }
952 
Store(const typename Decoder::StoreFpArgs & args)953   void Store(const typename Decoder::StoreFpArgs& args) {
954     Register arg = GetRegOrZero(args.src);
955     FpRegister data = GetFpReg(args.data);
956     switch (args.operand_type) {
957       case Decoder::FloatOperandType::kFloat:
958         listener_->template StoreFp<Float32>(arg, args.offset, data);
959         break;
960       case Decoder::FloatOperandType::kDouble:
961         listener_->template StoreFp<Float64>(arg, args.offset, data);
962         break;
963       default:
964         Undefined();
965         return;
966     }
967   }
968 
969   // We may have executed a signal handler just after the syscall. If that handler changed x10, then
970   // overwriting x10 here would be incorrect. On the other hand asynchronous signals are unlikely to
971   // change CPU state, so we don't support this at the moment for simplicity."
System(const typename Decoder::SystemArgs & args)972   void System(const typename Decoder::SystemArgs& args) {
973     if (args.opcode != Decoder::SystemOpcode::kEcall) {
974       return Undefined();
975     }
976     Register syscall_nr = GetRegOrZero(17);
977     Register arg0 = GetRegOrZero(10);
978     Register arg1 = GetRegOrZero(11);
979     Register arg2 = GetRegOrZero(12);
980     Register arg3 = GetRegOrZero(13);
981     Register arg4 = GetRegOrZero(14);
982     Register arg5 = GetRegOrZero(15);
983     Register result = listener_->Ecall(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5);
984     SetRegOrIgnore(10, result);
985   }
986 
Undefined()987   void Undefined() { listener_->Undefined(); };
988 
989  private:
GetRegOrZero(uint8_t reg)990   Register GetRegOrZero(uint8_t reg) {
991     return reg == 0 ? listener_->GetImm(0) : listener_->GetReg(reg);
992   }
993 
SetRegOrIgnore(uint8_t reg,Register value)994   void SetRegOrIgnore(uint8_t reg, Register value) {
995     if (reg != 0) {
996       listener_->SetReg(reg, value);
997     }
998   }
999 
1000   // TODO(b/260725458): stop using GetCsrProcessor helper class and define lambda in GetCsr instead.
1001   // We need C++20 (https://wg21.link/P0428R2) for that.
1002   class GetCsrProcessor {
1003    public:
GetCsrProcessor(Register & reg,SemanticsListener * listener)1004     GetCsrProcessor(Register& reg, SemanticsListener* listener) : reg_(reg), listener_(listener) {}
1005     template <CsrName kName>
operator()1006     void operator()() {
1007       reg_ = listener_->template GetCsr<kName>();
1008     }
1009 
1010    private:
1011     Register& reg_;
1012     SemanticsListener* listener_;
1013   };
1014 
GetCsr(CsrName csr)1015   std::tuple<bool, Register> GetCsr(CsrName csr) {
1016     Register reg;
1017     GetCsrProcessor get_csr(reg, listener_);
1018     return {ProcessCsrNameAsTemplateParameter(csr, get_csr), reg};
1019   }
1020 
1021   // TODO(b/260725458): stop using SetCsrProcessor helper class and define lambda in SetCsr instead.
1022   // We need C++20 (https://wg21.link/P0428R2) for that.
1023   class SetCsrImmProcessor {
1024    public:
SetCsrImmProcessor(uint8_t imm,SemanticsListener * listener)1025     SetCsrImmProcessor(uint8_t imm, SemanticsListener* listener) : imm_(imm), listener_(listener) {}
1026     template <CsrName kName>
operator()1027     void operator()() {
1028       // Csr registers with two top bits set are read-only.
1029       // Attempts to write into such register raise illegal instruction exceptions.
1030       if constexpr (CsrWritable(kName)) {
1031         listener_->template SetCsr<kName>(imm_);
1032       }
1033     }
1034 
1035    private:
1036     uint8_t imm_;
1037     SemanticsListener* listener_;
1038   };
1039 
SetCsr(CsrName csr,uint8_t imm)1040   bool SetCsr(CsrName csr, uint8_t imm) {
1041     // Csr registers with two top bits set are read-only.
1042     // Attempts to write into such register raise illegal instruction exceptions.
1043     if (!CsrWritable(csr)) {
1044       return false;
1045     }
1046     SetCsrImmProcessor set_csr(imm, listener_);
1047     return ProcessCsrNameAsTemplateParameter(csr, set_csr);
1048   }
1049 
1050   // TODO(b/260725458): stop using SetCsrProcessor helper class and define lambda in SetCsr instead.
1051   // We need C++20 (https://wg21.link/P0428R2) for that.
1052   class SetCsrProcessor {
1053    public:
SetCsrProcessor(Register reg,SemanticsListener * listener)1054     SetCsrProcessor(Register reg, SemanticsListener* listener) : reg_(reg), listener_(listener) {}
1055     template <CsrName kName>
operator()1056     void operator()() {
1057       // Csr registers with two top bits set are read-only.
1058       // Attempts to write into such register raise illegal instruction exceptions.
1059       if constexpr (CsrWritable(kName)) {
1060         listener_->template SetCsr<kName>(reg_);
1061       }
1062     }
1063 
1064    private:
1065     Register reg_;
1066     SemanticsListener* listener_;
1067   };
1068 
SetCsr(CsrName csr,Register reg)1069   bool SetCsr(CsrName csr, Register reg) {
1070     // Csr registers with two top bits set are read-only.
1071     // Attempts to write into such register raise illegal instruction exceptions.
1072     if (!CsrWritable(csr)) {
1073       return false;
1074     }
1075     SetCsrProcessor set_csr(reg, listener_);
1076     return ProcessCsrNameAsTemplateParameter(csr, set_csr);
1077   }
1078 
1079   // Floating point instructions in RISC-V are encoded in a way where you may find out size of
1080   // operand (single-precision, double-precision, half-precision or quad-precesion; the latter
1081   // two optional) from the instruction encoding without determining the full form of instruction.
1082   //
1083   // Sources and targets are also specified via dedicated bits in opcodes.
1084   //
1085   // This allows us to split instruction handling in four steps:
1086   //   1. Load operands from register and convert it into a form suitable for host.
1087   //   2. Execute operations specified by opcode.
1088   //   3. Normalize NaNs if host and guest architctures handled them differently.
1089   //   4. Encode results as required by RISC-V (if host doesn't do that).
1090   //
1091   // Note that in case of execution of RISC-V on RISC-V all steps except #2 are not doing anything.
1092 
1093   // Step #1:
1094   //  • GetFpReg — for instructions like fsw or fmv.x.w use GetFpReg which doesn't change value.
1095   //  • GetFRegAndBoxNan — for most instructions (improperly boxed narrow float is turned into NaN).
GetFpReg(uint8_t reg)1096   FpRegister GetFpReg(uint8_t reg) { return listener_->GetFpReg(reg); }
1097   template <typename FloatType>
GetFRegAndUnboxNan(uint8_t reg)1098   FpRegister GetFRegAndUnboxNan(uint8_t reg) {
1099     return listener_->template GetFRegAndUnboxNan<FloatType>(reg);
1100   }
1101 
1102   // Step #3.
1103   template <typename FloatType>
CanonicalizeNan(FpRegister value)1104   FpRegister CanonicalizeNan(FpRegister value) {
1105     return listener_->template CanonicalizeNan<FloatType>(value);
1106   }
1107 
1108   // Step #4. Note the assymetry: step #1 may skip the NaN unboxing (would use GetFpReg if so),
1109   // but step #4 boxes uncoditionally (if actual instruction doesn't do that on host).
1110   template <typename FloatType>
NanBoxAndSetFpReg(uint8_t reg,FpRegister value)1111   void NanBoxAndSetFpReg(uint8_t reg, FpRegister value) {
1112     listener_->template NanBoxAndSetFpReg<FloatType>(reg, value);
1113   }
1114 
GetVlAndVtypeCsr()1115   std::tuple<Register, Register> GetVlAndVtypeCsr() {
1116     Register vl_orig = listener_->template GetCsr<CsrName::kVl>();
1117     Register vtype_orig = listener_->template GetCsr<CsrName::kVtype>();
1118     return {vl_orig, vtype_orig};
1119   }
1120 
SetVlAndVtypeCsr(Register vl,Register vtype)1121   void SetVlAndVtypeCsr(Register vl, Register vtype) {
1122     listener_->template SetCsr<CsrName::kVtype>(vtype);
1123     listener_->template SetCsr<CsrName::kVl>(vl);
1124   }
1125 
1126   SemanticsListener* listener_;
1127 };
1128 
1129 }  // namespace berberis
1130 
1131 #endif  // BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_
1132