• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "berberis/interpreter/riscv64/interpreter.h"
18 
19 #include <cfenv>
20 #include <cstdint>
21 #include <cstring>
22 
23 #include "berberis/base/bit_util.h"
24 #include "berberis/base/checks.h"
25 #include "berberis/base/logging.h"
26 #include "berberis/base/macros.h"
27 #include "berberis/decoder/riscv64/decoder.h"
28 #include "berberis/decoder/riscv64/semantics_player.h"
29 #include "berberis/guest_state/guest_addr.h"
30 #include "berberis/guest_state/guest_state_riscv64.h"
31 #include "berberis/intrinsics/riscv64_to_x86_64/intrinsics_float.h"
32 #include "berberis/kernel_api/run_guest_syscall.h"
33 
34 #include "atomics.h"
35 #include "fp_regs.h"
36 
37 namespace berberis {
38 
39 namespace {
40 
41 class Interpreter {
42  public:
43   using Decoder = Decoder<SemanticsPlayer<Interpreter>>;
44   using Register = uint64_t;
45   using FpRegister = uint64_t;
46   using Float32 = intrinsics::Float32;
47   using Float64 = intrinsics::Float64;
48 
Interpreter(ThreadState * state)49   explicit Interpreter(ThreadState* state) : state_(state), branch_taken_(false) {}
50 
51   //
52   // Instruction implementations.
53   //
54 
Csr(Decoder::CsrOpcode opcode,Register arg,Decoder::CsrRegister csr)55   Register Csr(Decoder::CsrOpcode opcode, Register arg, Decoder::CsrRegister csr) {
56     Register (*UpdateStatus)(Register arg, Register original_csr_value);
57     switch (opcode) {
58       case Decoder::CsrOpcode::kCsrrw:
59         UpdateStatus = [](Register arg, Register /*original_csr_value*/) { return arg; };
60         break;
61       case Decoder::CsrOpcode::kCsrrs:
62         UpdateStatus = [](Register arg, Register original_csr_value) {
63           return arg | original_csr_value;
64         };
65         break;
66       case Decoder::CsrOpcode::kCsrrc:
67         UpdateStatus = [](Register arg, Register original_csr_value) {
68           return ~arg & original_csr_value;
69         };
70         break;
71       default:
72         Unimplemented();
73         return {};
74     }
75     Register result;
76     switch (csr) {
77       case Decoder::CsrRegister::kFrm:
78         result = state_->cpu.frm;
79         arg = UpdateStatus(arg, result);
80         state_->cpu.frm = arg;
81         if (arg <= FPFlags::RM_MAX) {
82           std::fesetround(intrinsics::ToHostRoundingMode(arg));
83         }
84         break;
85       default:
86         Unimplemented();
87         return {};
88     }
89     return result;
90   }
91 
Csr(Decoder::CsrImmOpcode opcode,uint8_t imm,Decoder::CsrRegister csr)92   Register Csr(Decoder::CsrImmOpcode opcode, uint8_t imm, Decoder::CsrRegister csr) {
93     return Csr(Decoder::CsrOpcode(opcode), imm, csr);
94   }
95 
96   // Note: we prefer not to use C11/C++ atomic_thread_fence or even gcc/clang builtin
97   // __atomic_thread_fence because all these function rely on the fact that compiler never uses
98   // non-temporal loads and stores and only issue “mfence” when sequentially consistent ordering is
99   // requested. They never issue “lfence” or “sfence”.
100   // Instead we pull the page from Linux's kernel book and map read ordereding to “lfence”, write
101   // ordering to “sfence” and read-write ordering to “mfence”.
102   // This can be important in the future if we would start using nontemporal moves in manually
103   // created assembly code.
104   // Ordering affecting I/O devices is not relevant to user-space code thus we just ignore bits
105   // related to devices I/O.
Fence(Decoder::FenceOpcode,Register,bool sw,bool sr,bool,bool,bool pw,bool pr,bool,bool)106   void Fence(Decoder::FenceOpcode /*opcode*/,
107              Register /*src*/,
108              bool sw,
109              bool sr,
110              bool /*so*/,
111              bool /*si*/,
112              bool pw,
113              bool pr,
114              bool /*po*/,
115              bool /*pi*/) {
116     bool read_fence = sr | pr;
117     bool write_fence = sw | pw;
118     // Two types of fences (total store ordering fence and normal fence) are supposed to be
119     // processed differently, but only for the “read_fence && write_fence” case (otherwise total
120     // store ordering fence becomes normal fence for the “forward compatibility”), yet because x86
121     // doesn't distinguish between these two types of fences and since we are supposed to map all
122     // not-yet defined fences to normal fence (again, for the “forward compatibility”) it's Ok to
123     // just ignore opcode field.
124     if (read_fence) {
125       if (write_fence) {
126         asm volatile("mfence" ::: "memory");
127       } else {
128         asm volatile("lfence" ::: "memory");
129       }
130     } else if (write_fence) {
131       asm volatile("sfence" ::: "memory");
132     }
133     return;
134   }
135 
FenceI(Register,int16_t)136   void FenceI(Register /*arg*/, int16_t /*imm*/) {
137     // For interpreter-only mode we don't need to do anything here, but when we will have a
138     // translator we would need to flush caches here.
139   }
140 
Op(Decoder::OpOpcode opcode,Register arg1,Register arg2)141   Register Op(Decoder::OpOpcode opcode, Register arg1, Register arg2) {
142     using uint128_t = unsigned __int128;
143     switch (opcode) {
144       case Decoder::OpOpcode::kAdd:
145         return arg1 + arg2;
146       case Decoder::OpOpcode::kSub:
147         return arg1 - arg2;
148       case Decoder::OpOpcode::kAnd:
149         return arg1 & arg2;
150       case Decoder::OpOpcode::kOr:
151         return arg1 | arg2;
152       case Decoder::OpOpcode::kXor:
153         return arg1 ^ arg2;
154       case Decoder::OpOpcode::kSll:
155         return arg1 << arg2;
156       case Decoder::OpOpcode::kSrl:
157         return arg1 >> arg2;
158       case Decoder::OpOpcode::kSra:
159         return bit_cast<int64_t>(arg1) >> arg2;
160       case Decoder::OpOpcode::kSlt:
161         return bit_cast<int64_t>(arg1) < bit_cast<int64_t>(arg2) ? 1 : 0;
162       case Decoder::OpOpcode::kSltu:
163         return arg1 < arg2 ? 1 : 0;
164       case Decoder::OpOpcode::kMul:
165         return arg1 * arg2;
166       case Decoder::OpOpcode::kMulh:
167         return (__int128{bit_cast<int64_t>(arg1)} * __int128{bit_cast<int64_t>(arg2)}) >> 64;
168       case Decoder::OpOpcode::kMulhsu:
169         return (__int128{bit_cast<int64_t>(arg1)} * uint128_t{arg2}) >> 64;
170       case Decoder::OpOpcode::kMulhu:
171         return (uint128_t{arg1} * uint128_t{arg2}) >> 64;
172       case Decoder::OpOpcode::kDiv:
173         return bit_cast<int64_t>(arg1) / bit_cast<int64_t>(arg2);
174       case Decoder::OpOpcode::kDivu:
175         return arg1 / arg2;
176       case Decoder::OpOpcode::kRem:
177         return bit_cast<int64_t>(arg1) % bit_cast<int64_t>(arg2);
178       case Decoder::OpOpcode::kRemu:
179         return arg1 % arg2;
180       default:
181         Unimplemented();
182         return {};
183     }
184   }
185 
Op32(Decoder::Op32Opcode opcode,Register arg1,Register arg2)186   Register Op32(Decoder::Op32Opcode opcode, Register arg1, Register arg2) {
187     switch (opcode) {
188       case Decoder::Op32Opcode::kAddw:
189         return int32_t(arg1) + int32_t(arg2);
190       case Decoder::Op32Opcode::kSubw:
191         return int32_t(arg1) - int32_t(arg2);
192       case Decoder::Op32Opcode::kSllw:
193         return int32_t(arg1) << int32_t(arg2);
194       case Decoder::Op32Opcode::kSrlw:
195         return bit_cast<int32_t>(uint32_t(arg1) >> uint32_t(arg2));
196       case Decoder::Op32Opcode::kSraw:
197         return int32_t(arg1) >> int32_t(arg2);
198       case Decoder::Op32Opcode::kMulw:
199         return int32_t(arg1) * int32_t(arg2);
200       case Decoder::Op32Opcode::kDivw:
201         return int32_t(arg1) / int32_t(arg2);
202       case Decoder::Op32Opcode::kDivuw:
203         return uint32_t(arg1) / uint32_t(arg2);
204       case Decoder::Op32Opcode::kRemw:
205         return int32_t(arg1) % int32_t(arg2);
206       case Decoder::Op32Opcode::kRemuw:
207         return uint32_t(arg1) % uint32_t(arg2);
208       default:
209         Unimplemented();
210         return {};
211     }
212   }
213 
Amo(Decoder::AmoOpcode opcode,Register arg1,Register arg2,bool aq,bool rl)214   Register Amo(Decoder::AmoOpcode opcode, Register arg1, Register arg2, bool aq, bool rl) {
215     switch (opcode) {
216       case Decoder::AmoOpcode::kLrW:
217         Unimplemented();
218         return {};
219       case Decoder::AmoOpcode::kLrD:
220         Unimplemented();
221         return {};
222       case Decoder::AmoOpcode::kScW:
223         Unimplemented();
224         return {};
225       case Decoder::AmoOpcode::kScD:
226         Unimplemented();
227         return {};
228 
229       case Decoder::AmoOpcode::kAmoswapW:
230         return AtomicExchange<int32_t>(arg1, arg2, aq, rl);
231       case Decoder::AmoOpcode::kAmoswapD:
232         return AtomicExchange<int64_t>(arg1, arg2, aq, rl);
233 
234       case Decoder::AmoOpcode::kAmoaddW:
235         return AtomicAdd<int32_t>(arg1, arg2, aq, rl);
236       case Decoder::AmoOpcode::kAmoaddD:
237         return AtomicAdd<int64_t>(arg1, arg2, aq, rl);
238 
239       case Decoder::AmoOpcode::kAmoxorW:
240         return AtomicXor<int32_t>(arg1, arg2, aq, rl);
241       case Decoder::AmoOpcode::kAmoxorD:
242         return AtomicXor<int64_t>(arg1, arg2, aq, rl);
243 
244       case Decoder::AmoOpcode::kAmoandW:
245         return AtomicAnd<int32_t>(arg1, arg2, aq, rl);
246       case Decoder::AmoOpcode::kAmoandD:
247         return AtomicAnd<int64_t>(arg1, arg2, aq, rl);
248 
249       case Decoder::AmoOpcode::kAmoorW:
250         return AtomicOr<int32_t>(arg1, arg2, aq, rl);
251       case Decoder::AmoOpcode::kAmoorD:
252         return AtomicOr<int64_t>(arg1, arg2, aq, rl);
253 
254       case Decoder::AmoOpcode::kAmominW:
255         return AtomicMin<int32_t>(arg1, arg2, aq, rl);
256       case Decoder::AmoOpcode::kAmominD:
257         return AtomicMin<int64_t>(arg1, arg2, aq, rl);
258 
259       case Decoder::AmoOpcode::kAmomaxW:
260         return AtomicMax<int32_t>(arg1, arg2, aq, rl);
261       case Decoder::AmoOpcode::kAmomaxD:
262         return AtomicMax<int64_t>(arg1, arg2, aq, rl);
263 
264       case Decoder::AmoOpcode::kAmominuW:
265         return AtomicMinu<uint32_t>(arg1, arg2, aq, rl);
266       case Decoder::AmoOpcode::kAmominuD:
267         return AtomicMinu<uint64_t>(arg1, arg2, aq, rl);
268 
269       case Decoder::AmoOpcode::kAmomaxuW:
270         return AtomicMaxu<uint32_t>(arg1, arg2, aq, rl);
271       case Decoder::AmoOpcode::kAmomaxuD:
272         return AtomicMaxu<uint64_t>(arg1, arg2, aq, rl);
273 
274       default:
275         Unimplemented();
276         return {};
277     }
278   }
279 
Load(Decoder::LoadOpcode opcode,Register arg,int16_t offset)280   Register Load(Decoder::LoadOpcode opcode, Register arg, int16_t offset) {
281     void* ptr = ToHostAddr<void>(arg + offset);
282     switch (opcode) {
283       case Decoder::LoadOpcode::kLbu:
284         return Load<uint8_t>(ptr);
285       case Decoder::LoadOpcode::kLhu:
286         return Load<uint16_t>(ptr);
287       case Decoder::LoadOpcode::kLwu:
288         return Load<uint32_t>(ptr);
289       case Decoder::LoadOpcode::kLd:
290         return Load<uint64_t>(ptr);
291       case Decoder::LoadOpcode::kLb:
292         return Load<int8_t>(ptr);
293       case Decoder::LoadOpcode::kLh:
294         return Load<int16_t>(ptr);
295       case Decoder::LoadOpcode::kLw:
296         return Load<int32_t>(ptr);
297       default:
298         Unimplemented();
299         return {};
300     }
301   }
302 
LoadFp(Decoder::LoadFpOpcode opcode,Register arg,int16_t offset)303   FpRegister LoadFp(Decoder::LoadFpOpcode opcode, Register arg, int16_t offset) {
304     void* ptr = ToHostAddr<void>(arg + offset);
305     switch (opcode) {
306       case Decoder::LoadFpOpcode::kFlw:
307         return LoadFp<float>(ptr);
308       case Decoder::LoadFpOpcode::kFld:
309         return LoadFp<double>(ptr);
310       default:
311         Unimplemented();
312         return {};
313     }
314   }
315 
OpImm(Decoder::OpImmOpcode opcode,Register arg,int16_t imm)316   Register OpImm(Decoder::OpImmOpcode opcode, Register arg, int16_t imm) {
317     switch (opcode) {
318       case Decoder::OpImmOpcode::kAddi:
319         return arg + int64_t{imm};
320       case Decoder::OpImmOpcode::kSlti:
321         return bit_cast<int64_t>(arg) < int64_t{imm} ? 1 : 0;
322       case Decoder::OpImmOpcode::kSltiu:
323         return arg < bit_cast<uint64_t>(int64_t{imm}) ? 1 : 0;
324       case Decoder::OpImmOpcode::kXori:
325         return arg ^ int64_t { imm };
326       case Decoder::OpImmOpcode::kOri:
327         return arg | int64_t{imm};
328       case Decoder::OpImmOpcode::kAndi:
329         return arg & int64_t{imm};
330       default:
331         Unimplemented();
332         return {};
333     }
334   }
335 
Lui(int32_t imm)336   Register Lui(int32_t imm) { return int64_t{imm}; }
337 
Auipc(int32_t imm)338   Register Auipc(int32_t imm) {
339     uint64_t pc = state_->cpu.insn_addr;
340     return pc + int64_t{imm};
341   }
342 
OpImm32(Decoder::OpImm32Opcode opcode,Register arg,int16_t imm)343   Register OpImm32(Decoder::OpImm32Opcode opcode, Register arg, int16_t imm) {
344     switch (opcode) {
345       case Decoder::OpImm32Opcode::kAddiw:
346         return int32_t(arg) + int32_t{imm};
347       default:
348         Unimplemented();
349         return {};
350     }
351   }
352 
Ecall(Register syscall_nr,Register arg0,Register arg1,Register arg2,Register arg3,Register arg4,Register arg5)353   Register Ecall(Register syscall_nr, Register arg0, Register arg1, Register arg2, Register arg3,
354                  Register arg4, Register arg5) {
355     return RunGuestSyscall(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5);
356   }
357 
OpFp(Decoder::OpFpOpcode opcode,Decoder::FloatSize float_size,uint8_t rm,FpRegister arg1,FpRegister arg2)358   FpRegister OpFp(Decoder::OpFpOpcode opcode,
359                   Decoder::FloatSize float_size,
360                   uint8_t rm,
361                   FpRegister arg1,
362                   FpRegister arg2) {
363     switch (float_size) {
364       case Decoder::FloatSize::kFloat:
365         return NanBoxFloatToFPReg(OpFp<Float32>(
366             opcode, rm, NanUnboxFPRegToFloat<Float32>(arg1), NanUnboxFPRegToFloat<Float32>(arg2)));
367       case Decoder::FloatSize::kDouble:
368         return NanBoxFloatToFPReg(OpFp<Float64>(
369             opcode, rm, NanUnboxFPRegToFloat<Float64>(arg1), NanUnboxFPRegToFloat<Float64>(arg2)));
370       default:
371         Unimplemented();
372         return {};
373     }
374   }
375 
376   // TODO(b/278812060): switch to intrinsics when they would become available and stop using
377   // ExecuteFloatOperation directly.
378   template <typename FloatType>
OpFp(Decoder::OpFpOpcode opcode,uint8_t rm,FloatType arg1,FloatType arg2)379   FloatType OpFp(Decoder::OpFpOpcode opcode, uint8_t rm, FloatType arg1, FloatType arg2) {
380     switch (opcode) {
381       case Decoder::OpFpOpcode::kFAdd:
382         return intrinsics::ExecuteFloatOperation<FloatType>(
383             rm, state_->cpu.frm, [](auto x, auto y) { return x + y; }, arg1, arg2);
384       default:
385         Unimplemented();
386         return {};
387     }
388   }
389 
ShiftImm(Decoder::ShiftImmOpcode opcode,Register arg,uint16_t imm)390   Register ShiftImm(Decoder::ShiftImmOpcode opcode, Register arg, uint16_t imm) {
391     switch (opcode) {
392       case Decoder::ShiftImmOpcode::kSlli:
393         return arg << imm;
394       case Decoder::ShiftImmOpcode::kSrli:
395         return arg >> imm;
396       case Decoder::ShiftImmOpcode::kSrai:
397         return bit_cast<int64_t>(arg) >> imm;
398       default:
399         Unimplemented();
400         return {};
401     }
402   }
403 
ShiftImm32(Decoder::ShiftImm32Opcode opcode,Register arg,uint16_t imm)404   Register ShiftImm32(Decoder::ShiftImm32Opcode opcode, Register arg, uint16_t imm) {
405     switch (opcode) {
406       case Decoder::ShiftImm32Opcode::kSlliw:
407         return int32_t(arg) << int32_t{imm};
408       case Decoder::ShiftImm32Opcode::kSrliw:
409         return bit_cast<int32_t>(uint32_t(arg) >> uint32_t{imm});
410       case Decoder::ShiftImm32Opcode::kSraiw:
411         return int32_t(arg) >> int32_t{imm};
412       default:
413         Unimplemented();
414         return {};
415     }
416   }
417 
Store(Decoder::StoreOpcode opcode,Register arg,int16_t offset,Register data)418   void Store(Decoder::StoreOpcode opcode, Register arg, int16_t offset, Register data) {
419     void* ptr = ToHostAddr<void>(arg + offset);
420     switch (opcode) {
421       case Decoder::StoreOpcode::kSb:
422         Store<uint8_t>(ptr, data);
423         break;
424       case Decoder::StoreOpcode::kSh:
425         Store<uint16_t>(ptr, data);
426         break;
427       case Decoder::StoreOpcode::kSw:
428         Store<uint32_t>(ptr, data);
429         break;
430       case Decoder::StoreOpcode::kSd:
431         Store<uint64_t>(ptr, data);
432         break;
433       default:
434         return Unimplemented();
435     }
436   }
437 
StoreFp(Decoder::StoreFpOpcode opcode,Register arg,int16_t offset,FpRegister data)438   void StoreFp(Decoder::StoreFpOpcode opcode, Register arg, int16_t offset, FpRegister data) {
439     void* ptr = ToHostAddr<void>(arg + offset);
440     switch (opcode) {
441       case Decoder::StoreFpOpcode::kFsw:
442         StoreFp<float>(ptr, data);
443         break;
444       case Decoder::StoreFpOpcode::kFsd:
445         StoreFp<double>(ptr, data);
446         break;
447       default:
448         return Unimplemented();
449     }
450   }
451 
Branch(Decoder::BranchOpcode opcode,Register arg1,Register arg2,int16_t offset)452   void Branch(Decoder::BranchOpcode opcode, Register arg1, Register arg2, int16_t offset) {
453     bool cond_value;
454     switch (opcode) {
455       case Decoder::BranchOpcode::kBeq:
456         cond_value = arg1 == arg2;
457         break;
458       case Decoder::BranchOpcode::kBne:
459         cond_value = arg1 != arg2;
460         break;
461       case Decoder::BranchOpcode::kBltu:
462         cond_value = arg1 < arg2;
463         break;
464       case Decoder::BranchOpcode::kBgeu:
465         cond_value = arg1 >= arg2;
466         break;
467       case Decoder::BranchOpcode::kBlt:
468         cond_value = bit_cast<int64_t>(arg1) < bit_cast<int64_t>(arg2);
469         break;
470       case Decoder::BranchOpcode::kBge:
471         cond_value = bit_cast<int64_t>(arg1) >= bit_cast<int64_t>(arg2);
472         break;
473       default:
474         return Unimplemented();
475     }
476 
477     if (cond_value) {
478       state_->cpu.insn_addr += offset;
479       branch_taken_ = true;
480     }
481   }
482 
JumpAndLink(int32_t offset,uint8_t insn_len)483   Register JumpAndLink(int32_t offset, uint8_t insn_len) {
484     uint64_t pc = state_->cpu.insn_addr;
485     state_->cpu.insn_addr += offset;
486     branch_taken_ = true;
487     return pc + insn_len;
488   }
489 
JumpAndLinkRegister(Register base,int16_t offset,uint8_t insn_len)490   Register JumpAndLinkRegister(Register base, int16_t offset, uint8_t insn_len) {
491     uint64_t pc = state_->cpu.insn_addr;
492     // The lowest bit is always zeroed out.
493     state_->cpu.insn_addr = (base + offset) & ~uint64_t{1};
494     branch_taken_ = true;
495     return pc + insn_len;
496   }
497 
Nop()498   void Nop() {}
499 
Unimplemented()500   void Unimplemented() { FATAL("Unimplemented riscv64 instruction"); }
501 
502   //
503   // Guest state getters/setters.
504   //
505 
GetReg(uint8_t reg) const506   Register GetReg(uint8_t reg) const {
507     CheckRegIsValid(reg);
508     return state_->cpu.x[reg - 1];
509   }
510 
SetReg(uint8_t reg,Register value)511   void SetReg(uint8_t reg, Register value) {
512     CheckRegIsValid(reg);
513     state_->cpu.x[reg - 1] = value;
514   }
515 
GetFpReg(uint8_t reg) const516   FpRegister GetFpReg(uint8_t reg) const {
517     CheckFpRegIsValid(reg);
518     return state_->cpu.f[reg];
519   }
520 
SetFpReg(uint8_t reg,FpRegister value)521   void SetFpReg(uint8_t reg, FpRegister value) {
522     CheckFpRegIsValid(reg);
523     state_->cpu.f[reg] = value;
524   }
525 
526   //
527   // Various helper methods.
528   //
529 
GetImm(uint64_t imm) const530   uint64_t GetImm(uint64_t imm) const { return imm; }
531 
FinalizeInsn(uint8_t insn_len)532   void FinalizeInsn(uint8_t insn_len) {
533     if (!branch_taken_) {
534       state_->cpu.insn_addr += insn_len;
535     }
536   }
537 
538  private:
539   template <typename DataType>
Load(const void * ptr) const540   Register Load(const void* ptr) const {
541     static_assert(std::is_integral_v<DataType>);
542     DataType data;
543     memcpy(&data, ptr, sizeof(data));
544     // Signed types automatically sign-extend to int64_t.
545     return static_cast<uint64_t>(data);
546   }
547 
548   template <typename DataType>
LoadFp(const void * ptr) const549   FpRegister LoadFp(const void* ptr) const {
550     static_assert(std::is_floating_point_v<DataType>);
551     FpRegister reg = ~0ULL;
552     memcpy(&reg, ptr, sizeof(DataType));
553     return reg;
554   }
555 
556   template <typename DataType>
Store(void * ptr,uint64_t data) const557   void Store(void* ptr, uint64_t data) const {
558     static_assert(std::is_integral_v<DataType>);
559     memcpy(ptr, &data, sizeof(DataType));
560   }
561 
562   template <typename DataType>
StoreFp(void * ptr,uint64_t data) const563   void StoreFp(void* ptr, uint64_t data) const {
564     static_assert(std::is_floating_point_v<DataType>);
565     memcpy(ptr, &data, sizeof(DataType));
566   }
567 
CheckRegIsValid(uint8_t reg) const568   void CheckRegIsValid(uint8_t reg) const {
569     CHECK_GT(reg, 0u);
570     CHECK_LE(reg, arraysize(state_->cpu.x));
571   }
572 
CheckFpRegIsValid(uint8_t reg) const573   void CheckFpRegIsValid(uint8_t reg) const { CHECK_LT(reg, arraysize(state_->cpu.f)); }
574 
575   ThreadState* state_;
576   bool branch_taken_;
577 };
578 
579 }  // namespace
580 
InterpretInsn(ThreadState * state)581 void InterpretInsn(ThreadState* state) {
582   GuestAddr pc = state->cpu.insn_addr;
583 
584   Interpreter interpreter(state);
585   SemanticsPlayer sem_player(&interpreter);
586   Decoder decoder(&sem_player);
587   uint8_t insn_len = decoder.Decode(ToHostAddr<const uint16_t>(pc));
588   interpreter.FinalizeInsn(insn_len);
589 }
590 
591 }  // namespace berberis