• 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
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