• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}