• 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#include "assembly-ins.h"
17#include "mangling.h"
18
19namespace panda::pandasm {
20bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
21    const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
22    const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
23    const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
24    const std::unordered_map<std::string, panda_file::StringItem *> &strings,
25    const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
26    const std::unordered_map<std::string_view, panda::Label>& labels) const {
27    if (!IsValidToEmit()) {
28        std::cerr << "Invalid instruction: " << ToString() << std::endl;
29        LOG(FATAL, ASSEMBLER);
30    }
31    switch(opcode) {
32% instruction_hash = Panda::instructions.map { |i| [i.mnemonic, i] }.to_h
33%
34% Panda::instructions.group_by(&:mnemonic).each_pair do |mn, group|
35% insn = group[index_of_max(group.map(&:format).map(&:size))]
36%
37% def type(insn)
38%   src_acc_ops = insn.acc_and_operands.select(&:src?)
39%   src_acc_ops.size != 0 ? src_acc_ops.first.type : 'none'
40% end
41%
42% def op_size(insn)
43%   type(insn)[1..-1].to_i
44% end
45%
46% def operands(insn, regs = "regs")
47%   ops = []
48%   nr = 0
49%   ni = 0
50%   property_idx_start = 0
51%   num_id = 0
52%   insn.operands.each do |op|
53%     if op.reg?
54%       ops << "#{regs}[#{nr}]"
55%       nr += 1
56%     elsif op.imm?
57%       if insn.jump?
58%         ops << 'labels.find(ids[0])->second'
59%       else
60%         from_type, to_type = op_size(insn) == 64 ? ['double', 'int64_t'] : ['float', 'int32_t']
61%         if insn.float?
62%           ops << bit_cast("imms[#{ni}]", to_type, from_type)
63%         elsif type(insn).start_with? 'u' # can hold both float and integer literals
64%           ops << "std::holds_alternative<double>(imms[#{ni}]) ? #{bit_cast("imms[#{ni}]", to_type, from_type)} : std::get<int64_t>(imms[#{ni}])"
65%         else
66%           ops << "std::get<int64_t>(imms[#{ni}])"
67%         end
68%       end
69%       ni += 1
70%     elsif op.id?
71%       id_properties = insn.properties.slice(property_idx_start, insn.properties.length - property_idx_start)
72%       id_properties.each_with_index do |prop, prop_idx|
73%         if prop == 'method_id'
74%           ops << "methods.find(ids[#{num_id}])->second->GetIndex(method)"
75%           property_idx_start += prop_idx + 1
76%           num_id += 1
77%           break
78%         elsif prop == 'string_id'
79%           ops << "strings.find(ids[#{num_id}])->second->GetIndex(method)"
80%           property_idx_start += prop_idx + 1
81%           num_id += 1
82%           break
83%         elsif prop == 'literalarray_id'
84%           ops << "literalarrays.find(ids[#{num_id}])->second->GetIndex(method)"
85%           property_idx_start += prop_idx + 1
86%           num_id += 1
87%           break
88%         else
89%           next
90%         end
91%       end
92%     else
93%       raise "Unexpected operand type"
94%     end
95%   end
96%   ops
97% end
98    case Opcode::<%= insn.asm_token %>: {
99% if insn.jump?
100        if ((ids.size() == 0) || (labels.find(ids[0]) == labels.cend())) {
101            return false;
102        }
103% end
104% num_id = 0
105% insn.properties.each do |prop|
106%   if prop == 'method_id'
107        if ((ids.size() == 0) || (methods.find(ids[<%= num_id %>]) == methods.cend())) {
108            return false;
109        }
110%     num_id += 1
111%   elsif prop == 'string_id'
112        if ((ids.size() == 0) || (strings.find(ids[<%= num_id %>]) == strings.cend())) {
113            return false;
114        }
115%     num_id += 1
116%   elsif prop == 'literalarray_id'
117        if ((ids.size() == 0) || (literalarrays.find(ids[<%= num_id %>]) == literalarrays.cend())) {
118            return false;
119        }
120%     num_id += 1
121%   end
122% end
123% regs_num = 0
124% imms_num = 0
125% insn.operands.each do |op|
126%   if op.reg?
127%     regs_num += 1
128%   elsif op.imm?
129%     imms_num += 1
130%   end
131% end
132% if insn.simple_call?
133%   if imms_num > 0
134        if (imms.size() < <%= imms_num %>) {
135            return false;
136        }
137%   end
138% elsif insn.jump?
139%   if regs_num > 0
140        if (regs.size() < <%= regs_num %>) {
141            return false;
142        }
143%   end
144% else
145%   if regs_num > 0 and imms_num > 0
146        if (regs.size() < <%= regs_num %> || imms.size() < <%= imms_num %>) {
147            return false;
148        }
149%   elsif regs_num > 0
150        if (regs.size() < <%= regs_num %>) {
151            return false;
152        }
153%   elsif imms_num > 0
154        if (imms.size() < <%= imms_num %>) {
155            return false;
156        }
157%   end
158% end
159% if insn.simple_call?
160        auto registers = regs;
161%   call_mnemonics = if insn.mnemonic.end_with?('.short')
162%     [insn.mnemonic]
163%   else
164%     ["#{insn.mnemonic}.short", insn.mnemonic]
165%   end
166%   call_mnemonics.map { |m| instruction_hash[m] }.each do |i|
167%     registers = i.operands.select(&:reg?)
168        if (registers.size() < <%= registers.size + 1 %>) {
169            while (registers.size() < <%= registers.size %>) {
170                registers.push_back(0);
171            }
172            emitter.<%= i.emitter_name %>(<%= operands(i, "registers").join(", ") %>);
173            break;
174        }
175%   end
176% else
177        emitter.<%= insn.emitter_name %>(<%= operands(insn).join(", ") %>);
178% end
179        break;
180    }
181% end
182    default:
183        assert(0);
184    }
185
186    return true;
187}
188
189}
190