/* * 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. */ // Autogenerated file -- DO NOT EDIT! template static size_t Emit(It out, Types... args) { // NOLINT(readability-function-size) size_t insn_len = 0; % insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| % fmt = i.format % ops = i.operands % offsets = [0] # for opcode % offsets += ops.map(&:offset).sort % offsets += [fmt.size * 8] # terminating offset, used for calculating last operand encoding 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 size_t SIZE = <%= fmt.size %>; constexpr std::array> OFF{<%= offsets.join(', ') %>}; static_assert(OFF.size() == sizeof...(args) + 1); std::array buf{}; Span buf_sp(buf); Span off_sp(OFF); EmitImpl(buf_sp, off_sp, args...); std::copy(buf.begin(), buf.end(), out); insn_len = SIZE; } % end return insn_len; } % OPCODE_TYPE = 'BytecodeInstruction::Opcode' % FORMAT_TYPE = 'BytecodeInstruction::Format' % % def opcode_full_name(i) % OPCODE_TYPE + '::' + i.opcode.upcase % end % % def format_full_name(i) % FORMAT_TYPE + '::' + i.format.pretty.upcase % end % % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % emitter_name = group.first.emitter_name % formats = group.map(&:format) % signature = emitter_signature(group, group.first.jump?) % signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ') % // NOLINTNEXTLINE(misc-definitions-in-headers) void BytecodeEmitter::<%= emitter_name %>(<%= signature_str %>) { % % method_args = signature.map(&:name) % opcodes = group.map { |i| opcode_full_name(i) } % % i = group[0] % % if i.jump? % jmp_args = [opcode_full_name(i)] + method_args[0..-2] + ["0"] % format = format_full_name(i) branches_.insert(std::make_pair(pc_, label)); pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= jmp_args.join(', ') %>); % elsif group.length() == 1 % jmp_args = [opcode_full_name(i)] + method_args % format = format_full_name(i) pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= jmp_args.join(', ') %>); % else % bitlen_vars = [] % signature.each do |arg| % v = '%s_bitlen' % arg.name % bitlen_vars.push(v) % if arg.type.start_with?('u') auto <%= v %> = GetBitLengthUnsigned(<%= arg.name %>); % else auto <%= v %> = GetBitLengthSigned(<%= arg.name %>); % end % end % % group.each do |i| % conditions = [] % i.operands.each_with_index do |op, index| % conditions.push("%s <= BitImmSize::BITSIZE_%d" % [bitlen_vars[index], op.width]) % end % format = format_full_name(i) % opcode = opcode_full_name(i) if (<%= conditions.join(' && ') %>) { pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= opcode %>, <%= method_args.join(', ') %>); return; } % end % end } % end /* static */ // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) size_t BytecodeEmitter::GetSizeByOpcode(<%= OPCODE_TYPE %> opcode) { switch (opcode) { % Panda::instructions.each do |insn| case <%= opcode_full_name(insn) %>: return <%= insn.format.size %>; // NOLINT(readability-magic-numbers) % end default: UNREACHABLE(); return 0; } } template static void UpdateBranchByFormat(uint8_t *insn, OffsT offs) { // NOLINT(readability-function-size) % uniq_fmt_jmps = Panda.instructions.select { |i| i.jump? }.uniq { |i| i.format.pretty }.sort_by { |insn| insn.format.pretty } % uniq_fmt_jmps.each do |i| % fmt = i.format % offsets = [i.operands.map(&:offset).max, fmt.size * 8] % // 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 size_t SIZE = <%= fmt.size %>; constexpr std::array> OFF{<%= offsets.join(', ') %>}; Span off_sp(OFF); Span insn_sp(insn, SIZE); EmitImpl(insn_sp, off_sp, offs); return; } % end UNREACHABLE(); } /* static */ // NOLINTNEXTLINE(misc-definitions-in-headers) void BytecodeEmitter::UpdateBranchOffs(uint8_t *insn, int32_t offs) { auto opcode = BytecodeInstruction(insn).GetOpcode(); switch (opcode) { % Panda::instructions.each do |insn| % if insn.jump? case <%= opcode_full_name(insn) %>: UpdateBranchByFormat<<%= format_full_name(insn) %>>(insn, offs); return; % end % end default: UNREACHABLE(); } } /* static */ // NOLINTNEXTLINE(misc-definitions-in-headers) BytecodeEmitter::BitImmSize BytecodeEmitter::GetBitImmSizeByOpcode(<%= OPCODE_TYPE %> opcode) { switch (opcode) { % Panda::instructions.each do |insn| % if insn.jump? case <%= opcode_full_name(insn) %>: return BytecodeEmitter::BitImmSize::BITSIZE_<%= insn.operands.select(&:imm?).first.width %>; % end % end default: UNREACHABLE(); return BytecodeEmitter::BitImmSize::BITSIZE_32; // Any return value will do, we are broken here anyway. } } /* static */ // NOLINTNEXTLINE(misc-definitions-in-headers) <%= OPCODE_TYPE %> BytecodeEmitter::RevertConditionCode(<%= OPCODE_TYPE %> opcode) { % CC_INVERTER = { % "JEQ" => "JNE", % "JNE" => "JEQ", % "JLT" => "JGE", % "JGE" => "JLT", % "JGT" => "JLE", % "JLE" => "JGT", % } switch (opcode) { % Panda::instructions.each do |insn| % if insn.conditional? % pref = insn.format.prefixed? ? insn.prefix.name.upcase + "_" : "" % op = insn.opcode.upcase.delete_prefix(pref) % op = CC_INVERTER[/^.../.match(op).to_s] ? op.sub(/^.../, CC_INVERTER).prepend(pref) : "LAST" case <%= opcode_full_name(insn) %>: return <%= OPCODE_TYPE %>::<%= op %>; % end % end default: UNREACHABLE(); return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. } } /* static */ // NOLINTNEXTLINE(misc-definitions-in-headers) <%= OPCODE_TYPE %> BytecodeEmitter::GetLongestJump(<%= OPCODE_TYPE %> opcode) { switch (opcode) { % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % insn = group[0] % if insn.jump? % group.each do |i| case <%= OPCODE_TYPE %>::<%= i.opcode.upcase %>: % end return <%= OPCODE_TYPE %>::<%= group[-1].opcode.upcase %>; % end % end default: UNREACHABLE(); return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. } } /* static */ // // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) <%= OPCODE_TYPE %> BytecodeEmitter::GetSuitableJump(<%= OPCODE_TYPE %> opcode, BytecodeEmitter::BitImmSize width) { switch (opcode) { % jmp_w_list = [32, 16, 8, 4] % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % insn = group[0] % if insn.jump? case <%= OPCODE_TYPE %>::<%= insn.opcode.upcase %>: switch (width) { % suit_ind = 0 % jmp_w_list.each do |w| % if group[suit_ind - 1] != nil && w == group[suit_ind - 1].operands.select(&:imm?).first.width % if w != jmp_w_list[0] return <%= OPCODE_TYPE %>::<%= (suit_ind == 0) ? "LAST" : group[suit_ind].opcode.upcase %>; % end % suit_ind = suit_ind - 1 % end case BytecodeEmitter::BitImmSize::BITSIZE_<%= w %>: % end return <%= OPCODE_TYPE %>::<%= (suit_ind == 0) ? "LAST" : group[suit_ind].opcode.upcase %>; } break; % end % end default: UNREACHABLE(); return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. } UNREACHABLE(); return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. }