• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &regs, 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> &&regs, 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