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