1% def get_node_kind(mnemonic) 2% return "#{mnemonic.gsub('.', '_').upcase}" 3% end 4% 5% def get_format_name(mnemonic) 6% return "#{mnemonic.gsub('.', '_').upcase}" + "_FORMATS" 7% end 8% 9% def insn2node(insn) 10% mnemonic = insn.mnemonic.split('.') 11% return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join() 12% end 13% 14% def is_VReg(name) 15% if name == :v 16% return true 17% end 18% end 19% 20% def is_Acc(name) 21% if name == :acc 22% return true 23% end 24% end 25% 26% def is_Imm(name) 27% if name == :imm 28% return true 29% end 30% end 31% 32% def is_Id(name) 33% if %i[method_id type_id field_id string_id stringId callsite_id literalarray_id].include?(name) 34% return true 35% end 36% end 37% 38% def get_operand_type(name, name_tmp, insn) 39% if is_VReg (name_tmp) 40% return 'uint16_t' 41% elsif is_Imm(name_tmp) 42% if insn.properties.include? 'jump' 43% return "std::string" 44% end 45% if insn.sig.include? 'imm:f64' 46% return 'double' 47% end 48% return 'int64_t' 49% elsif is_Id(name_tmp) 50% return 'std::string' 51% else 52% return nil 53% end 54% end 55% 56% def get_operands(sig) 57% return [] unless sig.include? ' ' 58% _, operands = sig.match(/(\S+) (.+)/).captures 59% operands = operands.split(', ') 60% end 61% 62% def get_ctor_args(insn) 63% operands = get_operands(insn.sig) 64% ops = Array.new 65% ctor_args = Array.new 66% imms = Array.new 67% imm_members = Array.new 68% ids = Array.new 69% id_members = Array.new 70% regs = Array.new 71% reg_members = Array.new 72% id_count = 0 73% operands.map do |operand| 74% operand_parts = operand.split(':') 75% case operand_parts.size 76% when 1 77% name = operand_parts[0] 78% when 2 79% name, _ = operand_parts 80% when 3 81% name, _, _ = operand_parts 82% else 83% raise 'Unexpected operand string' 84% end 85% 86% name_tmp = name.to_s.gsub(/[0-9]/, '').to_sym; 87% 88% if is_Id(name_tmp) 89% name = "stringId_" 90% name.concat(id_count.to_s) 91% id_count = id_count + 1 92% end 93% type = get_operand_type(name, name_tmp, insn) 94% if type == "std::string" 95% ids.push(name) 96% id_members.push("#{type} #{name}") 97% elsif type == "uint16_t" 98% regs.push(name) 99% reg_members.push("#{type} #{name}") 100% else 101% imms.push(name) 102% imm_members.push("#{type} #{name}") 103% end 104% ctor_args.push("#{type} #{name}") 105% end 106% ops = regs + imms + ids 107% members = reg_members + imm_members + id_members 108% return ops,ctor_args,members,ids,imms,regs 109% end 110% 111/* 112 * Copyright (c) 2025 Huawei Device Co., Ltd. 113 * Licensed under the Apache License, Version 2.0 (the "License"); 114 * you may not use this file except in compliance with the License. 115 * You may obtain a copy of the License at 116 * 117 * http://www.apache.org/licenses/LICENSE-2.0 118 * 119 * Unless required by applicable law or agreed to in writing, software 120 * distributed under the License is distributed on an "AS IS" BASIS, 121 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 122 * See the License for the specific language governing permissions and 123 * limitations under the License. 124 */ 125 126// Autogenerated file -- DO NOT EDIT! 127 128#ifndef ASSEMBLER_ASSEMBLY_INS_H 129#define ASSEMBLER_ASSEMBLY_INS_H 130 131#include <array> 132#include <string> 133#include <string_view> 134#include <unordered_map> 135#include <variant> 136#include <vector> 137 138#include "assembly-debug.h" 139#include "bytecode_emitter.h" 140#include "file_items.h" 141#include "isa.h" 142#include "lexer.h" 143 144namespace panda::pandasm { 145class Ins; 146using IType = std::variant<int64_t, double>; 147using InsPtr = std::unique_ptr<pandasm::Ins>; 148 149enum class Opcode { 150#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode, 151 PANDA_INSTRUCTION_LIST(OPLIST) 152#undef OPLIST 153 INVALID, 154 NUM_OPCODES = INVALID 155}; 156 157enum InstFlags { 158 NONE = 0, 159 JUMP = (1U << 0U), 160 COND = (1U << 1U), 161 CALL = (1U << 2U), 162 RETURN = (1U << 3U), 163 ACC_READ = (1U << 4U), 164 ACC_WRITE = (1U << 5U), 165 PSEUDO = (1U << 6U), 166 THROWING = (1U << 7U), 167 METHOD_ID = (1U << 8U), 168 FIELD_ID = (1U << 9U), 169 TYPE_ID = (1U << 10U), 170 STRING_ID = (1U << 11U), 171 LITERALARRAY_ID = (1U << 12U), 172 CALL_RANGE = (1U << 13U), 173}; 174 175constexpr int INVALID_REG_IDX = -1; 176 177constexpr size_t MAX_NUMBER_OF_SRC_REGS = 4; // TODO(mbolshov): auto-generate 178 179constexpr InstFlags operator|(InstFlags a, InstFlags b) 180{ 181 using utype = std::underlying_type_t<InstFlags>; 182 return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b)); 183} 184 185#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags, 186constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = { 187 PANDA_INSTRUCTION_LIST(OPLIST)}; 188#undef OPLIST 189 190#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width, 191constexpr std::array<size_t, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = { 192 PANDA_INSTRUCTION_LIST(OPLIST)}; 193#undef OPLIST 194 195#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx, 196constexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)}; 197#undef OPLIST 198 199#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs, 200// clang-format off 201constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, 202 static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)}; 203// clang-format on 204#undef OPLIST 205 206class Ins { 207public: 208 std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const; 209 virtual std::string OpcodeToString() const 210 { 211 return ""; 212 } 213 214 bool HasFlag(InstFlags flag) const 215 { 216 if (opcode == Opcode::INVALID) { // TODO(mbolshov): introduce 'label' opcode for labels 217 return false; 218 } 219 return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0; 220 } 221 222 bool CanThrow() const 223 { 224 return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) || 225 HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID); 226 } 227 228 bool IsJump() const 229 { 230 return HasFlag(InstFlags::JUMP); 231 } 232 233 bool IsConditionalJump() const 234 { 235 return IsJump() && HasFlag(InstFlags::COND); 236 } 237 238 bool IsCall() const 239 { // Non-range call 240 return HasFlag(InstFlags::CALL); 241 } 242 243 bool IsCallRange() const 244 { // Range call 245 return HasFlag(InstFlags::CALL_RANGE); 246 } 247 248 bool IsPseudoCall() const 249 { 250 return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL); 251 } 252 253 bool IsReturn() const 254 { 255 return HasFlag(InstFlags::RETURN); 256 } 257 258 size_t MaxRegEncodingWidth() const 259 { 260 if (opcode == Opcode::INVALID) { 261 return 0; 262 } 263 return INST_WIDTH_TABLE[static_cast<size_t>(opcode)]; 264 } 265 266 size_t OperandListLength() const 267 { 268 return Regs().size() + Ids().size() + Imms().size(); 269 } 270 271 bool IsValidToEmit() const 272 { 273 const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth(); 274 for (auto reg : Regs()) { 275 if (reg >= INVALID_REG_NUM) { 276 return false; 277 } 278 } 279 return true; 280 } 281 282 bool HasDebugInfo() const 283 { 284 return ins_debug.line_number != 0; 285 } 286 287 virtual std::vector<std::string> Ids() const 288 { 289 return {}; 290 } 291 292 virtual std::vector<std::uint16_t> Regs() const 293 { 294 return {}; 295 } 296 297 virtual std::vector<IType> Imms() const 298 { 299 return {}; 300 } 301 302 virtual bool IsLabel() const 303 { 304 return false; 305 } 306 307 virtual const std::string &Label() const 308 { 309 return EMPTY_STRING; 310 } 311 312% max_reg_cnt = 0 313% max_imm_cnt = 0 314% max_id_cnt = 0 315% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 316% insn = group.first 317% ops_list,ctor_arg_list,member_list,id_list,imm_list,reg_list = get_ctor_args(insn) 318% max_reg_cnt = max_reg_cnt > reg_list.length ? max_reg_cnt : reg_list.length 319% max_imm_cnt = max_imm_cnt > imm_list.length ? max_imm_cnt : imm_list.length 320% max_id_cnt = max_id_cnt > id_list.length ? max_id_cnt : id_list.length 321% end 322 std::string &GetId(size_t idx) 323 { 324 switch(idx) { 325% max_id_cnt.times do |i| 326 case <%= i %>: 327 return GetId<%= i %>(); 328% end 329 default: 330 UNREACHABLE(); 331 } 332 } 333 334 const std::string &GetId(size_t idx) const 335 { 336 switch(idx) { 337% max_id_cnt.times do |i| 338 case <%= i %>: 339 return GetId<%= i %>(); 340% end 341 default: 342 UNREACHABLE(); 343 } 344 } 345 346 void SetId(size_t idx, const std::string &value) 347 { 348 switch(idx) { 349% max_id_cnt.times do |i| 350 case <%= i %>: 351 return SetId<%= i %>(value); 352% end 353 default: 354 UNREACHABLE(); 355 } 356 } 357 358 std::uint16_t GetReg(size_t idx) const 359 { 360 switch(idx) { 361% max_reg_cnt.times do |i| 362 case <%= i %>: 363 return GetReg<%= i %>(); 364% end 365 default: 366 UNREACHABLE(); 367 } 368 } 369 370 void SetReg(size_t idx, const uint16_t value) 371 { 372 switch(idx) { 373% max_reg_cnt.times do |i| 374 case <%= i %>: 375 return SetReg<%= i %>(value); 376% end 377 default: 378 UNREACHABLE(); 379 } 380 } 381 382 IType GetImm(size_t idx) const 383 { 384 switch(idx) { 385% max_imm_cnt.times do |i| 386 case <%= i %>: 387 return GetImm<%= i %>(); 388% end 389 default: 390 UNREACHABLE(); 391 } 392 } 393 394 void SetImm(size_t idx, const IType &value) 395 { 396 switch(idx) { 397% max_imm_cnt.times do |i| 398 case <%= i %>: 399 return SetImm<%= i %>(value); 400% end 401 default: 402 UNREACHABLE(); 403 } 404 } 405 406 static bool Emit(BytecodeEmitter &emitter, const InsPtr &ins, panda_file::MethodItem *method, 407 const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods, 408 const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields, 409 const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes, 410 const std::unordered_map<std::string, panda_file::StringItem *> &strings, 411 const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays, 412 const std::unordered_map<std::string_view, panda::Label>& labels); 413 414 Ins *DeepCopy() 415 { 416 ASSERT(!IsLabel()); 417 auto res = Ins::CreateIns(opcode, Regs(), Imms(), Ids()); 418 res->ins_debug = ins_debug; 419 return res; 420 } 421 422 template <typename... Args> 423 static Ins *CreateIns(Opcode opcode, Args &&... args); 424 425 virtual ~Ins() = default; 426 427 debuginfo::Ins ins_debug; 428 Opcode opcode; 429 430protected: 431 explicit Ins(Opcode opcode) : opcode(opcode) {} 432 433private: 434% max_reg_cnt.times do |i| 435 virtual void SetReg<%= i %>(const uint16_t reg) 436 { 437 UNREACHABLE(); 438 } 439 440 virtual uint16_t GetReg<%= i %>() const 441 { 442 UNREACHABLE(); 443 } 444 445% end 446% 447% max_imm_cnt.times do |i| 448 virtual void SetImm<%= i %>(const IType &imm) 449 { 450 UNREACHABLE(); 451 } 452 453 virtual IType GetImm<%= i %>() const 454 { 455 UNREACHABLE(); 456 } 457% end 458% 459% max_id_cnt.times do |i| 460 virtual void SetId<%= i %>(const std::string &id) 461 { 462 UNREACHABLE(); 463 } 464 465 virtual std::string &GetId<%= i %>() 466 { 467 UNREACHABLE(); 468 } 469 470 virtual const std::string &GetId<%= i %>() const 471 { 472 UNREACHABLE(); 473 } 474 475% end 476 static const std::string EMPTY_STRING; 477 std::string OperandsToString(bool print_args = false, size_t first_arg_idx = 0) const; 478 std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const; 479 std::string ImmsToString(bool &first) const; 480 std::string IdsToString(bool &first) const; 481 482 std::string IdToString(size_t idx, bool is_first) const; 483 std::string ImmToString(size_t idx, bool is_first) const; 484 std::string RegToString(size_t idx, bool is_first, bool print_args = false, size_t first_arg_idx = 0) const; 485}; 486 487class LabelIns : public Ins { 488public: 489 LabelIns(std::string label) : Ins(Opcode::INVALID), label_(label) {} 490 491 bool IsLabel() const override 492 { 493 return true; 494 } 495 496 const std::string &Label() const override 497 { 498 return label_; 499 } 500 501 std::string OpcodeToString() const override 502 { 503 return label_ + ": "; 504 } 505 506private: 507 std::string label_; 508}; 509 510% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 511% insn = group.first 512% node_kind = get_node_kind(mnemonic) 513% class_name = insn2node(insn) 514% base_class = "Ins" 515% ops_list,ctor_arg_list,member_list,id_list,imm_list,reg_list = get_ctor_args(insn) 516% ctor_args = ctor_arg_list.map {|arg| "#{arg}"}.join(", ") 517% members = member_list.map {|member| "#{member}_;"}.join("\n ") 518% ids = id_list.map{|id| "#{id}_"}.join(", ") 519% imms = imm_list.map{|imm| "#{imm}_"}.join(", ") 520% regs = reg_list.map{|reg| "#{reg}_"}.join(", ") 521% id_index = imm_index = reg_index = -1 522% init = "" 523% if id_list.length != 0 524% init += "\n " + id_list.map {|id| id_index+=1; "#{id}_ = ids[#{id_index}];"}.join("\n ") 525% end 526% if imm_list.length != 0 527% init += "\n " + imm_list.map {|imm| imm_index+=1; "#{imm}_ = std::holds_alternative<int64_t>(imms[#{imm_index}]) ? std::get<int64_t>(imms[#{imm_index}]) : std::get<double>(imms[#{imm_index}]);"}.join("\n ") 528% end 529% if reg_list.length != 0 530% init += "\n " + reg_list.map {|reg| reg_index+=1; "#{reg}_ = regs[#{reg_index}];"}.join("\n ") 531% end 532% ops = (ops_list.length == 0 ? "" : ", ") + ops_list.map { |op| "#{op}_(#{op})"}.join(", ") 533class <%= class_name %> : public <%= base_class %> { 534public: 535 <%= class_name %>(<%= ctor_args %>) : <%= base_class %>(Opcode::<%= insn.asm_token %>)<%= ops %> {} 536 <%= class_name %>(std::vector<std::uint16_t> ®s, std::vector<IType> &imms, std::vector<std::string> &ids) : <%= base_class %>(Opcode::<%= insn.asm_token %>) 537 { 538 ASSERT(regs.size() >= <%= reg_index + 1 %>); 539 ASSERT(ids.size() >= <%= id_index + 1 %>); 540 ASSERT(imms.size() >= <%= imm_index + 1 %>); 541 <%= init %> 542 } 543 <%= class_name %>(std::vector<std::uint16_t> &®s, std::vector<IType> &&imms, std::vector<std::string> &&ids) : <%= base_class %>(Opcode::<%= insn.asm_token %>) 544 { 545 ASSERT(regs.size() >= <%= reg_index + 1 %>); 546 ASSERT(ids.size() >= <%= id_index + 1 %>); 547 ASSERT(imms.size() >= <%= imm_index + 1 %>); 548 <%= init %> 549 } 550 551 std::string OpcodeToString() const override 552 { 553 return "<%= insn.mnemonic%>"; 554 } 555 556 std::vector<std::uint16_t> Regs() const override 557 { 558 return {<%= regs %>}; 559 } 560 561 std::vector<IType> Imms() const override 562 { 563 return {<%= imms %>}; 564 } 565 566 std::vector<std::string> Ids() const override 567 { 568 return {<%=ids %>}; 569 } 570 571% if ops_list.length != 0 572private: 573 <%= members %> 574% idx = 0 575% reg_list.each do |reg| 576 void SetReg<%= idx %>(const uint16_t reg) override 577 { 578 <%= reg %>_ = reg; 579 } 580 581 std::uint16_t GetReg<%= idx %>() const override 582 { 583 return <%= reg %>_; 584 } 585 586% idx += 1 587% end 588% 589% idx = 0 590% imm_list.each do |imm| 591 void SetImm<%= idx %>(const IType &imm) override 592 { 593 <%= imm %>_ = std::holds_alternative<int64_t>(imm) ? std::get<int64_t>(imm) : std::get<double>(imm); 594 } 595 596 IType GetImm<%= idx %>() const override 597 { 598 return <%= imm %>_; 599 } 600 601% idx += 1 602% end 603% 604% idx = 0 605% id_list.each do |id| 606 void SetId<%= idx %>(const std::string &id) override 607 { 608 <%= id %>_ = id; 609 } 610 611 std::string &GetId<%= idx %>() override 612 { 613 return <%= id %>_; 614 } 615 616 const std::string &GetId<%= idx %>() const override 617 { 618 return <%= id %>_; 619 } 620 621% idx += 1 622% end 623% end 624}; 625% end 626 627template <typename... Args> 628Ins *Ins::CreateIns(Opcode opcode, Args &&... args) 629{ 630 switch(opcode) { 631% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| 632% insn = group.first 633% class_name = insn2node(insn) 634 case Opcode::<%= insn.asm_token %>: { 635 return new <%= class_name %>(std::forward<Args>(args)...); 636 } 637% end 638 default: 639 UNREACHABLE(); 640 } 641} 642 643} // namespace panda::pandasm 644 645#endif // ASSEMBLER_ASSEMBLY_INS_H