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