1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16/* static */ 17template<const BytecodeInstMode Mode> 18constexpr bool BytecodeInst<Mode>::HasId(Format format, size_t idx) { 19 switch (format) { 20% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 21% fmt = i.format 22% n = i.operands.count(&:id?) 23% next if n == 0 24 case Format::<%= fmt.pretty.upcase %>: 25 return idx < <%= n %>; 26% end 27 default: { 28 return false; 29 } 30 } 31 32 UNREACHABLE_CONSTEXPR(); 33} 34 35/* static */ 36template<const BytecodeInstMode Mode> 37constexpr bool BytecodeInst<Mode>::HasVReg(Format format, size_t idx) { 38 switch (format) { 39% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 40% fmt = i.format 41% n = i.operands.count(&:reg?) 42% next if n == 0 43 case Format::<%= fmt.pretty.upcase %>: 44 return idx < <%= n %>; // NOLINT(readability-magic-numbers) 45% end 46 default: { 47 return false; 48 } 49 } 50 51 UNREACHABLE_CONSTEXPR(); 52} 53 54/* static */ 55template<const BytecodeInstMode Mode> 56constexpr bool BytecodeInst<Mode>::HasImm(Format format, size_t idx) { 57 switch (format) { 58% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 59% fmt = i.format 60% n = i.operands.count(&:imm?) 61% next if n == 0 62 case Format::<%= fmt.pretty.upcase %>: 63 return idx < <%= n %>; 64% end 65 default: { 66 return false; 67 } 68 } 69 70 UNREACHABLE_CONSTEXPR(); 71} 72 73/* static */ 74template<const BytecodeInstMode Mode> 75constexpr size_t BytecodeInst<Mode>::Size(Format format) { // NOLINTNEXTLINE(readability-function-size) 76 switch (format) { 77% Panda::formats.each do |fmt| 78 case Format::<%= fmt.pretty.upcase %>: { 79 constexpr size_t SIZE = <%= fmt.size %>; 80 return SIZE; 81 } 82% end 83 } 84 85 UNREACHABLE_CONSTEXPR(); 86} 87 88template <const BytecodeInstMode Mode> 89template <typename BytecodeInst<Mode>::Format format, size_t idx /* = 0 */> 90inline BytecodeId BytecodeInst<Mode>::GetId() const { 91 static_assert(HasId(format, idx), "Instruction doesn't have id operand with such index"); 92 93% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 94% fmt = i.format 95% n = i.operands.count(&:id?) 96% next if n == 0 97% 98% id_ops = i.operands.select(&:id?) 99% offsets = id_ops.map(&:offset) 100% widths = id_ops.map(&:width) 101% 102 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 103 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 104 if (format == Format::<%= fmt.pretty.upcase %>) { 105% if offsets.length == 1 && widths.length == 1 106 return BytecodeId(static_cast<uint32_t>(Read<<%= offsets[0] %>, <%= widths[0] %>>())); 107% else 108 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 109 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 110 return BytecodeId(static_cast<uint32_t>(Read<OFFSETS[idx], WIDTHS[idx]>())); 111% end 112 } 113 114% end 115 UNREACHABLE(); 116} 117 118template <const BytecodeInstMode Mode> 119inline void BytecodeInst<Mode>::UpdateId(BytecodeId new_id, uint32_t idx /* = 0 */) { 120 Format format = GetFormat(); 121 ASSERT_PRINT(HasId(format, idx), "Instruction doesn't have imm operand with such index"); 122 123 if (!HasId(format, idx)) { 124 return; 125 } 126 127% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 128% fmt = i.format 129% n = i.operands.count(&:id?) 130% next if n == 0 131% 132% id_ops = i.operands.select(&:id?) 133% offsets = id_ops.map(&:offset) 134% widths = id_ops.map(&:width) 135% 136 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 137 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 138 if (format == Format::<%= fmt.pretty.upcase %>) { 139 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 140 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 141 this->Write(new_id.AsRawValue(), OFFSETS[idx] / 8, WIDTHS[idx] / 8); 142 return; 143 } 144 145% end 146 UNREACHABLE(); 147} 148 149template<const BytecodeInstMode Mode> 150inline BytecodeId BytecodeInst<Mode>::GetId(size_t idx /* = 0 */) const { 151 Format format = GetFormat(); 152 ASSERT_PRINT(HasId(format, idx), "Instruction doesn't have id operand with such index"); 153 154 if (!HasId(format, idx)) { 155 return {}; 156 } 157 158 switch (format) { 159% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 160% fmt = i.format 161% n = i.operands.count(&:id?) 162% next if n == 0 163% 164% id_ops = i.operands.select(&:id?) 165% offsets = id_ops.map(&:offset) 166% widths = id_ops.map(&:width) 167% 168 case Format::<%= fmt.pretty.upcase %>: { 169 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 170 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 171 return BytecodeId(static_cast<uint32_t>(Read64(OFFSETS[idx], WIDTHS[idx]))); 172 } 173% end 174 default: { 175 break; 176 } 177 } 178 179 UNREACHABLE(); 180} 181 182template <const BytecodeInstMode Mode> 183template <typename BytecodeInst<Mode>::Format format, size_t idx /* = 0 */> 184__attribute__ ((visibility("hidden"))) 185ALWAYS_INLINE inline uint16_t BytecodeInst<Mode>::GetVReg() const { // NOLINTNEXTLINE(readability-function-size) 186 static_assert(HasVReg(format, idx), "Instruction doesn't have vreg operand with such index"); 187 188% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 189% fmt = i.format 190% n = i.operands.count(&:reg?) 191% next if n == 0 192% 193% reg_ops = i.operands.select(&:reg?) 194% offsets = reg_ops.map(&:offset) 195% widths = reg_ops.map(&:width) 196% 197 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 198 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 199 if constexpr (format == Format::<%= fmt.pretty.upcase %>) { 200 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 201 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 202 return static_cast<uint16_t>(Read<OFFSETS[idx], WIDTHS[idx]>()); 203 } 204 205% end 206 UNREACHABLE(); 207} 208 209template<const BytecodeInstMode Mode> 210__attribute__ ((visibility("hidden"))) 211ALWAYS_INLINE inline uint16_t BytecodeInst<Mode>::GetVReg(size_t idx /* = 0 */) const { // NOLINTNEXTLINE(readability-function-size) 212 Format format = GetFormat(); 213 ASSERT_PRINT(HasVReg(format, idx), "Instruction doesn't have vreg operand with such index"); 214 215 if (!HasVReg(format, idx)) { 216 return 0; 217 } 218 219 switch (format) { 220% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 221% fmt = i.format 222% n = i.operands.count(&:reg?) 223% next if n == 0 224% 225% reg_ops = i.operands.select(&:reg?) 226% offsets = reg_ops.map(&:offset) 227% widths = reg_ops.map(&:width) 228% 229 case Format::<%= fmt.pretty.upcase %>: { 230 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 231 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 232 if (idx > <%= n - 1 %>) { 233 break; 234 } 235 return static_cast<uint16_t>(Read64(OFFSETS[idx], WIDTHS[idx])); 236 } 237% end 238 default: { 239 break; 240 } 241 } 242 243 UNREACHABLE(); 244} 245 246template <const BytecodeInstMode Mode> 247template <typename BytecodeInst<Mode>::Format format, size_t idx /* = 0 */, bool is_signed /* = true */> 248inline auto BytecodeInst<Mode>::GetImm() const { // NOLINTNEXTLINE(readability-function-size) 249 static_assert(HasImm(format, idx), "Instruction doesn't have imm operand with such index"); 250 251% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 252% fmt = i.format 253% n = i.operands.count(&:imm?) 254% next if n == 0 255% 256% imm_ops = i.operands.select(&:imm?) 257% offsets = imm_ops.map(&:offset) 258% widths = imm_ops.map(&:width) 259% 260 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 261 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 262 if constexpr (format == Format::<%= fmt.pretty.upcase %>) { 263 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 264 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 265 return Read<OFFSETS[idx], WIDTHS[idx], is_signed>(); 266 } 267 268% end 269 UNREACHABLE(); 270} 271 272template <const BytecodeInstMode Mode> 273inline auto BytecodeInst<Mode>::GetImmCount() const { 274 Format format = GetFormat(); 275 auto idx = 0; 276 ASSERT_PRINT(HasImm(format, idx), "Instruction has no imm operand"); 277 278 if (!HasImm(format, idx)) { 279 return static_cast<size_t>(0); 280 } 281 282 switch (format) { 283% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 284% fmt = i.format 285% n = i.operands.count(&:imm?) 286% next if n == 0 287 288 case Format::<%= fmt.pretty.upcase %>: { 289 return static_cast<size_t>(<%= n %>); 290 } 291% end 292 default: { 293 break; 294 } 295 } 296 297 UNREACHABLE(); 298} 299 300template<const BytecodeInstMode Mode> 301inline auto BytecodeInst<Mode>::GetImm64(size_t idx /* = 0 */) const { 302 Format format = GetFormat(); 303 ASSERT_PRINT(HasImm(format, idx), "Instruction doesn't have imm operand with such index"); 304 305 if (!HasImm(format, idx)) { 306 return static_cast<int64_t>(0); 307 } 308 309 switch (format) { 310% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 311% fmt = i.format 312% n = i.operands.count(&:imm?) 313% next if n == 0 314% 315% imm_ops = i.operands.select(&:imm?) 316% offsets = imm_ops.map(&:offset) 317% widths = imm_ops.map(&:width) 318% 319 case Format::<%= fmt.pretty.upcase %>: { 320 constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>}; 321 constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>}; 322 return Read64<true>(OFFSETS[idx], WIDTHS[idx]); 323 } 324% end 325 default: { 326 break; 327 } 328 } 329 330 UNREACHABLE(); 331} 332 333template<const BytecodeInstMode Mode> 334inline auto BytecodeInst<Mode>::GetImmData(size_t idx /* = 0 */) const { 335 Format format = GetFormat(); 336 ASSERT_PRINT(HasImm(format, idx), "Instruction doesn't have imm operand with such index"); 337 338 if (!HasImm(format, idx)) { 339 return static_cast<int64_t>(0); 340 } 341 342 int64_t imm = 0; 343 344 switch (GetOpcode()) { 345% Panda::instructions.each do |inst| 346% imm_count = 0 347 case BytecodeInst<Mode>::Opcode::<%= inst.opcode.upcase %>: 348% 349% inst.operands.each do |op| 350% if op.imm? 351% if op.is_float_imm? 352 if (idx == <%=imm_count%>) { 353 // Note: If the immediate value is a floating-point number, 354 // converting it to int64_t may result in precision loss. 355 imm = static_cast<int64_t>(GetImm<BytecodeInstruction::Format::<%=inst.format.pretty.upcase%>, <%=imm_count%>, true>()); 356 } 357% elsif op.is_signed_imm? 358 if (idx == <%=imm_count%>) { 359 imm = static_cast<int64_t>(GetImm<BytecodeInstruction::Format::<%=inst.format.pretty.upcase%>, <%=imm_count%>, true>()); 360 } 361% elsif op.is_unsigned_imm? 362 if (idx == <%=imm_count%>) { 363 imm = static_cast<int64_t>(GetImm<BytecodeInstruction::Format::<%=inst.format.pretty.upcase%>, <%=imm_count%>, false>()); 364 } 365% else 366% raise "Incorrect imm type #{op.type}" 367% end 368% imm_count += 1 369% end 370% end 371 break; 372% end 373 default: 374 break; 375 } 376 377 return imm; 378} 379 380template <const BytecodeInstMode Mode> 381inline typename BytecodeInst<Mode>::Opcode BytecodeInst<Mode>::GetOpcode() const { 382 uint8_t primary = GetPrimaryOpcode(); 383 if (primary >= <%= Panda::prefixes.map(&:opcode_idx).min %>) { // NOLINT(readability-magic-numbers) 384 uint8_t secondary = GetSecondaryOpcode(); 385 return static_cast<BytecodeInst::Opcode>((secondary << 8U) | primary); // NOLINT(hicpp-signed-bitwise) 386 } 387 return static_cast<BytecodeInst::Opcode>(primary); 388} 389 390template <const BytecodeInstMode Mode> 391inline uint8_t BytecodeInst<Mode>::GetSecondaryOpcode() const { 392 ASSERT(GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>); // NOLINT(readability-magic-numbers) 393 return ReadByte(1); 394} 395 396/* static */ 397template <const BytecodeInstMode Mode> 398constexpr uint8_t BytecodeInst<Mode>::GetMinPrefixOpcodeIndex() { 399 return <%= Panda::prefixes.map(&:opcode_idx).min %>; // NOLINT(readability-magic-numbers) 400} 401 402template <const BytecodeInstMode Mode> 403inline bool BytecodeInst<Mode>::IsPrefixed() const { 404 return GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>; // NOLINT(readability-magic-numbers) 405} 406 407template <const BytecodeInstMode Mode> 408inline typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat() const { // NOLINT(readability-function-size) 409 return GetFormat(GetOpcode()); 410} 411 412/* static */ 413template <const BytecodeInstMode Mode> 414constexpr typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat(Opcode opcode) { // NOLINT(readability-function-size) 415 switch(opcode) { 416% Panda::instructions.each do |i| 417 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 418 return BytecodeInst<Mode>::Format::<%= i.format.pretty.upcase %>; 419% end 420 default: 421 break; 422 } 423 424 UNREACHABLE(); 425} 426 427// NOLINTNEXTLINE(readability-function-size) 428template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::HasFlag(Flags flag) const { 429 switch(GetOpcode()) { 430% Panda::instructions.each do |i| 431% flag_array = i.real_properties.map {|prop| "Flags::" + prop.upcase} 432% flag_array += ['0'] if flag_array.empty? 433% flags = flag_array.join(' | ') 434 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 435 return ((<%= flags %>) & flag) == flag; // NOLINT(hicpp-signed-bitwise) 436% end 437 default: 438 return false; 439 } 440 441 UNREACHABLE(); 442} 443 444// NOLINTNEXTLINE(readability-function-size) 445template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::IsIdMatchFlag(size_t idx, Flags flag) const { 446 switch(GetOpcode()) { 447% Panda::instructions.each do |i| 448% flag_array = i.real_properties.map {|prop| prop.upcase} 449% flag_array = [] if flag_array.empty? 450% ids = [] 451% flag_array.each do |f| 452% if f == "STRING_ID" || f == "METHOD_ID" || f == "LITERALARRAY_ID" 453% ids << "Flags::" + f 454% end 455% end 456 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: { 457% if ids.empty? 458 return false; 459 } 460% else 461 constexpr std::array<Flags, <%= ids.size %>> ids_array { <%= ids.join(', ') %> }; 462 return ids_array[idx] == flag; 463 } 464% end 465% end 466 default: 467 return false; 468 } 469} 470 471// NOLINTNEXTLINE(readability-function-size) 472template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::IsThrow(Exceptions exception) const { 473 switch(GetOpcode()) { 474% Panda::instructions.each do |i| 475% exception_array = i.exceptions.map {|prop| "Exceptions::" + prop.upcase} 476% exception_array += ['0'] if exception_array.empty? 477% exceptions = exception_array.join(' | ') 478 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 479 return ((<%= exceptions %>) & exception) == exception; // NOLINT(hicpp-signed-bitwise) 480% end 481 default: 482 return false; 483 } 484 485 UNREACHABLE(); 486} 487 488// NOLINTNEXTLINE(readability-function-size) 489template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::CanThrow() const { 490 switch(GetOpcode()) { 491% Panda::instructions.each do |i| 492 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 493 return <%= i.exceptions != ["x_none"] %>; 494% end 495 default: 496 return false; 497 } 498 499 UNREACHABLE(); 500} 501 502// NOLINTNEXTLINE(readability-function-size) 503template<const BytecodeInstMode Mode> std::ostream& operator<<(std::ostream& os, const BytecodeInst<Mode>& inst) { 504 switch(inst.GetOpcode()) { 505% Panda::instructions.each do |inst| 506% imm_count = 0 507% reg_count = 0 508% id_count = 0 509 case BytecodeInst<Mode>::Opcode::<%= inst.opcode.upcase %>: 510 os << "<%= inst.mnemonic %>"; 511% sep = " " 512% inst.operands.each do |op| 513% if op.imm? 514% if op.is_float_imm? 515% op_str = "\"#{sep}\" << bit_cast<double>(inst.template GetImm<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{imm_count}, true>())"; 516% elsif op.is_unsigned_imm? 517% op_str = "\"#{sep}\" << inst.template GetImm<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{imm_count}, false>()"; 518% elsif op.is_signed_imm? 519% op_str = "\"#{sep}\" << inst.template GetImm<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{imm_count}, true>()"; 520% else 521% raise "Incorrect imm type #{op.type}" 522% end 523% imm_count += 1 524% elsif op.reg? 525% op_str = "\"#{sep}v\" << inst.template GetVReg<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{reg_count}>()"; 526% reg_count += 1 527% elsif op.id? 528% op_str = "\"#{sep}id\" << inst.template GetId<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{id_count}>()"; 529% id_count += 1 530% end 531 os << <%= op_str %>; 532% sep = ', ' 533% end 534 break; 535% end 536 } 537 return os; 538} 539 540template<const BytecodeInstMode Mode> // NOLINTNEXTLINE(readability-function-size) 541std::ostream& operator<<(std::ostream& os, const typename BytecodeInst<Mode>::Opcode& op) 542{ 543 switch(op) { 544% Panda::instructions.each do |inst| 545 case BytecodeInst<Mode>::Opcode::<%= inst.opcode.upcase %>: 546 os << "<%= inst.opcode.upcase %>"; 547 break; 548% end 549 default: 550 os << "(unknown opcode:) " << static_cast<uint16_t>(op); 551 break; 552 553 } 554 return os; 555} 556 557template <const BytecodeInstMode Mode> 558inline bool BytecodeInst<Mode>::IsPrimaryOpcodeValid() const 559{ 560 auto opcode = GetPrimaryOpcode(); 561 // NOLINTNEXTLINE(readability-magic-numbers) 562 if (((opcode >= <%= Panda::dispatch_table.invalid_non_prefixed_interval.min %>) && 563 // NOLINTNEXTLINE(readability-magic-numbers) 564 (opcode <= <%= Panda::dispatch_table.invalid_non_prefixed_interval.max %>)) || 565 // NOLINTNEXTLINE(readability-magic-numbers) 566 ((opcode >= <%= Panda::dispatch_table.invalid_prefixes_interval.min %>) && 567 // NOLINTNEXTLINE(readability-magic-numbers) 568 (opcode <= <%= Panda::dispatch_table.invalid_prefixes_interval.max %>))) { 569 // NOLINTNEXTLINE(readability-simplify-boolean-expr) 570 return false; 571 } 572 return true; 573} 574 575// NOLINTNEXTLINE(readability-function-size) 576template<const BytecodeInstMode Mode> inline size_t BytecodeInst<Mode>::GetLiteralIndex() const { 577 switch(GetOpcode()) { 578% Panda::instructions.each do |i| 579% flag_array = i.real_properties.map {|prop| prop.upcase} 580% flag_array = [] if flag_array.empty? 581% count = -1 582% flag_array.each do |f| 583% if f == "STRING_ID" || f == "METHOD_ID" || f == "LITERALARRAY_ID" 584% count += 1 585% end 586% if f == "LITERALARRAY_ID" 587% break 588% end 589% end 590 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 591 return <%= count %>; 592 break; 593% end 594 default: 595 return -1; 596 break; 597 } 598} 599 600template<const BytecodeInstMode Mode> 601inline bool BytecodeInst<Mode>::IsJumpInstruction() const { 602 switch(GetOpcode()) { 603% Panda::instructions.each do |i| 604% if i.jump? 605 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 606 return true; 607% end 608% end 609 default: 610 return false; 611 } 612 613 UNREACHABLE(); 614} 615 616template<const BytecodeInstMode Mode> 617inline bool BytecodeInst<Mode>::IsRangeInstruction() const { 618 switch (GetOpcode()) { 619% Panda::instructions.each do |i| 620% if i.is_range_instruction? 621 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 622 return true; 623% end 624% end 625 default: 626 return false; 627 } 628 UNREACHABLE(); 629} 630 631template <const BytecodeInstMode Mode> 632inline std::optional<uint64_t> BytecodeInst<Mode>::GetLastVReg() const { 633 Format format = GetFormat(); 634 ASSERT_PRINT(HasVReg(format, 0), "Instruction doesn't have VReg operand with such index"); 635 636 if (!HasVReg(format, 0)) { 637 return std::nullopt; 638 } 639 640 switch (format) { 641% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 642% fmt = i.format 643% n = i.operands.count(&:reg?) 644% next if n == 0 645% 646 case Format::<%= fmt.pretty.upcase %>: { 647 return GetVReg<BytecodeInstruction::Format::<%=fmt.pretty.upcase%>, <%=n-1%>>(); 648 } 649% end 650 default: { 651 break; 652 } 653 } 654 655 UNREACHABLE(); 656} 657 658template <const BytecodeInstMode Mode> 659inline std::optional<uint64_t> BytecodeInst<Mode>::GetRangeInsLastRegIdx() const { 660 // For the range instruction, where A stores the number of registers 661 // The actual register index needs to handle 2 cases: B~B+A-1 / B~B+A 662 // range_0 is B~B+A-1 663 // range_1 is B~B+A 664 size_t count = GetImmCount(); 665 if (count == 0) { 666 return std::nullopt; 667 } 668 int64_t range_reg_num = GetImmData(count - 1); 669 switch (GetOpcode()) { 670% Panda::instructions.each do |i| 671% if i.is_range_0? 672 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 673 if (range_reg_num > 0) { 674 return SafeAdd(GetLastVReg().value(), range_reg_num - 1); 675 } 676 return GetLastVReg(); 677% end 678% if i.is_range_1? 679 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 680 return SafeAdd(GetLastVReg().value(), range_reg_num); 681% end 682% end 683 default: 684 return std::nullopt; 685 } 686 UNREACHABLE(); 687} 688 689template<const BytecodeInstMode Mode> 690inline bool BytecodeInst<Mode>::IsReturnOrThrowInstruction() const { 691 switch (GetOpcode()) { 692% Panda::instructions.each do |i| 693% if i.is_return_instruction? || i.is_unconditional_throw_instruction? 694 case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: 695 return true; 696% end 697% end 698 default: 699 return false; 700 } 701 UNREACHABLE(); 702}