• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 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% additional_deprecated_opcodes = ["JNSTRICTEQUNDEFINED",
17%                                 "JSTRICTEQUNDEFINED",
18%                                 "JNEUNDEFINED",
19%                                 "JEQUNDEFINED",
20%                                 "JNSTRICTEQNULL",
21%                                 "JSTRICTEQNULL",
22%                                 "JNENULL",
23%                                 "JEQNULL",
24%                                 "JNSTRICTEQZ",
25%                                 "JSTRICTEQZ",
26%                                 "STTOGLOBALRECORD",
27%                                 "STCONSTTOGLOBALRECORD",
28%                                 "CREATEREGEXPWITHLITERAL",
29%                                 "CLOSEITERATOR"]
30
31% replaced_opcodes = ["JNSTRICTEQ",
32%                    "JSTRICTEQ",
33%                    "JNE",
34%                    "JEQ"]
35
36% skipped_opcodes = additional_deprecated_opcodes + replaced_opcodes
37
38/* static */
39constexpr bool BytecodeInst::HasId(Format format, size_t idx) {
40    switch (format) {
41% formats = Set.new
42% Panda::instructions.each do |i|
43%   n = i.operands.count(&:id?)
44%   next if n == 0
45%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
46%   fmt = i.format
47%   next if formats.include? fmt
48%   formats.add(fmt)
49    case Format::<%= fmt.pretty.upcase %>:
50        return idx < <%= n %>;  // NOLINT(readability-magic-numbers)
51% end
52    default:
53        return false;
54    }
55
56    UNREACHABLE_CONSTEXPR();
57}
58
59/* static */
60constexpr bool BytecodeInst::HasVReg(Format format, size_t idx) {
61    switch (format) {
62% formats = Set.new
63% Panda::instructions.each do |i|
64%   n = i.operands.count(&:reg?)
65%   next if n == 0
66%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
67%   fmt = i.format
68%   next if formats.include? fmt
69%   formats.add(fmt)
70    case Format::<%= fmt.pretty.upcase %>:
71        return idx < <%= n %>;  // NOLINT(readability-magic-numbers)
72% end
73    default:
74        return false;
75    }
76
77    UNREACHABLE_CONSTEXPR();
78}
79
80/* static */
81constexpr bool BytecodeInst::HasImm(Format format, size_t idx) {
82    switch (format) {
83% formats = Set.new
84% Panda::instructions.each do |i|
85%   n = i.operands.count(&:imm?)
86%   next if n == 0
87%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
88%   fmt = i.format
89%   next if formats.include? fmt
90%   formats.add(fmt)
91    case Format::<%= fmt.pretty.upcase %>:
92        return idx < <%= n %>;  // NOLINT(readability-magic-numbers)
93% end
94    default:
95        return false;
96    }
97
98    UNREACHABLE_CONSTEXPR();
99}
100
101/* static */
102constexpr size_t BytecodeInst::Size(Format format) {  // NOLINT(readability-function-size)
103    switch (format) {
104% formats = Set.new
105% Panda::instructions.each do |i|
106%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
107%   fmt = i.format
108%   next if formats.include? fmt
109%   formats.add(fmt)
110    case Format::<%= fmt.pretty.upcase %>:
111        return <%= fmt.size %>; // NOLINT(readability-magic-numbers)
112% end
113    default:
114        break;
115    }
116
117    UNREACHABLE_CONSTEXPR();
118}
119
120inline BytecodeId BytecodeInst::GetId(size_t idx /* = 0 */) const {
121    Format format = GetFormat();
122    ASSERT_PRINT(HasId(format, idx), "Instruction doesn't have id operand with such index");
123
124    if (!HasId(format, idx)) {
125        return {};
126    }
127
128    uint32_t id = 0;
129    switch (format) {
130% formats = Set.new
131% Panda::instructions.each do |i|
132%   n = i.operands.count(&:id?)
133%   next if n == 0
134%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
135%   fmt = i.format
136%   next if formats.include? fmt
137%   formats.add(fmt)
138%
139%   id_ops = i.operands.select(&:id?)
140%   offsets = id_ops.map(&:offset)
141%   widths = id_ops.map(&:width)
142    case Format::<%= fmt.pretty.upcase %>: {
143        constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
144        constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
145        id = static_cast<uint32_t>(Read64(OFFSETS[idx], WIDTHS[idx]));
146        break; }
147% end
148    default:
149        UNREACHABLE();
150    }
151    return BytecodeId(id);
152}
153
154ALWAYS_INLINE inline uint16_t BytecodeInst::GetVReg(size_t idx /* = 0 */) const {  // NOLINT(readability-function-size)
155    Format format = GetFormat();
156    ASSERT_PRINT(HasVReg(format, idx), "Instruction doesn't have vreg operand with such index");
157
158    if (!HasVReg(format, idx)) {
159        return 0;
160    }
161
162    switch (format) {
163% formats = Set.new
164% Panda::instructions.each do |i|
165%   n = i.operands.count(&:reg?)
166%   next if n == 0
167%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
168%   fmt = i.format
169%   next if formats.include? fmt
170%   formats.add(fmt)
171%
172%   reg_ops = i.operands.select(&:reg?)
173%   offsets = reg_ops.map(&:offset)
174%   widths = reg_ops.map(&:width)
175%
176    case Format::<%= fmt.pretty.upcase %>: {
177        constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
178        constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
179        if (idx > <%= n - 1 %>) {
180            break;
181        }
182        return static_cast<uint16_t>(Read64(OFFSETS[idx], WIDTHS[idx])); }
183% end
184    default:
185        break;
186    }
187    UNREACHABLE();
188}
189
190template <BytecodeInst::Format FORMAT, size_t IDX /* = 0 */, bool IS_SIGNED /* = false */>
191inline auto BytecodeInst::GetImm() const {  // NOLINT(readability-function-size)
192    static_assert(HasImm(FORMAT, IDX), "Instruction doesn't have imm operand with such index");
193
194% formats = Set.new
195% Panda::instructions.each do |i|
196%   n = i.operands.count(&:imm?)
197%   next if n == 0
198%   next if ((i.opcode.upcase.include? "DEPRECATED_") || (skipped_opcodes.include? i.mnemonic.upcase))
199%   fmt = i.format
200%   next if formats.include? fmt
201%   formats.add(fmt)
202%
203%   imm_ops = i.operands.select(&:imm?)
204%   offsets = imm_ops.map(&:offset)
205%   widths = imm_ops.map(&:width)
206%
207    // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
208    // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
209    if constexpr (FORMAT == Format::<%= fmt.pretty.upcase %>) {
210        constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
211        constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
212        return Read<OFFSETS[IDX], WIDTHS[IDX], IS_SIGNED>();
213    }
214
215% end
216    UNREACHABLE();
217}
218
219inline BytecodeInst::Opcode BytecodeInst::GetOpcode() const {
220    uint8_t primary = GetPrimaryOpcode();
221    if (primary >= <%= Panda::prefixes.map(&:opcode_idx).min %>) {  // NOLINT(readability-magic-numbers)
222        uint8_t secondary = GetSecondaryOpcode();
223        return static_cast<BytecodeInst::Opcode>((secondary << 8U) | primary);  // NOLINT(hicpp-signed-bitwise)
224    }
225    return static_cast<BytecodeInst::Opcode>(primary);
226}
227
228inline uint8_t BytecodeInst::GetSecondaryOpcode() const {
229    ASSERT(GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>);  // NOLINT(readability-magic-numbers)
230    return ReadByte(1);
231}
232
233inline BytecodeInst::Format BytecodeInst::GetFormat() const {  // NOLINT(readability-function-size)
234    return GetFormat(GetOpcode());
235}
236
237/* static */
238constexpr BytecodeInst::Format BytecodeInst::GetFormat(Opcode opcode) {  // NOLINT(readability-function-size)
239    switch(opcode) {
240% Panda::instructions.each do |i|
241%   if !(i.opcode.upcase.include? "DEPRECATED_") && !(skipped_opcodes.include? i.mnemonic.upcase)
242    case BytecodeInst::Opcode::<%= i.opcode.upcase %>:
243        return BytecodeInst::Format::<%= i.format.pretty.upcase %>;
244%   end
245% end
246    default:
247        break;
248    }
249
250    UNREACHABLE();
251}
252
253// NOLINTNEXTLINE(readability-function-size)
254inline bool BytecodeInst::HasFlag(Flags flag) const {
255    switch(GetOpcode()) {
256% Panda::instructions.each do |i|
257%   if !(i.opcode.upcase.include? "DEPRECATED_") && !(skipped_opcodes.include? i.mnemonic.upcase)
258%     flag_array = i.real_properties.map {|prop| "Flags::" + prop.upcase}
259%     flag_array += ['0'] if flag_array.empty?
260%     flags = flag_array.join(' | ')
261    case BytecodeInst::Opcode::<%= i.opcode.upcase %>:
262        return ((<%= flags %>) & flag) == flag;  // NOLINT(hicpp-signed-bitwise)
263%   end
264% end
265    default:
266        return false;
267    }
268
269    UNREACHABLE();
270}
271
272// NOLINTNEXTLINE(readability-function-size)
273inline bool BytecodeInst::IsThrow(Exceptions exception) const {
274    switch(GetOpcode()) {
275% Panda::instructions.each do |i|
276%   if !(i.opcode.upcase.include? "DEPRECATED_") && !(skipped_opcodes.include? i.mnemonic.upcase)
277%     exception_array = i.exceptions.map {|prop| "Exceptions::" + prop.upcase}
278%     exception_array += ['0'] if exception_array.empty?
279%     exceptions = exception_array.join(' | ')
280    case BytecodeInst::Opcode::<%= i.opcode.upcase %>:
281        return ((<%= exceptions %>) & exception) == exception;  // NOLINT(hicpp-signed-bitwise)
282%   end
283% end
284    default:
285        return false;
286    }
287
288    UNREACHABLE();
289}
290