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// 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% signature = emitter_signature(group, group.first.jump?) 62% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ') 63% 64// NOLINTNEXTLINE(misc-definitions-in-headers) 65void BytecodeEmitter::<%= emitter_name %>(<%= signature_str %>) { 66% 67% method_args = signature.map(&:name) 68% opcodes = group.map { |i| opcode_full_name(i) } 69% 70% i = group[0] 71% 72% if i.jump? 73% jmp_args = [opcode_full_name(i)] + method_args[0..-2] + ["0"] 74% format = format_full_name(i) 75 branches_.insert(std::make_pair(pc_, label)); 76 pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= jmp_args.join(', ') %>); 77% elsif group.length() == 1 78% jmp_args = [opcode_full_name(i)] + method_args 79% format = format_full_name(i) 80 pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= jmp_args.join(', ') %>); 81% else 82% bitlen_vars = [] 83% signature.each do |arg| 84% v = '%s_bitlen' % arg.name 85% bitlen_vars.push(v) 86% if arg.name.start_with?('imm') 87 auto <%= v %> = GetBitLengthSigned(<%= arg.name %>); 88% else 89 auto <%= v %> = GetBitLengthUnsigned(<%= arg.name %>); 90% end 91% end 92% 93% group.each do |i| 94% conditions = [] 95% i.operands.each_with_index do |op, index| 96% conditions.push("%s <= BitImmSize::BITSIZE_%d" % [bitlen_vars[index], op.width]) 97% end 98% format = format_full_name(i) 99% opcode = opcode_full_name(i) 100 101 if (<%= conditions.join(' && ') %>) { 102 pc_ += Emit<<%= format %>>(std::back_inserter(bytecode_), <%= opcode %>, <%= method_args.join(', ') %>); 103 return; 104 } 105% end 106% end 107} 108 109% end 110 111/* static */ 112// NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) 113size_t BytecodeEmitter::GetSizeByOpcode(<%= OPCODE_TYPE %> opcode) { 114 switch (opcode) { 115% Panda::instructions.each do |insn| 116 case <%= opcode_full_name(insn) %>: 117 return <%= insn.format.size %>; // NOLINT(readability-magic-numbers) 118% end 119 default: 120 UNREACHABLE(); 121 return 0; 122 } 123} 124 125template <Format format, typename OffsT> 126static void UpdateBranchByFormat(uint8_t *insn, OffsT offs) { // NOLINT(readability-function-size) 127% uniq_fmt_jmps = Panda.instructions.select { |i| i.jump? }.uniq { |i| i.format.pretty }.sort_by { |insn| insn.format.pretty } 128% uniq_fmt_jmps.each do |i| 129% fmt = i.format 130% offsets = [i.operands.map(&:offset).max, fmt.size * 8] 131% 132 // Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 133 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 134 if constexpr (format == Format::<%= fmt.pretty.upcase %>) { 135 constexpr size_t SIZE = <%= fmt.size %>; 136 constexpr std::array<uint8_t, <%= offsets.size %>> OFF{<%= offsets.join(', ') %>}; 137 Span<const uint8_t> off_sp(OFF); 138 Span<uint8_t> insn_sp(insn, SIZE); 139 EmitImpl(insn_sp, off_sp, offs); 140 return; 141 } 142 143% end 144 UNREACHABLE(); 145} 146 147/* static */ 148// NOLINTNEXTLINE(misc-definitions-in-headers) 149void BytecodeEmitter::UpdateBranchOffs(uint8_t *insn, int32_t offs) { 150 auto opcode = BytecodeInstruction(insn).GetOpcode(); 151 switch (opcode) { 152% Panda::instructions.each do |insn| 153% if insn.jump? 154 case <%= opcode_full_name(insn) %>: 155 UpdateBranchByFormat<<%= format_full_name(insn) %>>(insn, offs); 156 return; 157% end 158% end 159 default: 160 UNREACHABLE(); 161 } 162} 163 164/* static */ 165// NOLINTNEXTLINE(misc-definitions-in-headers) 166BytecodeEmitter::BitImmSize BytecodeEmitter::GetBitImmSizeByOpcode(<%= OPCODE_TYPE %> opcode) { 167 switch (opcode) { 168% Panda::instructions.each do |insn| 169% if insn.jump? 170 case <%= opcode_full_name(insn) %>: 171 return BytecodeEmitter::BitImmSize::BITSIZE_<%= insn.operands.select(&:imm?).first.width %>; 172% end 173% end 174 default: 175 UNREACHABLE(); 176 return BytecodeEmitter::BitImmSize::BITSIZE_32; // Any return value will do, we are broken here anyway. 177 } 178} 179 180/* static */ 181// NOLINTNEXTLINE(misc-definitions-in-headers) 182<%= OPCODE_TYPE %> BytecodeEmitter::RevertConditionCode(<%= OPCODE_TYPE %> opcode) { 183% CC_INVERTER = { 184% "JEQ" => "JNE", 185% "JNE" => "JEQ", 186% "JLT" => "JGE", 187% "JGE" => "JLT", 188% "JGT" => "JLE", 189% "JLE" => "JGT", 190% } 191 switch (opcode) { 192% Panda::instructions.each do |insn| 193% if insn.conditional? 194% pref = insn.format.prefixed? ? insn.prefix.name.upcase + "_" : "" 195% op = insn.opcode.upcase.delete_prefix(pref) 196% op = CC_INVERTER[/^.../.match(op).to_s] ? op.sub(/^.../, CC_INVERTER).prepend(pref) : "LAST" 197 case <%= opcode_full_name(insn) %>: 198 return <%= OPCODE_TYPE %>::<%= op %>; 199% end 200% end 201 default: 202 UNREACHABLE(); 203 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 204 } 205} 206 207/* static */ 208// NOLINTNEXTLINE(misc-definitions-in-headers) 209<%= OPCODE_TYPE %> BytecodeEmitter::GetLongestJump(<%= OPCODE_TYPE %> opcode) { 210 switch (opcode) { 211% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 212% insn = group[0] 213% if insn.jump? 214% group.each do |i| 215 case <%= OPCODE_TYPE %>::<%= i.opcode.upcase %>: 216% end 217 return <%= OPCODE_TYPE %>::<%= group[-1].opcode.upcase %>; 218% end 219% end 220 default: 221 UNREACHABLE(); 222 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 223 } 224} 225 226/* static */ 227// // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) 228<%= OPCODE_TYPE %> BytecodeEmitter::GetSuitableJump(<%= OPCODE_TYPE %> opcode, BytecodeEmitter::BitImmSize width) { 229 switch (opcode) { 230% jmp_w_list = [32, 16, 8, 4] 231% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 232% insn = group[0] 233% if insn.jump? 234 case <%= OPCODE_TYPE %>::<%= insn.opcode.upcase %>: 235 switch (width) { 236% suit_ind = 0 237% jmp_w_list.each do |w| 238% if group[suit_ind - 1] != nil && w == group[suit_ind - 1].operands.select(&:imm?).first.width 239% if w != jmp_w_list[0] 240 return <%= OPCODE_TYPE %>::<%= (suit_ind == 0) ? "LAST" : group[suit_ind].opcode.upcase %>; 241% end 242% suit_ind = suit_ind - 1 243% end 244 case BytecodeEmitter::BitImmSize::BITSIZE_<%= w %>: 245% end 246 return <%= OPCODE_TYPE %>::<%= (suit_ind == 0) ? "LAST" : group[suit_ind].opcode.upcase %>; 247 } 248 break; 249% end 250% end 251 default: 252 UNREACHABLE(); 253 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 254 } 255 UNREACHABLE(); 256 return <%= OPCODE_TYPE %>::LAST; // Any return value will do, we are broken here anyway. 257} 258