1#!/usr/bin/env ruby 2 3# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16require 'optparse' 17require 'ostruct' 18require 'yaml' 19 20Options = OpenStruct.new 21class << Options 22 23 attr_accessor :compiling 24 25 def parse 26 OptionParser.new do |opts| 27 opts.banner = "Usage: irtoc.rb [options] INPUT_FILE" 28 29 opts.on("--ark_source_dir=PATH", "Path to panda source code") { |v| self.ark_source_dir = v } 30 opts.on("--output=PATH", "Output file") { |v| self.output_file = v } 31 opts.on("--input=PATH", "Input files, separated by ':' symbol") { |v| self.input_files = v.split(':') } 32 opts.on("--definitions=LIST", "C++ definitions that will be used for compiling output file") { |v| self.definitions = v } 33 opts.on("--arch=ARCH", "Target architecture") { |v| self.arch = v } 34 opts.on('--ir-api=API', 'API to emit during C++ code generation') { |v| self.ir_api = v } 35 opts.on('--isa=PATH', 'ISA YAML file') { |v| self.isa = v } 36 opts.on('--plugins=PATH', 'Plugins file') { |v| self.plugins = v } 37 opts.on('--keep-artifacts', 'Do not remove intermediate files') { |v| self.keep_artifacts = true } 38 end.parse! 39 40 self.instructions_yaml = "#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml" 41 self.isapi = "#{self.ark_source_dir}/isa/isapi.rb" 42 self.commonapi = "#{self.ark_source_dir}/templates/common.rb" 43 44 # Collect compiler definitions 45 if self.definitions 46 defines = self.definitions.split(':') 47 new_definitions = OpenStruct.new 48 defines.each do |define| 49 vals = define.split('=') 50 new_definitions[vals[0]] = vals.size > 1 ? vals[1] : true 51 end 52 self.definitions = new_definitions 53 else 54 self.definitions = OpenStruct.new 55 end 56 self.definitions.DEBUG = !self.definitions.NDEBUG 57 58 # Collect plugins files 59 if self.plugins 60 new_plugins = Hash.new { |h, k| h[k] = [] } 61 File.open(self.plugins).readlines.each do |plugin| 62 next if plugin.strip.empty? 63 full_plugin_path = "#{self.ark_source_dir}/#{plugin}".chop 64 line_matches = File.open(full_plugin_path).to_a.first.match(/# +plugin +(.*)/) 65 raise "Irtoc plugin doesn't specifiy its name: #{full_plugin_path}" unless line_matches 66 plugin_name = line_matches[1] 67 new_plugins[plugin_name] << full_plugin_path 68 end 69 self.plugins = new_plugins 70 else 71 self.plugins = Hash.new { |h, k| h[k] = [] } 72 end 73 74 # Determine target architecture 75 if self.arch.nil? 76 arch_str = self.definitions.marshal_dump.keys.grep(/PANDA_TARGET_(AMD64|ARM64|ARM32)/)[0] 77 self.arch = arch_str.to_s.sub('PANDA_TARGET_','').downcase 78 end 79 self.arch = self.arch.to_sym 80 if self.arch == :amd64 || self.arch == :x64 81 self.arch = :x86_64 82 end 83 if self.arch == :arm 84 self.arch = :arm32 85 end 86 possible_arch = %w[arm64 arm32 x86_64 x86] 87 raise "Wrong arch: #{arch_str}" unless possible_arch.include?(self.arch.to_s) 88 89 # Read compiler arch info 90 arch_info = YAML.load_file("#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml")['arch_info'] 91 raise "Compiler config doesn't contain `arch_info`" unless arch_info 92 arch_info = arch_info[arch_info.index { |x| x['name'].to_sym == self.arch }] 93 raise "Arch info not found for #{self.arch}" unless arch_info 94 self.arch_info = OpenStruct.new(arch_info) 95 96 raise 'Supported IR APIs: ir-constructor, ir-builder, ir-inline' unless self.ir_api =~ /^ir-(constructor|builder|inline)$/ 97 end 98 99 def arch_64_bits? 100 self.arch == :x86_64 || self.arch == :arm64 101 end 102 103 def arm64? 104 self.arch == :arm64 105 end 106 107 def cpp_arch 108 @cpp_arch_map ||= { 109 arm32: "Arch::AARCH32", 110 arm64: "Arch::AARCH64", 111 x86_64: "Arch::X86_64" 112 } 113 @cpp_arch_map[self.arch] 114 end 115 116end 117