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 18static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Opcode op) 19{ 20 if (static_cast<unsigned>(op) >= <%= Panda.instructions.select(&:prefix).map(&:opcode_idx).min %>) { 21 out.push_back(static_cast<uint8_t>(op)); 22 out.push_back(static_cast<uint8_t>(static_cast<unsigned>(op) >> 8)); 23 } else { 24 out.push_back(static_cast<uint8_t>(op)); 25 } 26 return out; 27} 28 29#ifdef WITH_MOCK 30#include <bytecode_emitter.cpp> 31#endif 32 33template <BytecodeInstruction::Format format, typename It, typename... Types> 34static size_t Emit(It out, Types... args) 35{ 36 size_t insn_len = 0; 37 38% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 39% fmt = i.format 40% ops = i.operands 41% offsets = [0] # for opcode 42% offsets += ops.map(&:offset).sort 43% offsets += [fmt.size * 8] 44% 45 if constexpr (format == BytecodeInstruction::Format::<%= fmt.pretty.upcase %>) { 46 constexpr size_t SIZE = <%= fmt.size %>; 47 constexpr std::array<uint8_t, <%= offsets.size %>> OFF{<%= offsets.join(', ') %>}; 48 static_assert(OFF.size() == sizeof...(args) + 1); 49 std::array<uint8_t, SIZE> buf{}; 50 Span<uint8_t> buf_sp(buf); 51 Span<const uint8_t> off_sp(OFF); 52 EmitImpl(buf_sp, off_sp, args...); 53 std::copy(buf.begin(), buf.end(), out); 54 insn_len = SIZE; 55 } 56 57% end 58 return insn_len; 59} 60 61static constexpr uint8_t DEFAULT_OFFSET = 4U; 62static constexpr std::array<uint8_t, 4U> OFFSETS{8, 16, 32, 64}; 63 64static std::vector<std::vector<uint8_t>> MakeOffsetsVector(uint8_t current) 65{ 66 std::vector<std::vector<uint8_t>> res; 67 std::vector<uint8_t> init; 68 init.reserve(current); 69 for (uint8_t i = 0U; i < current; i++) { 70 init.emplace_back(i * DEFAULT_OFFSET); 71 } 72 res.emplace_back(init); 73 for (uint8_t i = 0U; i < 4U; i++) { 74 for (uint8_t j = 0U; j < current - 1; j++) { 75 std::vector<uint8_t> tmp; 76 tmp.reserve(current); 77 uint8_t start = 0U; 78 for (uint8_t z = 0U; z < current; z++) { 79 tmp.emplace_back(start); 80 if (j == z) { 81 start += OFFSETS[i]; 82 } else { 83 start += DEFAULT_OFFSET; 84 } 85 } 86 res.emplace_back(tmp); 87 } 88 } 89 return res; 90} 91 92template <BytecodeInstruction::Format format, typename It, typename... Types> 93static size_t EmitMock(It out, Types... args) 94{ 95 size_t insn_len = 0; 96 97% insns_uniq_sort_fmts.each do |i| # Panda::formats.each do |fmt| 98% fmt = i.format 99% ops = i.operands 100% if fmt.size == 1 101% offsets4 = [0] # for opcode 102% offsets4 += [4] 103% offsets8 = [0] # for opcode 104% offsets8 += [8] 105% offsets16 = [0] # for opcode 106% offsets16 += [16] 107% offsets32 = [0] # for opcode 108% offsets32 += [32] 109% offsets64 = [0] # for opcode 110% offsets64 += [64] 111 112 if constexpr (format == BytecodeInstruction::Format::<%= fmt.pretty.upcase %>) { 113 constexpr size_t SIZE = <%= fmt.size %>; 114 constexpr std::array<uint8_t, <%= offsets4.size %>> OFF4{<%= offsets4.join(', ') %>}; 115 constexpr std::array<uint8_t, <%= offsets8.size %>> OFF8{<%= offsets8.join(', ') %>}; 116 constexpr std::array<uint8_t, <%= offsets16.size %>> OFF16{<%= offsets16.join(', ') %>}; 117 constexpr std::array<uint8_t, <%= offsets32.size %>> OFF32{<%= offsets32.join(', ') %>}; 118 constexpr std::array<uint8_t, <%= offsets64.size %>> OFF64{<%= offsets64.join(', ') %>}; 119 static_assert(OFF4.size() == sizeof...(args) + 1); 120 static_assert(OFF8.size() == sizeof...(args) + 1); 121 static_assert(OFF16.size() == sizeof...(args) + 1); 122 static_assert(OFF32.size() == sizeof...(args) + 1); 123 static_assert(OFF64.size() == sizeof...(args) + 1); 124 std::array<uint8_t, SIZE * 8> buf{}; 125 Span<uint8_t> buf_sp(buf); 126 Span<const uint8_t> off_sp4(OFF4); 127 EmitImpl(buf_sp, off_sp4, args...); 128 Span<const uint8_t> off_sp8(OFF8); 129 EmitImpl(buf_sp, off_sp8, args...); 130 Span<const uint8_t> off_sp16(OFF16); 131 EmitImpl(buf_sp, off_sp16, args...); 132 Span<const uint8_t> off_sp32(OFF32); 133 EmitImpl(buf_sp, off_sp32, args...); 134 Span<const uint8_t> off_sp64(OFF64); 135 EmitImpl(buf_sp, off_sp64, args...); 136 std::copy(buf.begin(), buf.end(), out); 137 insn_len = SIZE; 138 } 139% else 140 141 if constexpr (format == BytecodeInstruction::Format::<%= fmt.pretty.upcase %>) { 142 constexpr size_t SIZE = <%= fmt.size %>; 143 std::array<uint8_t, SIZE * 8U> buf{}; 144 Span<uint8_t> buf_sp(buf); 145 const auto &vector = MakeOffsetsVector(<%= ops.size + 2 %>); 146 for (const auto &v : vector) { 147 Span<const uint8_t> off_sp(v); 148 EmitImpl(buf_sp, off_sp, args...); 149 } 150 std::copy(buf.begin(), buf.end(), out); 151 insn_len = SIZE; 152 } 153% end 154% end 155 156 return insn_len; 157} 158 159% OPCODE_TYPE = 'BytecodeInstruction::Opcode' 160% FORMAT_TYPE = 'BytecodeInstruction::Format' 161% 162% def opcode_full_name(i) 163% OPCODE_TYPE + '::' + i.opcode.upcase 164% end 165% 166% def format_full_name(i) 167% FORMAT_TYPE + '::' + i.format.pretty.upcase 168% end 169% 170% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 171% emitter_name = group.first.emitter_name 172% formats = group.map(&:format) 173% signature = emitter_signature(group, group.first.jump?) 174% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ') 175% 176 177[[maybe_unused]] static void <%= emitter_name %>Mock(<%= signature_str %>) 178{ 179 std::vector<uint8_t> bytecode; 180% 181% method_args = signature.map(&:name) 182% opcodes = group.map { |i| opcode_full_name(i) } 183% 184% i = group[0] 185% 186% if i.jump? 187% jmp_args = [opcode_full_name(i)] + method_args[0..-2] + ["0"] 188% format = format_full_name(i) 189 EmitMock<<%= format %>>(std::back_inserter(bytecode), <%= jmp_args.join(', ') %>); 190% elsif group.length() == 1 191% jmp_args = [opcode_full_name(i)] + method_args 192% format = format_full_name(i) 193 EmitMock<<%= format %>>(std::back_inserter(bytecode), <%= jmp_args.join(', ') %>); 194% else 195% group.each do |i| 196% format = format_full_name(i) 197% opcode = opcode_full_name(i) 198 EmitMock<<%= format %>>(std::back_inserter(bytecode), <%= opcode %>, <%= method_args.join(', ') %>); 199% end 200% end 201} 202% end 203% 204% def get_min(width, is_signed) 205% if width < 8 206% if is_signed 207% return '%d' % ((1 << (width - 1)) - (1 << width)) 208% else 209% return '%d' % ((1 << (width - 1))) 210% end 211% else 212% if is_signed 213% return 'std::numeric_limits<int%d_t>::min()' % width 214% else 215% return '%s + 1' % get_max(width / 2, false) 216% end 217% end 218% end 219% 220% def get_max(width, is_signed) 221% if width < 8 222% if is_signed 223% return '%d' % ((1 << (width - 1)) - 1) 224% else 225% return '%d' % ((1 << width) - 1) 226% end 227% else 228% if is_signed 229% return 'std::numeric_limits<int%d_t>::max()' % width 230% else 231% return 'std::numeric_limits<uint%d_t>::max()' % width 232% end 233% end 234% end 235% 236% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 237% emitter_name = group.first.emitter_name 238% formats = group.map(&:format) 239% signature = emitter_signature(group, group.first.jump?) 240% method_args = signature.map(&:name) 241% 242% if emitter_name == "Jmp" 243% next 244% end 245% 246% i = group.first 247% 248% if i.operands.empty? 249 250HWTEST(BytecodeEmitter, <%= emitter_name %>, testing::ext::TestSize.Level0) 251{ 252 TestNoneFormat(Opcode::<%= i.opcode.upcase %>, [](BytecodeEmitter* emitter) { 253 emitter-><%= emitter_name %>(); 254 }); 255 <%= emitter_name %>Mock(); 256} 257% elsif i.jump? && method_args.length == 1 258% group.each do |group_insn| 259% pretty_format = group_insn.format.pretty.upcase 260% opcode = group_insn.opcode.upcase 261 262HWTEST(BytecodeEmitter, <%= emitter_name %>_<%= pretty_format %>_AUTO, testing::ext::TestSize.Level0) 263{ 264 Jmpz_<%= pretty_format %>(Opcode::<%= opcode %>, [](BytecodeEmitter* emitter, const Label &label) { 265 emitter-><%= emitter_name %>(label); 266 <%= emitter_name %>Mock(label); 267 }); 268} 269% end 270% elsif i.jump? && method_args.length == 2 271% group.each do |group_insn| 272% pretty_format = group_insn.format.pretty.upcase 273% opcode = group_insn.opcode.upcase 274 275HWTEST(BytecodeEmitter, <%= emitter_name %>_<%= pretty_format %>_AUTO, testing::ext::TestSize.Level0) 276{ 277 Jmp_<%= pretty_format %>(Opcode::<%= opcode %>, [](BytecodeEmitter* emitter, uint8_t reg, const Label &label) { 278 emitter-><%= emitter_name %>(reg, label); 279 <%= emitter_name %>Mock(reg, label); 280 }); 281} 282% end 283% else 284% group.each do |i| 285 286HWTEST(BytecodeEmitter, <%= emitter_name %>_<%= i.format.pretty.upcase %>_AUTO, testing::ext::TestSize.Level0) 287{ 288% num_ops = i.operands.length() 289% ops = format_ops(i.format) 290% ['min', 'max'].repeated_permutation(num_ops).each do |p| 291% args = [] 292% vals = [] 293% p.each_with_index do |v, index| 294% op = ops[index] 295% is_signed = op.name.start_with?('imm') 296% arg = v == 'min' ? get_min(op.width, is_signed) : get_max(op.width, is_signed) 297% args.push(arg) 298% if op.width <= 8 299% vals.push(arg) 300% elsif op.width == 16 301% vals.push('Split16(%s)' % arg) 302% elsif op.width == 32 303% vals.push('Split32(%s)' % arg) 304% else 305% vals.push('Split64(%s)' % arg) 306% end 307% end 308% 309% index = 0 310% packed_vals = [] 311% while index < num_ops do 312% if ops[index].width == 4 313% packed_vals.push('(((static_cast<uint8_t>(%s) & 0xF) << 4) | (static_cast<uint8_t>(%s) & 0xF))' % [vals[index + 1], vals[index]]) 314% index += 2 315% else 316% packed_vals.push(vals[index]) 317% index += 1 318% end 319% end 320% 321 { 322 BytecodeEmitter emitter; 323 emitter.<%= emitter_name %>(<%= args.join(', ') %>); 324 std::vector<uint8_t> out; 325 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out)); 326 std::vector<uint8_t> expected; 327 expected << Opcode::<%= i.opcode.upcase %> << <%= packed_vals.join(' << ') %>; 328 ASSERT_EQ(expected, out); 329 <%= emitter_name %>Mock(<%= args.join(', ') %>); 330 } 331 332% end 333} 334% end 335% end 336% end 337