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