• 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 */>
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], true>();
266    }
267
268% end
269    UNREACHABLE();
270}
271
272template<const BytecodeInstMode Mode>
273inline auto BytecodeInst<Mode>::GetImm64(size_t idx /* = 0 */) const {
274    Format format = GetFormat();
275    ASSERT_PRINT(HasImm(format, idx), "Instruction doesn't have imm operand with such index");
276
277    if (!HasImm(format, idx)) {
278        return static_cast<int64_t>(0);
279    }
280
281    switch (format) {
282% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt|
283%   fmt = i.format
284%   n = i.operands.count(&:imm?)
285%   next if n == 0
286%
287%   imm_ops = i.operands.select(&:imm?)
288%   offsets = imm_ops.map(&:offset)
289%   widths = imm_ops.map(&:width)
290%
291    case Format::<%= fmt.pretty.upcase %>: {
292        constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
293        constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
294        return Read64<true>(OFFSETS[idx], WIDTHS[idx]);
295    }
296% end
297    default: {
298        break;
299    }
300    }
301
302    UNREACHABLE();
303}
304
305template <const BytecodeInstMode Mode>
306inline typename BytecodeInst<Mode>::Opcode BytecodeInst<Mode>::GetOpcode() const {
307    uint8_t primary = GetPrimaryOpcode();
308    if (primary >= <%= Panda::prefixes.map(&:opcode_idx).min %>) {  // NOLINT(readability-magic-numbers)
309        uint8_t secondary = GetSecondaryOpcode();
310        return static_cast<BytecodeInst::Opcode>((secondary << 8U) | primary);  // NOLINT(hicpp-signed-bitwise)
311    }
312    return static_cast<BytecodeInst::Opcode>(primary);
313}
314
315template <const BytecodeInstMode Mode>
316inline uint8_t BytecodeInst<Mode>::GetSecondaryOpcode() const {
317    ASSERT(GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>);  // NOLINT(readability-magic-numbers)
318    return ReadByte(1);
319}
320
321/* static */
322template <const BytecodeInstMode Mode>
323constexpr uint8_t BytecodeInst<Mode>::GetMinPrefixOpcodeIndex() {
324    return <%= Panda::prefixes.map(&:opcode_idx).min %>;  // NOLINT(readability-magic-numbers)
325}
326
327template <const BytecodeInstMode Mode>
328inline bool BytecodeInst<Mode>::IsPrefixed() const {
329    return GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>;  // NOLINT(readability-magic-numbers)
330}
331
332template <const BytecodeInstMode Mode>
333inline typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat() const {  // NOLINT(readability-function-size)
334    return GetFormat(GetOpcode());
335}
336
337/* static */
338template <const BytecodeInstMode Mode>
339constexpr typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat(Opcode opcode) {  // NOLINT(readability-function-size)
340    switch(opcode) {
341% Panda::instructions.each do |i|
342    case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
343        return BytecodeInst<Mode>::Format::<%= i.format.pretty.upcase %>;
344% end
345    default:
346        break;
347    }
348
349    UNREACHABLE();
350}
351
352// NOLINTNEXTLINE(readability-function-size)
353template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::HasFlag(Flags flag) const {
354    switch(GetOpcode()) {
355% Panda::instructions.each do |i|
356%   flag_array = i.real_properties.map {|prop| "Flags::" + prop.upcase}
357%   flag_array += ['0'] if flag_array.empty?
358%   flags = flag_array.join(' | ')
359    case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
360        return ((<%= flags %>) & flag) == flag;  // NOLINT(hicpp-signed-bitwise)
361% end
362    default:
363        return false;
364    }
365
366    UNREACHABLE();
367}
368
369// NOLINTNEXTLINE(readability-function-size)
370template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::IsIdMatchFlag(size_t idx, Flags flag) const {
371    switch(GetOpcode()) {
372% Panda::instructions.each do |i|
373%   flag_array = i.real_properties.map {|prop| prop.upcase}
374%   flag_array = [] if flag_array.empty?
375%   ids = []
376%   flag_array.each do |f|
377%     if f == "STRING_ID" || f == "METHOD_ID" || f == "LITERALARRAY_ID"
378%       ids << "Flags::" + f
379%     end
380%   end
381    case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: {
382%   if ids.empty?
383        return false;
384    }
385%   else
386        constexpr std::array<Flags, <%= ids.size %>> ids_array { <%= ids.join(', ') %> };
387        return ids_array[idx] == flag;
388    }
389%   end
390% end
391    default:
392        return false;
393    }
394}
395
396// NOLINTNEXTLINE(readability-function-size)
397template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::IsThrow(Exceptions exception) const {
398    switch(GetOpcode()) {
399% Panda::instructions.each do |i|
400%   exception_array = i.exceptions.map {|prop| "Exceptions::" + prop.upcase}
401%   exception_array += ['0'] if exception_array.empty?
402%   exceptions = exception_array.join(' | ')
403    case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
404        return ((<%= exceptions %>) & exception) == exception;  // NOLINT(hicpp-signed-bitwise)
405% end
406    default:
407        return false;
408    }
409
410    UNREACHABLE();
411}
412
413// NOLINTNEXTLINE(readability-function-size)
414template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::CanThrow() const {
415    switch(GetOpcode()) {
416% Panda::instructions.each do |i|
417    case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
418        return <%= i.exceptions != ["x_none"] %>;
419% end
420    default:
421        return false;
422    }
423
424    UNREACHABLE();
425}
426
427// NOLINTNEXTLINE(readability-function-size)
428template<const BytecodeInstMode Mode> std::ostream& operator<<(std::ostream& os, const BytecodeInst<Mode>& inst) {
429    switch(inst.GetOpcode()) {
430% Panda::instructions.each do |inst|
431    case BytecodeInst<Mode>::Opcode::<%= inst.opcode.upcase %>:
432        os << "<%= inst.mnemonic %>";
433%   sep = " "
434%   inst.each_operand do |op, idx|
435%     op_str = "\"#{sep}v\" << inst.template GetVReg<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.reg?
436%     op_str = "\"#{sep}\" << inst.template GetImm<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.imm?
437%     op_str = "\"#{sep}id\" << inst.template GetId<BytecodeInst<Mode>::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.id?
438        os << <%= op_str %>;
439%     sep = ', '
440%   end
441        break;
442% end
443    }
444    return os;
445}
446
447template<const BytecodeInstMode Mode> // NOLINTNEXTLINE(readability-function-size)
448std::ostream& operator<<(std::ostream& os, const typename BytecodeInst<Mode>::Opcode& op)
449{
450    switch(op) {
451% Panda::instructions.each do |inst|
452    case BytecodeInst<Mode>::Opcode::<%= inst.opcode.upcase %>:
453        os << "<%= inst.opcode.upcase %>";
454        break;
455% end
456    default:
457        os << "(unknown opcode:) " << static_cast<uint16_t>(op);
458        break;
459
460    }
461    return os;
462}
463
464template <const BytecodeInstMode Mode>
465inline bool BytecodeInst<Mode>::IsPrimaryOpcodeValid() const
466{
467    auto opcode = GetPrimaryOpcode();
468    // NOLINTNEXTLINE(readability-magic-numbers)
469    if (((opcode >= <%= Panda::dispatch_table.invalid_non_prefixed_interval.min %>) &&
470        // NOLINTNEXTLINE(readability-magic-numbers)
471        (opcode <= <%= Panda::dispatch_table.invalid_non_prefixed_interval.max %>)) ||
472        // NOLINTNEXTLINE(readability-magic-numbers)
473        ((opcode >= <%= Panda::dispatch_table.invalid_prefixes_interval.min %>) &&
474        // NOLINTNEXTLINE(readability-magic-numbers)
475        (opcode <= <%= Panda::dispatch_table.invalid_prefixes_interval.max %>))) {
476        // NOLINTNEXTLINE(readability-simplify-boolean-expr)
477        return false;
478    }
479    return true;
480}
481