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