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