1b1994897Sopenharmony_ci# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
2b1994897Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
3b1994897Sopenharmony_ci# you may not use this file except in compliance with the License.
4b1994897Sopenharmony_ci# You may obtain a copy of the License at
5b1994897Sopenharmony_ci#
6b1994897Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
7b1994897Sopenharmony_ci#
8b1994897Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
9b1994897Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
10b1994897Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11b1994897Sopenharmony_ci# See the License for the specific language governing permissions and
12b1994897Sopenharmony_ci# limitations under the License.
13b1994897Sopenharmony_ci
14b1994897Sopenharmony_cirequire 'ostruct'
15b1994897Sopenharmony_cirequire_relative 'codegen_arm64'
16b1994897Sopenharmony_cirequire 'delegate'
17b1994897Sopenharmony_ci
18b1994897Sopenharmony_cimodule Tokens
19b1994897Sopenharmony_ci  module_function
20b1994897Sopenharmony_ci
21b1994897Sopenharmony_ci  module Types
22b1994897Sopenharmony_ci    INT8 = 'i8'
23b1994897Sopenharmony_ci    INT16 = 'i16'
24b1994897Sopenharmony_ci    INT32 = 'i32'
25b1994897Sopenharmony_ci    INT64 = 'i64'
26b1994897Sopenharmony_ci    UINT8 = 'u8'
27b1994897Sopenharmony_ci    UINT16 = 'u16'
28b1994897Sopenharmony_ci    UINT32 = 'u32'
29b1994897Sopenharmony_ci    UINT64 = 'u64'
30b1994897Sopenharmony_ci    FLOAT32 = 'f32'
31b1994897Sopenharmony_ci    FLOAT64 = 'f64'
32b1994897Sopenharmony_ci    BOOL = 'bool'
33b1994897Sopenharmony_ci    REF = 'ref'
34b1994897Sopenharmony_ci    PTR = 'ptr'
35b1994897Sopenharmony_ci    VOID = 'void'
36b1994897Sopenharmony_ci    IMM = 'imm'
37b1994897Sopenharmony_ci    INTEGER = 'int'
38b1994897Sopenharmony_ci    FLOAT = 'float'
39b1994897Sopenharmony_ci    NUMBER = 'number'
40b1994897Sopenharmony_ci    REAL = 'real'
41b1994897Sopenharmony_ci    ANY = 'any'
42b1994897Sopenharmony_ci    ACC = 'acc'
43b1994897Sopenharmony_ci    STRING = 'string_id'
44b1994897Sopenharmony_ci    METHOD = 'method_id'
45b1994897Sopenharmony_ci    SAVE_STATE = 'save_state'
46b1994897Sopenharmony_ci  end
47b1994897Sopenharmony_ci
48b1994897Sopenharmony_ci  module Other
49b1994897Sopenharmony_ci    DST = 'd'
50b1994897Sopenharmony_ci    DYNAMIC = 'dyn'
51b1994897Sopenharmony_ci    PSEUDO = 'pseudo'
52b1994897Sopenharmony_ci    NULL_CHECK = 'nc'
53b1994897Sopenharmony_ci    ZERO_CHECK = 'zc'
54b1994897Sopenharmony_ci    NEGATIVE_CHECK = 'ngc'
55b1994897Sopenharmony_ci    BOUNDS_CHECK = 'bc'
56b1994897Sopenharmony_ci  end
57b1994897Sopenharmony_ci
58b1994897Sopenharmony_ciend
59b1994897Sopenharmony_ci
60b1994897Sopenharmony_ciclass Operand
61b1994897Sopenharmony_ci  attr_accessor :tokens, :types
62b1994897Sopenharmony_ci
63b1994897Sopenharmony_ci  TYPE_ALIASES = {
64b1994897Sopenharmony_ci    # We add `bool` type into the `int`, because IR uses same constant instructions for bool and integer types, i.e.
65b1994897Sopenharmony_ci    # same constant instruction can be definition for bool and integer instructions simultaneously.
66b1994897Sopenharmony_ci    "int"    => %w[bool i8 i16 i32 i64 u8 u16 u32 u64],
67b1994897Sopenharmony_ci    "float"  => %w[f32 f64],
68b1994897Sopenharmony_ci    "number" => %w[bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64],
69b1994897Sopenharmony_ci    "real"   => %w[bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 ref ptr]
70b1994897Sopenharmony_ci  }
71b1994897Sopenharmony_ci
72b1994897Sopenharmony_ci  CPP_IR_TYPES = {
73b1994897Sopenharmony_ci    Tokens::Types::INT8 => "DataType::INT8",
74b1994897Sopenharmony_ci    Tokens::Types::INT16 => "DataType::INT16",
75b1994897Sopenharmony_ci    Tokens::Types::INT32 => "DataType::INT32",
76b1994897Sopenharmony_ci    Tokens::Types::INT64 => "DataType::INT64",
77b1994897Sopenharmony_ci    Tokens::Types::UINT8 => "DataType::UINT8",
78b1994897Sopenharmony_ci    Tokens::Types::UINT16 => "DataType::UINT16",
79b1994897Sopenharmony_ci    Tokens::Types::UINT32 => "DataType::UINT32",
80b1994897Sopenharmony_ci    Tokens::Types::UINT64 => "DataType::UINT64",
81b1994897Sopenharmony_ci    Tokens::Types::BOOL => "DataType::BOOL",
82b1994897Sopenharmony_ci    Tokens::Types::FLOAT32 => "DataType::FLOAT32",
83b1994897Sopenharmony_ci    Tokens::Types::FLOAT64 => "DataType::FLOAT64",
84b1994897Sopenharmony_ci    Tokens::Types::REF => "DataType::REFERENCE",
85b1994897Sopenharmony_ci    Tokens::Types::PTR => "DataType::POINTER",
86b1994897Sopenharmony_ci    Tokens::Types::VOID => "DataType::VOID",
87b1994897Sopenharmony_ci    Tokens::Types::ANY => "DataType::ANY"
88b1994897Sopenharmony_ci  }
89b1994897Sopenharmony_ci
90b1994897Sopenharmony_ci  def initialize(descr)
91b1994897Sopenharmony_ci    @tokens = descr.split('-')
92b1994897Sopenharmony_ci    @types = []
93b1994897Sopenharmony_ci    @aux_types = []
94b1994897Sopenharmony_ci    @tokens.each do |token|
95b1994897Sopenharmony_ci      if IR::types.include?(token)
96b1994897Sopenharmony_ci        @types << token
97b1994897Sopenharmony_ci        next
98b1994897Sopenharmony_ci      end
99b1994897Sopenharmony_ci      resolved = TYPE_ALIASES[token]
100b1994897Sopenharmony_ci      if resolved
101b1994897Sopenharmony_ci        @types += resolved
102b1994897Sopenharmony_ci        next
103b1994897Sopenharmony_ci      end
104b1994897Sopenharmony_ci      @aux_types << token
105b1994897Sopenharmony_ci    end
106b1994897Sopenharmony_ci  end
107b1994897Sopenharmony_ci
108b1994897Sopenharmony_ci  def has(type)
109b1994897Sopenharmony_ci    @tokens.include? type
110b1994897Sopenharmony_ci  end
111b1994897Sopenharmony_ci
112b1994897Sopenharmony_ci  def types_string
113b1994897Sopenharmony_ci    @tokens.join(', ') + (@tokens.include?(Tokens::Other::DYNAMIC) ? ", ..." : "")
114b1994897Sopenharmony_ci  end
115b1994897Sopenharmony_ci
116b1994897Sopenharmony_ci  def is_dst?
117b1994897Sopenharmony_ci    has(Tokens::Other::DST)
118b1994897Sopenharmony_ci  end
119b1994897Sopenharmony_ci
120b1994897Sopenharmony_ci  def is_dyn?
121b1994897Sopenharmony_ci    has(Tokens::Other::DYNAMIC)
122b1994897Sopenharmony_ci  end
123b1994897Sopenharmony_ci
124b1994897Sopenharmony_ci  def pseudo?
125b1994897Sopenharmony_ci    has(Tokens::Other::PSEUDO)
126b1994897Sopenharmony_ci  end
127b1994897Sopenharmony_ci
128b1994897Sopenharmony_ci  def self.cpp_type(t)
129b1994897Sopenharmony_ci    raise "No cpp token for type #{t}" unless CPP_IR_TYPES.include?(t.to_s)
130b1994897Sopenharmony_ci    CPP_IR_TYPES[t]
131b1994897Sopenharmony_ci  end
132b1994897Sopenharmony_ciend
133b1994897Sopenharmony_ci
134b1994897Sopenharmony_ciclass Instruction < SimpleDelegator
135b1994897Sopenharmony_ci  attr_reader :operands, :inputs
136b1994897Sopenharmony_ci
137b1994897Sopenharmony_ci  def initialize(data)
138b1994897Sopenharmony_ci    data.modes ||= IR::modes.each_pair.map { |key, value| key.to_s }
139b1994897Sopenharmony_ci    super(data)
140b1994897Sopenharmony_ci    @operands = signature.map { |sgn| Operand.new(sgn) }
141b1994897Sopenharmony_ci    if @operands.empty?
142b1994897Sopenharmony_ci      @inputs = []
143b1994897Sopenharmony_ci    else
144b1994897Sopenharmony_ci      @inputs = @operands.drop(@operands.first.is_dst? ? 1 : 0)
145b1994897Sopenharmony_ci    end
146b1994897Sopenharmony_ci    raise "Destination can be only first operand" if inputs.any? { |x| x.is_dst? }
147b1994897Sopenharmony_ci  end
148b1994897Sopenharmony_ci
149b1994897Sopenharmony_ci  def has_dst?
150b1994897Sopenharmony_ci    !operands.empty? && operands.first.is_dst?
151b1994897Sopenharmony_ci  end
152b1994897Sopenharmony_ci
153b1994897Sopenharmony_ci  def dst
154b1994897Sopenharmony_ci    @operands.first
155b1994897Sopenharmony_ci  end
156b1994897Sopenharmony_ci
157b1994897Sopenharmony_ci  def has_inputs?
158b1994897Sopenharmony_ci    !inputs.empty?
159b1994897Sopenharmony_ci  end
160b1994897Sopenharmony_ci
161b1994897Sopenharmony_ci  def is_call?
162b1994897Sopenharmony_ci    flags.include?("call")
163b1994897Sopenharmony_ci  end
164b1994897Sopenharmony_ci
165b1994897Sopenharmony_ci  def resolve_item(item)
166b1994897Sopenharmony_ci    if item.is_a? Array
167b1994897Sopenharmony_ci      return item.map { |v| (v.start_with? '$') ? IR::templates[v[1..-1]] : v }
168b1994897Sopenharmony_ci    elsif item.is_a? Hash
169b1994897Sopenharmony_ci      return item.map { |k, v| (v.start_with? '$') ? [k, IR::templates[v[1..-1]]] : [k, v] }
170b1994897Sopenharmony_ci    else
171b1994897Sopenharmony_ci      return item
172b1994897Sopenharmony_ci    end
173b1994897Sopenharmony_ci  end
174b1994897Sopenharmony_ci
175b1994897Sopenharmony_ci  def resolve
176b1994897Sopenharmony_ci    self['verification'] = resolve_item(verification) if respond_to? 'verification'
177b1994897Sopenharmony_ci    self
178b1994897Sopenharmony_ci  end
179b1994897Sopenharmony_ciend
180b1994897Sopenharmony_ci
181b1994897Sopenharmony_cimodule IR
182b1994897Sopenharmony_ci  module_function
183b1994897Sopenharmony_ci
184b1994897Sopenharmony_ci  def instructions
185b1994897Sopenharmony_ci    @instructions ||= @data['instructions'].map do |inst_dscr|
186b1994897Sopenharmony_ci      Instruction.new(OpenStruct.new(inst_dscr)).resolve
187b1994897Sopenharmony_ci    end
188b1994897Sopenharmony_ci  end
189b1994897Sopenharmony_ci
190b1994897Sopenharmony_ci  def flags
191b1994897Sopenharmony_ci    @data['flags']
192b1994897Sopenharmony_ci  end
193b1994897Sopenharmony_ci
194b1994897Sopenharmony_ci  def modes
195b1994897Sopenharmony_ci    @data['modes']
196b1994897Sopenharmony_ci  end
197b1994897Sopenharmony_ci
198b1994897Sopenharmony_ci  def templates
199b1994897Sopenharmony_ci    @data['templates']
200b1994897Sopenharmony_ci  end
201b1994897Sopenharmony_ci
202b1994897Sopenharmony_ci  def arch_info
203b1994897Sopenharmony_ci    @data['arch_info']
204b1994897Sopenharmony_ci  end
205b1994897Sopenharmony_ci
206b1994897Sopenharmony_ci  def legend
207b1994897Sopenharmony_ci    @data['legend']
208b1994897Sopenharmony_ci  end
209b1994897Sopenharmony_ci
210b1994897Sopenharmony_ci  def wrap_data(data)
211b1994897Sopenharmony_ci    @data = data
212b1994897Sopenharmony_ci  end
213b1994897Sopenharmony_ci
214b1994897Sopenharmony_ci  def types
215b1994897Sopenharmony_ci    @types ||= @data['types'].map { |x| x.name }
216b1994897Sopenharmony_ci  end
217b1994897Sopenharmony_ci
218b1994897Sopenharmony_ci  def codegen
219b1994897Sopenharmony_ci    @@cg ||= Codegen.new
220b1994897Sopenharmony_ci  end
221b1994897Sopenharmony_ci
222b1994897Sopenharmony_ci  def get_ir_type(type)
223b1994897Sopenharmony_ci    @type_map ||= {
224b1994897Sopenharmony_ci      'i8' => 'DataType::INT8',
225b1994897Sopenharmony_ci      'i16' => 'DataType::INT16',
226b1994897Sopenharmony_ci      'i32' => 'DataType::INT32',
227b1994897Sopenharmony_ci      'i64' => 'DataType::INT64',
228b1994897Sopenharmony_ci      'u8' => 'DataType::UINT8',
229b1994897Sopenharmony_ci      'u16' => 'DataType::UINT16',
230b1994897Sopenharmony_ci      'u32' => 'DataType::UINT32',
231b1994897Sopenharmony_ci      'u64' => 'DataType::UINT64',
232b1994897Sopenharmony_ci      'f32' => 'DataType::FLOAT32',
233b1994897Sopenharmony_ci      'f64' => 'DataType::FLOAT64',
234b1994897Sopenharmony_ci      'obj' => 'DataType::REFERENCE',
235b1994897Sopenharmony_ci      'any' => 'DataType::ANY',
236b1994897Sopenharmony_ci      'acc' => 'DataType::ACC',
237b1994897Sopenharmony_ci      'string_id' => 'DataType::UINT32',
238b1994897Sopenharmony_ci      'method_id' => 'DataType::UINT32',
239b1994897Sopenharmony_ci      'none' => 'DataType::NO_TYPE'}
240b1994897Sopenharmony_ci    @type_map[type]
241b1994897Sopenharmony_ci  end
242b1994897Sopenharmony_ci
243b1994897Sopenharmony_ciend
244b1994897Sopenharmony_ci
245b1994897Sopenharmony_cidef Gen.on_require(data)
246b1994897Sopenharmony_ci  IR.wrap_data(data)
247b1994897Sopenharmony_ciend
248