// Copyright (c) 2021-2022 Huawei Device Co., Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. % def get_node_kind(mnemonic) % return "#{mnemonic.gsub('.', '_').upcase}" % end % % def insn2node(insn) % mnemonic = insn.mnemonic.split('.') % return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join() % end % % def get_result_type(insn) % if insn.mnemonic.start_with? "call" % return "ResultType.Unknown" % end % case insn.dtype % when 'i32' % return "ResultType.Int" % when 'i64', 'b64' % return "ResultType.Long" % when 'f64' % return "ResultType.Float" % when 'obj' % return "ResultType.Obj" % else % return "ResultType.None" % end % end % % def get_result_dst(insn) % if insn.properties.include? "acc_write" % return "ResultDst.Acc" % end % dst_operands = insn.operands.select { |op| op.dst? } % if dst_operands.length > 0 and dst_operands[0].reg? % return "ResultDst.VReg" % end % return "ResultDst.None" % end % % def is_VReg(name) % if name == :v % return true % end % end % % def is_Acc(name) % if name == :acc % return true % end % end % % def is_Imm(name) % if name == :imm % return true % end % end % % def is_Id(name) % if %i[method_id type_id field_id string_id literalarray_id callsite_id].include?(name) % return true % end % end % % def is_Call(insn) % if insn.mnemonic.start_with? "call" % return true % end % return false % end % % def is_CallRange(insn) % if insn.mnemonic == "call.range" or insn.mnemonic == "calli.dyn.range" or insn.mnemonic == "ecma.callirangedyn" or insn.mnemonic == "ecma.callithisrangedyn" or insn.mnemonic == "ecma.createobjectwithexcludedkeys" or insn.mnemonic == "ecma.newobjdynrange" % return true % end % return false % end % % def get_operand_type(name, insn) % if is_VReg(name) % return "VReg" % elsif is_Imm(name) % is_jump = insn.properties.include? 'jump' % return is_jump ? "Label" : "Imm" % elsif is_Id(name) % return "string" % else % return nil % end % end % % def get_operands(sig) % return [] unless sig.include? ' ' % _, operands = sig.match(/(\S+) (.+)/).captures % operands = operands.split(', ') % end % % def get_ctor_args(insn) % operands = get_operands(insn.sig) % ops = Array.new % ctor_args = Array.new % operands.map do |operand| % operand_parts = operand.split(':') % case operand_parts.size % when 1 % name = operand_parts[0] % when 2 % name, _ = operand_parts % when 3 % name, _, _ = operand_parts % else % raise 'Unexpected operand string' % end % ops.push(name) % name_tmp = name.to_s.gsub(/[0-9]/, '').to_sym % type = get_operand_type(name_tmp,insn) % if is_Call(insn) and !is_CallRange(insn) and is_VReg(name_tmp) and !insn.mnemonic.include?('acc') % ctor_args.push("#{name}?: #{type}") % else % ctor_args.push("#{name}: #{type}") % end % end % return ops,ctor_args % end % % def get_operand_kind(op, insn) % if op.reg? % if op.src? and op.dst? % return 2 % elsif op.src? % return 0 % elsif op.dst? % return 1 % end % return nil % elsif op.imm? % is_jump = insn.properties.include? 'jump' % return is_jump ? 6 : 3 % elsif op.id? % is_string_id = insn.properties.include? 'string_id' % return is_string_id ? 5 : 4 % else % return nil % end % end % % def make_format(fmt, insn) % operands = fmt.operands.map {|op| "[#{get_operand_kind(op, insn)}, #{op.width}]"} % return "[" + operands.join(", ") + "]" % end % % def get_parent_type(insn) % if insn.prefix != nil and insn.prefix.name == "ecma" % return "Intrinsic" % else % return "IRNode" % end % end // Autogenerated file -- DO NOT EDIT! import * as ts from "typescript"; import { DebugPosInfo, NodeKind } from "./debuginfo"; import { Scope } from "./scope"; export enum IRNodeKind { % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| <%= get_node_kind(mnemonic) %>, % end VREG, IMM, LABEL, VIRTUALSTARTINS_DYN, VIRTUALENDINS_DYN, DEFINE_GLOBAL_VAR, } export function getInstructionSize(opcode: IRNodeKind) { switch(opcode) { % Panda::instructions.each do |insn| % node_kind = get_node_kind(insn.mnemonic) % kind = "IRNodeKind." + node_kind case <%= kind %>: return <%= insn.format.size %>; % end default: // LOGE("getInstructionSize: Unknown opcode:" + opcode); return 0; } } export enum ResultType { None, Unknown, Int, Long, Float, Obj, Boolean } export enum ResultDst { None, Acc, VReg } export enum BuiltIns { NaN, Infinity, globalThis, undefined, Boolean, Number, String, BigInt, Symbol, Null, Object, Function, Global, True, False, LexEnv, MAX_BUILTIN, } export type OperandType = VReg | Imm | Label | string | number export enum OperandKind { // the least significant bit indicates vreg // the second bit indicates src or dst SrcVReg = 0, DstVReg, SrcDstVReg, Imm, Id, StringId, Label } export namespace OperandKind { // @ts-ignore function isVReg(kind: OperandKind): boolean { return kind === OperandKind.SrcVReg || kind === OperandKind.DstVReg || kind === OperandKind.SrcDstVReg; } } export type Format = number[][] export function getInsnMnemonic(opcode: IRNodeKind): string { switch(opcode) { % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % node_kind = get_node_kind(mnemonic) % kind = "IRNodeKind." + node_kind case <%= kind %>: return "<%= mnemonic %>"; % end default: return ''; } } export function getInsnFormats(opcode: IRNodeKind) { switch(opcode) { % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % insn = group.first % formats = group.map {|i| make_format(i,insn) } % node_kind = get_node_kind(mnemonic) % kind = "IRNodeKind." + node_kind case <%= kind %>: { return [ <%= formats.join(",\n ") %> ]; } % end default: return []; } } export abstract class IRNode { private node: ts.Node | NodeKind = NodeKind.Normal; constructor( readonly kind: IRNodeKind, readonly operands: OperandType[], ) {} // for debuginfo public debugPosInfo: DebugPosInfo = new DebugPosInfo(); toString(): string { let mnemonic = this.getMnemonic(); let out = mnemonic + "\t"; if (mnemonic.length < 8) { out += "\t"; } this.operands.forEach((element) => { out = out + element.toString() + ", "; }); return out; } setNode(node: ts.Node | NodeKind) { this.node = node; } getNodeName() { if (this.node != NodeKind.Invalid && this.node != NodeKind.FirstNodeOfFunction && this.node != NodeKind.Normal) { return ts.SyntaxKind[(this.node).kind]; } return "undefined"; } getMnemonic() { return getInsnMnemonic(this.kind); } getFormats() { return getInsnFormats(this.kind); } } export abstract class Intrinsic extends IRNode { constructor( readonly kind: IRNodeKind, readonly operands: OperandType[], ) { super(kind, operands); } toString(): string { return super.toString() + " [i]"; } } export class VReg { private typeIndex: number | undefined; private variableName: string | undefined; num: number = -1; toString(): string { return "V" + this.num; } constructor() { } getTypeIndex() { return this.typeIndex; } setTypeIndex(typeIndex: number) { this.typeIndex = typeIndex; } getVariableName() { return this.variableName; } setVariableName(variableName: string) { this.variableName = variableName; } } export class Imm extends IRNode { readonly value: number; constructor(value: number) { super(IRNodeKind.IMM, []); this.value = value; } toString(): string { return "#" + this.value; } } export class Label extends IRNode { private static global_id = 0; readonly id: number; constructor() { super(IRNodeKind.LABEL, []); this.id = Label.global_id++; } toString(): string { return "LABEL_" + this.id; } } export class DebugInsStartPlaceHolder extends IRNode { private scope: Scope; constructor(scope: Scope) { super(IRNodeKind.VIRTUALSTARTINS_DYN, []); this.scope = scope; } getScope() { return this.scope; } } export class DebugInsEndPlaceHolder extends IRNode { private scope: Scope; constructor(scope: Scope) { super(IRNodeKind.VIRTUALENDINS_DYN, []); this.scope = scope; } getScope() { return this.scope; } } % Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| % insn = group.first % jump = insn.properties.include? 'jump' % node_kind = get_node_kind(mnemonic) % kind = "IRNodeKind." + node_kind % ops_list,ctor_arg_list = get_ctor_args(insn) % ctor_args = ctor_arg_list.map {|arg| "#{arg}"}.join(", ") % ops = ops_list.map { |op| "#{op}"}.join(", ") % result_type = get_result_type(insn) % result_dst = get_result_dst(insn); % is_call_op = is_Call(insn) % is_callrange_op = is_CallRange(insn) % parent_type = get_parent_type(insn) export class <%= insn2node(insn) %> extends <%=parent_type %> { % if is_callrange_op % op_last = ops_list.pop % ops_length = ops_list.size constructor(<%= ctor_arg_list.join(", ")%>[]) { var ctors = [<%=ops_list.join(", ")%>, ...<%=op_last %>] var operands:OperandType[] = [<%=ops_list.join(", ")%>] % for i in 1..ops_length do ctors.shift() % end while (!!(ctors && ctors.length)){ let ctor = ctors.shift() if (ctor != undefined) { operands.push(ctor) } } % elsif insn2node(insn) == "BuiltinR2i" constructor(<%= ctor_arg_list[0] %>, <%= ctor_arg_list[1] %>, <%= ctor_arg_list[2] %>[]) { var operands:OperandType[] = [<%=ops_list[0] %>, <%=ops_list[1] %>, ...<%=ops_list[2] %>] % else constructor(<%= ctor_args %>) { % if is_call_op and ops.length() != 0 var ctors = [<%= ops %>] var operands:OperandType[] = [<%=ops_list[0] %>] ctors.shift() while (!!(ctors && ctors.length)){ let ctor = ctors.shift() if (ctor != undefined) { operands.push(ctor) } } % end % end super( <%= kind %>, % if is_call_op or is_callrange_op or insn2node(insn) == "BuiltinR2i" operands, % else [<%= ops %>] % end ); } % if jump % target_index = insn.operands.index {|op| op.imm? } getTarget(): Label { return