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