/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* static */ template constexpr bool BytecodeInst::HasId(Format format, size_t idx) { switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:id?) % next if n == 0 case Format::<%= fmt.pretty.upcase %>: return idx < <%= n %>; % end default: { return false; } } UNREACHABLE_CONSTEXPR(); } /* static */ template constexpr bool BytecodeInst::HasVReg(Format format, size_t idx) { switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:reg?) % next if n == 0 case Format::<%= fmt.pretty.upcase %>: return idx < <%= n %>; // NOLINT(readability-magic-numbers) % end default: { return false; } } UNREACHABLE_CONSTEXPR(); } /* static */ template constexpr bool BytecodeInst::HasImm(Format format, size_t idx) { switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:imm?) % next if n == 0 case Format::<%= fmt.pretty.upcase %>: return idx < <%= n %>; % end default: { return false; } } UNREACHABLE_CONSTEXPR(); } /* static */ template constexpr size_t BytecodeInst::Size(Format format) { // NOLINTNEXTLINE(readability-function-size) switch (format) { % Panda::formats.each do |fmt| case Format::<%= fmt.pretty.upcase %>: { constexpr size_t SIZE = <%= fmt.size %>; return SIZE; } % end } UNREACHABLE_CONSTEXPR(); } template template ::Format format, size_t idx /* = 0 */> inline BytecodeId BytecodeInst::GetId() const { static_assert(HasId(format, idx), "Instruction doesn't have id operand with such index"); % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:id?) % next if n == 0 % % id_ops = i.operands.select(&:id?) % offsets = id_ops.map(&:offset) % widths = id_ops.map(&:width) % // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if (format == Format::<%= fmt.pretty.upcase %>) { % if offsets.length == 1 && widths.length == 1 return BytecodeId(static_cast(Read<<%= offsets[0] %>, <%= widths[0] %>>())); % else constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; return BytecodeId(static_cast(Read())); % end } % end UNREACHABLE(); } template inline void BytecodeInst::UpdateId(BytecodeId new_id, uint32_t idx /* = 0 */) { Format format = GetFormat(); ASSERT_PRINT(HasId(format, idx), "Instruction doesn't have imm operand with such index"); if (!HasId(format, idx)) { return; } % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:id?) % next if n == 0 % % id_ops = i.operands.select(&:id?) % offsets = id_ops.map(&:offset) % widths = id_ops.map(&:width) % // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if (format == Format::<%= fmt.pretty.upcase %>) { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; this->Write(new_id.AsRawValue(), OFFSETS[idx] / 8, WIDTHS[idx] / 8); return; } % end UNREACHABLE(); } template inline BytecodeId BytecodeInst::GetId(size_t idx /* = 0 */) const { Format format = GetFormat(); ASSERT_PRINT(HasId(format, idx), "Instruction doesn't have id operand with such index"); if (!HasId(format, idx)) { return {}; } switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:id?) % next if n == 0 % % id_ops = i.operands.select(&:id?) % offsets = id_ops.map(&:offset) % widths = id_ops.map(&:width) % case Format::<%= fmt.pretty.upcase %>: { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; return BytecodeId(static_cast(Read64(OFFSETS[idx], WIDTHS[idx]))); } % end default: { break; } } UNREACHABLE(); } template template ::Format format, size_t idx /* = 0 */> __attribute__ ((visibility("hidden"))) ALWAYS_INLINE inline uint16_t BytecodeInst::GetVReg() const { // NOLINTNEXTLINE(readability-function-size) static_assert(HasVReg(format, idx), "Instruction doesn't have vreg operand with such index"); % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:reg?) % next if n == 0 % % reg_ops = i.operands.select(&:reg?) % offsets = reg_ops.map(&:offset) % widths = reg_ops.map(&:width) % // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (format == Format::<%= fmt.pretty.upcase %>) { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; return static_cast(Read()); } % end UNREACHABLE(); } template __attribute__ ((visibility("hidden"))) ALWAYS_INLINE inline uint16_t BytecodeInst::GetVReg(size_t idx /* = 0 */) const { // NOLINTNEXTLINE(readability-function-size) Format format = GetFormat(); ASSERT_PRINT(HasVReg(format, idx), "Instruction doesn't have vreg operand with such index"); if (!HasVReg(format, idx)) { return 0; } switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:reg?) % next if n == 0 % % reg_ops = i.operands.select(&:reg?) % offsets = reg_ops.map(&:offset) % widths = reg_ops.map(&:width) % case Format::<%= fmt.pretty.upcase %>: { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; if (idx > <%= n - 1 %>) { break; } return static_cast(Read64(OFFSETS[idx], WIDTHS[idx])); } % end default: { break; } } UNREACHABLE(); } template template ::Format format, size_t idx /* = 0 */> inline auto BytecodeInst::GetImm() const { // NOLINTNEXTLINE(readability-function-size) static_assert(HasImm(format, idx), "Instruction doesn't have imm operand with such index"); % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:imm?) % next if n == 0 % % imm_ops = i.operands.select(&:imm?) % offsets = imm_ops.map(&:offset) % widths = imm_ops.map(&:width) % // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (format == Format::<%= fmt.pretty.upcase %>) { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; return Read(); } % end UNREACHABLE(); } template inline auto BytecodeInst::GetImm64(size_t idx /* = 0 */) const { Format format = GetFormat(); ASSERT_PRINT(HasImm(format, idx), "Instruction doesn't have imm operand with such index"); if (!HasImm(format, idx)) { return static_cast(0); } switch (format) { % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % n = i.operands.count(&:imm?) % next if n == 0 % % imm_ops = i.operands.select(&:imm?) % offsets = imm_ops.map(&:offset) % widths = imm_ops.map(&:width) % case Format::<%= fmt.pretty.upcase %>: { constexpr std::array> OFFSETS{<%= offsets.join(", ") %>}; constexpr std::array> WIDTHS{<%= widths.join(", ") %>}; return Read64(OFFSETS[idx], WIDTHS[idx]); } % end default: { break; } } UNREACHABLE(); } template inline typename BytecodeInst::Opcode BytecodeInst::GetOpcode() const { uint8_t primary = GetPrimaryOpcode(); if (primary >= <%= Panda::prefixes.map(&:opcode_idx).min %>) { // NOLINT(readability-magic-numbers) uint8_t secondary = GetSecondaryOpcode(); return static_cast((secondary << 8U) | primary); // NOLINT(hicpp-signed-bitwise) } return static_cast(primary); } template inline uint8_t BytecodeInst::GetSecondaryOpcode() const { ASSERT(GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>); // NOLINT(readability-magic-numbers) return ReadByte(1); } /* static */ template constexpr uint8_t BytecodeInst::GetMinPrefixOpcodeIndex() { return <%= Panda::prefixes.map(&:opcode_idx).min %>; // NOLINT(readability-magic-numbers) } template inline bool BytecodeInst::IsPrefixed() const { return GetPrimaryOpcode() >= <%= Panda::prefixes.map(&:opcode_idx).min %>; // NOLINT(readability-magic-numbers) } template inline typename BytecodeInst::Format BytecodeInst::GetFormat() const { // NOLINT(readability-function-size) return GetFormat(GetOpcode()); } /* static */ template constexpr typename BytecodeInst::Format BytecodeInst::GetFormat(Opcode opcode) { // NOLINT(readability-function-size) switch(opcode) { % Panda::instructions.each do |i| case BytecodeInst::Opcode::<%= i.opcode.upcase %>: return BytecodeInst::Format::<%= i.format.pretty.upcase %>; % end default: break; } UNREACHABLE(); } // NOLINTNEXTLINE(readability-function-size) template inline bool BytecodeInst::HasFlag(Flags flag) const { switch(GetOpcode()) { % Panda::instructions.each do |i| % flag_array = i.real_properties.map {|prop| "Flags::" + prop.upcase} % flag_array += ['0'] if flag_array.empty? % flags = flag_array.join(' | ') case BytecodeInst::Opcode::<%= i.opcode.upcase %>: return ((<%= flags %>) & flag) == flag; // NOLINT(hicpp-signed-bitwise) % end default: return false; } UNREACHABLE(); } // NOLINTNEXTLINE(readability-function-size) template inline bool BytecodeInst::IsIdMatchFlag(size_t idx, Flags flag) const { switch(GetOpcode()) { % Panda::instructions.each do |i| % flag_array = i.real_properties.map {|prop| prop.upcase} % flag_array = [] if flag_array.empty? % ids = [] % flag_array.each do |f| % if f == "STRING_ID" || f == "METHOD_ID" || f == "LITERALARRAY_ID" % ids << "Flags::" + f % end % end case BytecodeInst::Opcode::<%= i.opcode.upcase %>: { % if ids.empty? return false; } % else constexpr std::array> ids_array { <%= ids.join(', ') %> }; return ids_array[idx] == flag; } % end % end default: return false; } } // NOLINTNEXTLINE(readability-function-size) template inline bool BytecodeInst::IsThrow(Exceptions exception) const { switch(GetOpcode()) { % Panda::instructions.each do |i| % exception_array = i.exceptions.map {|prop| "Exceptions::" + prop.upcase} % exception_array += ['0'] if exception_array.empty? % exceptions = exception_array.join(' | ') case BytecodeInst::Opcode::<%= i.opcode.upcase %>: return ((<%= exceptions %>) & exception) == exception; // NOLINT(hicpp-signed-bitwise) % end default: return false; } UNREACHABLE(); } // NOLINTNEXTLINE(readability-function-size) template inline bool BytecodeInst::CanThrow() const { switch(GetOpcode()) { % Panda::instructions.each do |i| case BytecodeInst::Opcode::<%= i.opcode.upcase %>: return <%= i.exceptions != ["x_none"] %>; % end default: return false; } UNREACHABLE(); } // NOLINTNEXTLINE(readability-function-size) template std::ostream& operator<<(std::ostream& os, const BytecodeInst& inst) { switch(inst.GetOpcode()) { % Panda::instructions.each do |inst| case BytecodeInst::Opcode::<%= inst.opcode.upcase %>: os << "<%= inst.mnemonic %>"; % sep = " " % inst.each_operand do |op, idx| % op_str = "\"#{sep}v\" << inst.template GetVReg::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.reg? % op_str = "\"#{sep}\" << inst.template GetImm::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.imm? % op_str = "\"#{sep}id\" << inst.template GetId::Format::#{inst.format.pretty.upcase}, #{idx}>()" if op.id? os << <%= op_str %>; % sep = ', ' % end break; % end } return os; } template // NOLINTNEXTLINE(readability-function-size) std::ostream& operator<<(std::ostream& os, const typename BytecodeInst::Opcode& op) { switch(op) { % Panda::instructions.each do |inst| case BytecodeInst::Opcode::<%= inst.opcode.upcase %>: os << "<%= inst.opcode.upcase %>"; break; % end default: os << "(unknown opcode:) " << static_cast(op); break; } return os; } template inline bool BytecodeInst::IsPrimaryOpcodeValid() const { auto opcode = GetPrimaryOpcode(); // NOLINTNEXTLINE(readability-magic-numbers) if (((opcode >= <%= Panda::dispatch_table.invalid_non_prefixed_interval.min %>) && // NOLINTNEXTLINE(readability-magic-numbers) (opcode <= <%= Panda::dispatch_table.invalid_non_prefixed_interval.max %>)) || // NOLINTNEXTLINE(readability-magic-numbers) ((opcode >= <%= Panda::dispatch_table.invalid_prefixes_interval.min %>) && // NOLINTNEXTLINE(readability-magic-numbers) (opcode <= <%= Panda::dispatch_table.invalid_prefixes_interval.max %>))) { // NOLINTNEXTLINE(readability-simplify-boolean-expr) return false; } return true; }