• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 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_view, 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% inst_map = Panda::instructions.collect { |i| [i.mnemonic, i] }.to_h
33% call_map = {
34%   "call.short" => ["call.short"],
35%   "call" => ["call.short", "call"],
36%   "calli.dyn.short" => ["calli.dyn.short"],
37%   "calli.dyn" => ["calli.dyn.short", "calli.dyn"],
38%   "call.acc.short" => ["call.acc.short"],
39%   "call.acc" => ["call.acc.short", "call.acc"],
40%   "call.virt.short" => ["call.virt.short"],
41%   "call.virt" => ["call.virt.short", "call.virt"],
42%   "call.virt.acc.short" => ["call.virt.acc.short"],
43%   "call.virt.acc" => ["call.virt.acc.short", "call.virt.acc"],
44%   "call.dyn.short" => ["call.dyn.short"],
45%   "call.dyn" => ["call.dyn.short", "call.dyn"],
46%   "initobj.short" => ["initobj.short"],
47%   "initobj" => ["initobj"],
48%   "builtin.idr4" => ["builtin.idr4"],
49%   "builtin.idr6" => ["builtin.idr6"]
50%}
51% Panda::instructions.group_by(&:mnemonic).each_pair do |mn, group|
52% insn = group[index_of_max(group.map(&:format).map(&:size))]
53%
54% def type(insn)
55%   src_acc_ops = insn.acc_and_operands.select(&:src?)
56%   src_acc_ops.size != 0 ? src_acc_ops.first.type : 'none'
57% end
58%
59% def op_size(insn)
60%   type(insn)[1..-1].to_i
61% end
62%
63% def operands(insn, regs = "regs")
64%   ops = []
65%   nr = 0
66%   ni = 0
67%   insn.operands.each do |op|
68%     if op.reg?
69%       ops << "#{regs}[#{nr}]"
70%       nr += 1
71%     elsif op.imm?
72%       if insn.jump?
73%         ops << 'labels.find(ids[0])->second'
74%       else
75%         from_type, to_type = op_size(insn) == 64 ? ['double', 'int64_t'] : ['float', 'int32_t']
76%         if insn.float?
77%           ops << bit_cast("imms[#{ni}]", to_type, from_type)
78%         elsif type(insn).start_with? 'u' # can hold both float and integer literals
79%           ops << "std::holds_alternative<double>(imms[#{ni}]) ? #{bit_cast("imms[#{ni}]", to_type, from_type)} : std::get<int64_t>(imms[#{ni}])"
80%         else
81%           ops << "std::get<int64_t>(imms[#{ni}])"
82%         end
83%       end
84%       ni += 1
85%     elsif op.id?
86%       if insn.properties.include?('method_id')
87%         ops << 'methods.find(ids[0])->second->GetIndex(method)'
88%       elsif insn.properties.include?('field_id')
89%         ops << 'fields.find(ids[0])->second->GetIndex(method)'
90%       elsif insn.properties.include?('type_id')
91%         ops << 'classes.find(ids[0])->second->GetIndex(method)'
92%       elsif insn.properties.include?('string_id')
93%         ops << 'strings.find(ids[0])->second->GetOffset()'
94%       elsif insn.properties.include?('literalarray_id')
95%         ops << 'static_cast<uint32_t>(literalarrays.find(ids[0])->second->GetOffset())'
96%       else
97%         raise "Unexpected ID type"
98%       end
99%     else
100%       raise "Unexpected operand type"
101%     end
102%   end
103%   if insn.call? && insn.properties.include?('method_id')
104%     ops << ops.shift
105%   end
106%   ops
107% end
108    case Opcode::<%= insn.asm_token %>: {
109% if insn.properties.include?('method_id')
110        if ((ids.size() == 0) || (methods.find(ids[0]) == methods.cend())) {
111            return false;
112        }
113% elsif insn.properties.include?('field_id')
114        if ((ids.size() == 0) || (fields.find(ids[0]) == fields.cend())) {
115            return false;
116        }
117% elsif insn.properties.include?('type_id')
118        if ((ids.size() == 0) || (classes.find(ids[0]) == classes.cend())) {
119            return false;
120        }
121% elsif insn.properties.include?('string_id')
122        if ((ids.size() == 0) || (strings.find(ids[0]) == strings.cend())) {
123            return false;
124        }
125% elsif insn.jump?
126        if ((ids.size() == 0) || (labels.find(ids[0]) == labels.cend())) {
127            return false;
128        }
129% end
130% regs_num = 0
131% imms_num = 0
132% insn.operands.each do |op|
133%   if op.reg?
134%     regs_num += 1
135%   elsif op.imm?
136%     imms_num += 1
137%   end
138% end
139% if insn.simple_call?
140%   if imms_num > 0
141        if (imms.size() < <%= imms_num %>) {
142            return false;
143        }
144%   end
145% elsif insn.jump?
146%   if regs_num > 0
147        if (regs.size() < <%= regs_num %>) {
148            return false;
149        }
150%   end
151% else
152%   if regs_num > 0 and imms_num > 0
153        if (regs.size() < <%= regs_num %> || imms.size() < <%= imms_num %>) {
154            return false;
155        }
156%   elsif regs_num > 0
157        if (regs.size() < <%= regs_num %>) {
158            return false;
159        }
160%   elsif imms_num > 0
161        if (imms.size() < <%= imms_num %>) {
162            return false;
163        }
164%   end
165% end
166% if insn.simple_call?
167        auto registers = regs;
168%   call_map[insn.mnemonic].map { |m| inst_map[m] }.each do |i|
169%     registers = i.operands.select(&:reg?)
170        if (registers.size() < <%= registers.size + 1 %>) {
171            while (registers.size() < <%= registers.size %>) {
172                registers.push_back(0);
173            }
174            emitter.<%= i.emitter_name %>(<%= operands(i, "registers").join(", ") %>);
175            break;
176        }
177%   end
178% else
179        emitter.<%= insn.emitter_name %>(<%= operands(insn).join(", ") %>);
180% end
181        break;
182    }
183% end
184    default:
185        assert(0);
186    }
187
188    return true;
189}
190
191}  // namespace panda::pandasm
192