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