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