• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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