1/* 2 * Copyright (c) 2021 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// Autogenerated file -- DO NOT EDIT! 17 18template <Format format, typename It, typename... Types> 19static size_t Emit(It out, Types... args) { // NOLINT(readability-function-size) 20 size_t insn_len = 0; 21 22% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 23% fmt = i.format 24% ops = i.operands 25% offsets = [0] # for opcode 26% offsets += ops.map(&:offset).sort 27% offsets += [fmt.size * 8] # terminating offset, used for calculating last operand encoding width 28% 29 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 30 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 31 if constexpr (format == Format::<%= fmt.pretty.upcase %>) { 32 constexpr size_t SIZE = <%= fmt.size %>; 33 constexpr std::array<uint8_t, <%= offsets.size %>> OFF{<%= offsets.join(', ') %>}; 34 static_assert(OFF.size() == sizeof...(args) + 1); 35 std::array<uint8_t, SIZE> buf{}; 36 Span<uint8_t> buf_sp(buf); 37 Span<const uint8_t> off_sp(OFF); 38 EmitImpl(buf_sp, off_sp, args...); 39 std::copy(buf.begin(), buf.end(), out); 40 insn_len = SIZE; 41 } 42 43% end 44 return insn_len; 45} 46 47% OPCODE_TYPE = 'BytecodeInstruction::Opcode' 48% FORMAT_TYPE = 'BytecodeInstruction::Format' 49% 50% def opcode_full_name(i) 51% OPCODE_TYPE + '::' + i.opcode.upcase 52% end 53% 54% def format_full_name(i) 55% FORMAT_TYPE + '::' + i.format.pretty.upcase 56% end 57% 58% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 59% emitter_name = group.first.emitter_name 60% formats = group.map(&:format) 61% 62% if emitter_name == "Jmp" 63% next 64% end 65% 66% signature = emitter_signature(group, group.first.jump?) 67% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ') 68% 69// NOLINTNEXTLINE(misc-definitions-in-headers) 70void BytecodeEmitter::<%= emitter_name %>(<%= signature_str %>) { 71% 72% method_args = signature.map(&:name) 73% opcodes = group.map { |i| opcode_full_name(i) } 74% 75% i = group[0] 76% 77% if i.jcmpz? 78 Jcmpz(<%= opcodes[0] %>, <%= method_args.join(', ') %>); 79% elsif i.jcmp? 80 Jcmp(<%= opcodes.join(', ') %>, <%= method_args.join(', ') %>); 81% elsif group.length() == 1 82% method_args_str = method_args.join(', ') 83% if method_args_str != '' 84% method_args_str = ', ' + method_args_str 85% end 86% format = format_full_name(i) 87% opcode = opcode_full_name(i) 88 pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= opcode %><%= method_args_str %>); 89% else 90% bitlen_vars = [] 91% signature.each do |arg| 92% v = '%s_bitlen' % arg.name 93% bitlen_vars.push(v) 94% if arg.name.start_with?('imm') 95 auto <%= v %> = GetBitLengthSigned(<%= arg.name %>); 96% else 97 auto <%= v %> = GetBitLengthUnsigned(<%= arg.name %>); 98% end 99% end 100% 101% group.each do |i| 102% conditions = [] 103% i.operands.each_with_index do |op, index| 104% conditions.push("%s <= BitImmSize::BITSIZE_%d" % [bitlen_vars[index], op.width]) 105% end 106% format = format_full_name(i) 107% opcode = opcode_full_name(i) 108 109 if (<%= conditions.join(' && ') %>) { 110 pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= opcode %>, <%= method_args.join(', ') %>); 111 return; 112 } 113% end 114% end 115} 116 117% end 118 119/* static */ 120// NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) 121size_t BytecodeEmitter::GetSizeByOpcode(<%= OPCODE_TYPE %> opcode) { 122 switch (opcode) { 123% Panda::instructions.each do |insn| 124 case <%= opcode_full_name(insn) %>: 125 return <%= insn.format.size %>; // NOLINT(readability-magic-numbers) 126% end 127 default: 128 UNREACHABLE(); 129 return 0; 130 } 131} 132 133/* static */ 134// NOLINTNEXTLINE(misc-definitions-in-headers) 135BytecodeEmitter::BitImmSize BytecodeEmitter::GetBitImmSizeByOpcode(<%= OPCODE_TYPE %> opcode) { 136 switch (opcode) { 137% Panda::instructions.each do |insn| 138% if insn.jump? 139 case <%= opcode_full_name(insn) %>: 140 return BytecodeEmitter::BitImmSize::BITSIZE_<%= insn.operands.select(&:imm?).first.width %>; 141% end 142% end 143 default: 144 UNREACHABLE(); 145 return BytecodeEmitter::BitImmSize::BITSIZE_32; // Any return value will do, we are broken here anyway. 146 } 147} 148 149/* static */ 150// NOLINTNEXTLINE(misc-definitions-in-headers) 151<%= OPCODE_TYPE %> BytecodeEmitter::RevertConditionCode(<%= OPCODE_TYPE %> opcode) { 152% CC_INVERTER = { 153% "JEQ" => "JNE", 154% "JNE" => "JEQ", 155% "JLT" => "JGE", 156% "JGE" => "JLT", 157% "JGT" => "JLE", 158% "JLE" => "JGT", 159% } 160 switch (opcode) { 161% Panda::instructions.each do |insn| 162% if insn.conditional? 163 case <%= opcode_full_name(insn) %>: 164 return <%= OPCODE_TYPE %>::<%= insn.opcode.upcase.sub(/^.../, CC_INVERTER) %>; 165% end 166% end 167 default: 168 UNREACHABLE(); 169 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 170 } 171} 172 173/* static */ 174// NOLINTNEXTLINE(misc-definitions-in-headers) 175<%= OPCODE_TYPE %> BytecodeEmitter::GetLongestConditionalJump(<%= OPCODE_TYPE %> opcode) { 176% JCC_WIDENER = { 177% "_V8_IMM8" => "_V8_IMM16", 178% "_V8_IMM16" => "_V8_IMM16", 179% "_IMM8" => "_IMM16", 180% "_IMM16" => "_IMM16", 181% } 182 switch (opcode) { 183% Panda::instructions.each do |insn| 184% if insn.conditional? 185 case <%= OPCODE_TYPE %>::<%= insn.opcode.upcase %>: 186 return <%= OPCODE_TYPE %>::<%= insn.opcode.upcase.sub(/(_V4_IMM4|_V8_IMM16|_IMM8|_IMM16)$/, JCC_WIDENER) %>; 187% end 188% end 189 default: 190 UNREACHABLE(); 191 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 192 } 193} 194