• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2021-2022 Huawei Device Co., Ltd.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6//     http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14import { PandaGen } from "./pandagen"
15% def get_node_kind(mnemonic)
16%   return "#{mnemonic.gsub('.', '_').upcase}"
17% end
18%
19% def insn2node(insn)
20%   mnemonic = insn.mnemonic.split('.')
21%   return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join()
22% end
23%
24% def get_result_type(insn)
25%   if insn.mnemonic.start_with? "call"
26%     return "ResultType.Unknown"
27%   end
28%   case insn.dtype
29%   when 'i32'
30%     return "ResultType.Int"
31%   when 'i64', 'b64'
32%     return "ResultType.Long"
33%   when 'f64'
34%     return "ResultType.Float"
35%   when 'obj'
36%     return "ResultType.Obj"
37%   else
38%     return "ResultType.None"
39%   end
40% end
41%
42% def get_result_dst(insn)
43%   if insn.properties.include? "acc_write"
44%     return "ResultDst.Acc"
45%   end
46%   dst_operands = insn.operands.select { |op| op.dst? }
47%   if dst_operands.length > 0 and dst_operands[0].reg?
48%     return "ResultDst.VReg"
49%   end
50%   return "ResultDst.None"
51% end
52%
53% def is_VReg(name)
54%     if name ==  :v
55%        return true
56%     end
57% end
58%
59% def is_Acc(name)
60%    if name ==  :acc
61%        return true
62%     end
63% end
64%
65% def is_Imm(name)
66%    if name ==  :imm
67%        return true
68%     end
69% end
70%
71% def is_Id(name)
72%     if %i[method_id type_id field_id string_id literalarray_id callsite_id].include?(name)
73%        return true
74%     end
75% end
76%
77% def is_Call(insn)
78%   if insn.mnemonic.start_with? "callruntime"
79%      return false
80%   end
81%   if insn.mnemonic.start_with? "call"
82%      return true
83%   end
84%   return false
85% end
86%
87% def is_CallRange(insn)
88%   if insn.mnemonic == "callrange" or insn.mnemonic == "wide.callrange" or
89%       insn.mnemonic == "callthisrange" or insn.mnemonic == "wide.callthisrange" or
90%       insn.mnemonic == "newobjrange" or insn.mnemonic == "wide.newobjrange" or
91%       insn.mnemonic == "createobjectwithexcludedkeys" or insn.mnemonic == "wide.createobjectwithexcludedkeys" or
92%       insn.mnemonic == "supercallthisrange" or insn.mnemonic == "wide.supercallthisrange" or
93%       insn.mnemonic == "supercallarrowrange" or insn.mnemonic == "wide.supercallarrowrange"
94%      return true
95%   end
96%   return false
97% end
98%
99% def get_operand_type(name, insn)
100%   if is_VReg(name)
101%     return "VReg"
102%   elsif is_Imm(name)
103%     is_jump = insn.properties.include? 'jump'
104%     return is_jump ? "Label" : "Imm"
105%   elsif is_Id(name)
106%     return "string"
107%   else
108%     return nil
109%   end
110% end
111%
112% def get_operands(sig)
113%     return [] unless sig.include? ' '
114%     _, operands = sig.match(/(\S+) (.+)/).captures
115%     operands = operands.split(', ')
116%     end
117%
118% def get_ctor_args(insn)
119%     operands = get_operands(insn.sig)
120%     ops = Array.new
121%     ctor_args = Array.new
122%     operands.map do |operand|
123%     operand_parts = operand.split(':')
124%       case operand_parts.size
125%       when 1
126%         name = operand_parts[0]
127%       when 2
128%         name, _ = operand_parts
129%       when 3
130%         name, _, _ = operand_parts
131%       else
132%         raise 'Unexpected operand string'
133%       end
134%       ops.push(name)
135%       name_tmp = name.to_s.gsub(/[0-9]/, '').to_sym
136%       type = get_operand_type(name_tmp,insn)
137%       if is_Call(insn) and !is_CallRange(insn) and is_VReg(name_tmp) and !insn.mnemonic.include?('acc')
138%          ctor_args.push("#{name}?: #{type}")
139%       else
140%          ctor_args.push("#{name}: #{type}")
141%       end
142%     end
143%     return ops,ctor_args
144% end
145%
146% def get_operand_kind(op, insn)
147%   if op.reg?
148%     if op.src? and op.dst?
149%       return 2
150%     elsif op.src?
151%       return 0
152%     elsif op.dst?
153%       return 1
154%     end
155%     return nil
156%   elsif op.imm?
157%     is_jump = insn.properties.include? 'jump'
158%     return is_jump ? 6 : 3
159%  elsif op.id?
160%    is_string_id = insn.properties.include? 'string_id'
161%    return is_string_id ? 5 : 4
162%  else
163%    return nil
164%  end
165% end
166%
167% def make_format(fmt, insn)
168%   operands = fmt.operands.map {|op| "[#{get_operand_kind(op, insn)}, #{op.width}]"}
169%   return "[" + operands.join(", ") + "]"
170% end
171%
172// Autogenerated file -- DO NOT EDIT!
173import * as ts from "typescript";
174import {
175  DebugPosInfo,
176  NodeKind
177} from "./debuginfo";
178import { Scope } from "./scope";
179
180export enum IRNodeKind {
181% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
182  <%= get_node_kind(mnemonic) %>,
183% end
184  VREG,
185  IMM,
186  LABEL,
187  VIRTUALSTARTINS_DYN,
188  VIRTUALENDINS_DYN,
189  DEFINE_GLOBAL_VAR,
190}
191
192export function getInstructionSize(opcode: IRNodeKind) {
193  switch(opcode) {
194% Panda::instructions.each do |insn|
195% node_kind = get_node_kind(insn.mnemonic)
196% kind = "IRNodeKind." + node_kind
197    case <%= kind %>:
198      return <%= insn.format.size %>;
199% end
200    default:
201      // LOGE("getInstructionSize: Unknown opcode:" + opcode);
202      return 0;
203  }
204}
205
206export enum ResultType {
207  None,
208  Unknown,
209  Int,
210  Long,
211  Float,
212  Obj,
213  Boolean
214}
215
216export enum ResultDst {
217  None,
218  Acc,
219  VReg
220}
221
222export enum BuiltIns {
223  NaN,
224  Infinity,
225  globalThis,
226  undefined,
227  Boolean,
228  Number,
229  String,
230  BigInt,
231  Symbol,
232  Null,
233  Object,
234  Function,
235  Global,
236  True,
237  False,
238  LexEnv,
239  MAX_BUILTIN,
240}
241
242export type OperandType = VReg | Imm | Label | string | number
243
244export enum OperandKind {
245  // the least significant bit indicates vreg
246  // the second bit indicates src or dst
247  SrcVReg = 0, DstVReg, SrcDstVReg, Imm, Id, StringId, Label
248}
249
250export namespace OperandKind {
251  // @ts-ignore
252  function isVReg(kind: OperandKind): boolean {
253    return kind === OperandKind.SrcVReg || kind === OperandKind.DstVReg || kind === OperandKind.SrcDstVReg;
254  }
255}
256
257export type Format = number[][]
258
259export function getInsnMnemonic(opcode: IRNodeKind): string {
260  switch(opcode) {
261% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
262% node_kind = get_node_kind(mnemonic)
263% kind = "IRNodeKind." + node_kind
264    case <%= kind %>:
265      return "<%= mnemonic %>";
266% end
267    default:
268      return '';
269  }
270}
271
272export function getInsnFormats(opcode: IRNodeKind) {
273  switch(opcode) {
274% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
275% insn = group.first
276% formats = group.map {|i| make_format(i,insn) }
277% node_kind = get_node_kind(mnemonic)
278% kind = "IRNodeKind." + node_kind
279    case <%= kind %>: {
280      return [
281        <%= formats.join(",\n        ") %>
282      ];
283    }
284% end
285    default:
286      return [];
287  }
288}
289
290export abstract class IRNode {
291  private node: ts.Node | NodeKind = NodeKind.NORMAL;
292  public static pg: PandaGen | undefined = undefined;
293  constructor(
294    readonly kind: IRNodeKind,
295    readonly operands: OperandType[],
296  ) {}
297  // for debuginfo
298  public debugPosInfo: DebugPosInfo = new DebugPosInfo();
299
300  toString(): string {
301    let mnemonic = this.getMnemonic();
302    let out = mnemonic + "\t";
303    if (mnemonic.length < 8) {
304      out += "\t";
305    }
306
307    this.operands.forEach((element) => {
308      out = out + element.toString() + ", ";
309    });
310
311    return out;
312  }
313
314  setNode(node: ts.Node | NodeKind) {
315    this.node = node;
316  }
317
318  getNodeName() {
319    if (this.node != NodeKind.INVALID &&
320        this.node != NodeKind.FIRST_NODE_OF_FUNCTION &&
321        this.node != NodeKind.NORMAL) {
322      return ts.SyntaxKind[(<ts.Node>this.node).kind];
323    }
324
325    return "undefined";
326  }
327
328  getMnemonic() {
329    return getInsnMnemonic(this.kind);
330  }
331
332  getFormats() {
333    return getInsnFormats(this.kind);
334  }
335
336  static setPandagen(pg: PandaGen) {
337    IRNode.pg = pg;
338  }
339}
340
341export class VReg {
342  private typeIndex: number | undefined;
343  private variableName: string | undefined;
344  num: number = -1;
345
346  toString(): string {
347      return "V" + this.num;
348  }
349
350  constructor() {
351  }
352
353  getTypeIndex() {
354    return this.typeIndex;
355  }
356
357  setTypeIndex(typeIndex: number) {
358    this.typeIndex = typeIndex;
359  }
360
361  getVariableName() {
362    return this.variableName;
363  }
364
365  setVariableName(variableName: string) {
366    this.variableName = variableName;
367  }
368}
369
370export class Imm extends IRNode {
371  readonly value: number;
372
373  constructor(value: number) {
374    super(IRNodeKind.IMM, []);
375    this.value = value;
376  }
377
378  toString(): string {
379    return "#" + this.value;
380  }
381}
382
383export class Label extends IRNode {
384  private static global_id = 0;
385  readonly id: number;
386
387  constructor() {
388    super(IRNodeKind.LABEL, []);
389    this.id = Label.global_id++;
390  }
391
392  static resetGlobalId() {
393    Label.global_id = 0;
394  }
395
396  toString(): string {
397    return "LABEL_" + this.id;
398  }
399}
400
401export class DebugInsStartPlaceHolder extends IRNode {
402  private scope: Scope;
403
404  constructor(scope: Scope) {
405    super(IRNodeKind.VIRTUALSTARTINS_DYN, []);
406    this.scope = scope;
407  }
408
409  getScope() {
410    return this.scope;
411  }
412}
413
414export class DebugInsEndPlaceHolder extends IRNode {
415  private scope: Scope;
416
417  constructor(scope: Scope) {
418    super(IRNodeKind.VIRTUALENDINS_DYN, []);
419    this.scope = scope;
420  }
421
422  getScope() {
423    return this.scope;
424  }
425}
426
427% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
428% insn = group.first
429% jump = insn.properties.include? 'jump'
430% node_kind = get_node_kind(mnemonic)
431% kind = "IRNodeKind." + node_kind
432% ops_list,ctor_arg_list = get_ctor_args(insn)
433% ctor_args = ctor_arg_list.map {|arg| "#{arg}"}.join(", ")
434% ops = ops_list.map { |op| "#{op}"}.join(", ")
435% result_type = get_result_type(insn)
436% result_dst = get_result_dst(insn);
437% is_call_op = is_Call(insn)
438% is_callrange_op = is_CallRange(insn)
439% parent_type = "IRNode"
440export class <%= insn2node(insn) %> extends <%= parent_type %> {
441% if is_callrange_op
442%   op_last = ops_list.pop
443%   ops_length = ops_list.size
444  constructor(<%= ctor_arg_list.join(", ")%>[]) {
445    var ctors = [<%=ops_list.join(", ")%>, ...<%=op_last %>]
446    var operands:OperandType[] = [<%=ops_list.join(", ")%>]
447%   for i in 1..ops_length do
448    ctors.shift()
449%   end
450    while (!!(ctors && ctors.length)){
451      let ctor = ctors.shift()
452      if (ctor != undefined) {
453        operands.push(ctor)
454      }
455    }
456% else
457  constructor(<%= ctor_args %>) {
458% if is_call_op and ops.length() != 0
459    var ctors = [<%= ops %>]
460    var operands:OperandType[] = [<%=ops_list[0] %>]
461    ctors.shift()
462    while (!!(ctors && ctors.length)){
463      let ctor = ctors.shift()
464      if (ctor != undefined) {
465        operands.push(ctor)
466      }
467    }
468% end
469% end
470    super(
471      <%= kind %>,
472% if is_call_op or is_callrange_op
473      operands,
474% else
475      [<%= ops %>]
476% end
477    );
478% is_jit_ic = insn.properties.include?("jit_ic_slot")
479% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
480% if (is_ic)
481%   ret = insn.properties.include?("one_slot") ? 1 : 2;
482    let invalid = 255;
483    let icSize = (<PandaGen>(IRNode.pg)).getIcSize();
484    if (icSize <= invalid) {
485        if ((icSize + <%= ret %>) > 255)  {
486            this.operands[0] = new Imm(256);
487            let inc = <%= ret %> + 256 - icSize;
488            (<PandaGen>(IRNode.pg)).updateIcSize(inc);
489        } else {
490            this.operands[0] = new Imm(icSize);
491            (<PandaGen>(IRNode.pg)).updateIcSize(<%= ret %>);
492        }
493    } else if(icSize > invalid && icSize <= 65535) {
494        this.operands[0] = new Imm(icSize);
495        (<PandaGen>(IRNode.pg)).updateIcSize(<%= ret %>);
496    } else {
497        this.operands[0] = new Imm(invalid);
498    }
499% end
500% if (is_jit_ic && !is_ic)
501%   ret = insn.properties.include?("one_slot") ? 1 : 2;
502    let invalid = 255;
503    let icSize = (<PandaGen>(IRNode.pg)).getIcSize();
504    if (icSize < invalid) {
505        if ((icSize + <%= ret %>) > invalid) {
506            this.operands[0] = new Imm(invalid);
507            (<PandaGen>(IRNode.pg)).updateIcSize((256 - icSize));
508        } else {
509            this.operands[0] = new Imm(icSize);
510            (<PandaGen>(IRNode.pg)).updateIcSize(<%= ret %>);
511        }
512    } else {
513        this.operands[0] = new Imm(invalid);
514    }
515% end
516  }
517% if jump
518% target_index = insn.operands.index {|op| op.imm? }
519
520  getTarget(): Label {
521    return <Label> this.operands[<%= target_index %>];
522  }
523% end
524}
525
526% end
527