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