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