1#!/usr/bin/env ruby 2 3# Copyright (c) 2021-2024 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_files = v.split(':') } 31 opts.on("--input=PATH", "Input files, separated by ':' symbol") { |v| self.input_files = v.split(':') } 32 opts.on('-D=STR', '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('--working-dir=PATH', 'Run in specified working directory') { |v| self.working_dir = v } 38 end.parse! 39 40 if Options.working_dir 41 Dir.mkdir(Options.working_dir) unless File.exists?(Options.working_dir) 42 Dir.chdir(Options.working_dir) 43 end 44 45 self.instructions_yaml = "#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml" 46 self.isapi = "#{self.ark_source_dir}/isa/isapi.rb" 47 self.commonapi = "#{self.ark_source_dir}/templates/common.rb" 48 49 # Collect compiler definitions 50 if self.definitions 51 new_definitions = OpenStruct.new 52 self.definitions.each do |define| 53 vals = define.split('=') 54 new_definitions[vals[0]] = vals.size > 1 ? vals[1] : true 55 end 56 self.definitions = new_definitions 57 else 58 self.definitions = OpenStruct.new 59 end 60 self.definitions.DEBUG = !self.definitions.NDEBUG 61 62 # Collect plugins files 63 if self.plugins 64 new_plugins = Hash.new { |h, k| h[k] = [] } 65 File.open(self.plugins).readlines.each do |plugin| 66 next if plugin.strip.empty? 67 full_plugin_path = "#{self.ark_source_dir}/#{plugin}".chop 68 line_matches = File.open(full_plugin_path).to_a.first.match(/# +plugin +(.*)/) 69 raise "Irtoc plugin doesn't specifiy its name: #{full_plugin_path}" unless line_matches 70 plugin_name = line_matches[1] 71 new_plugins[plugin_name] << full_plugin_path 72 end 73 self.plugins = new_plugins 74 else 75 self.plugins = Hash.new { |h, k| h[k] = [] } 76 end 77 78 # Determine target architecture 79 if self.arch.nil? 80 arch_str = self.definitions.marshal_dump.keys.grep(/PANDA_TARGET_(AMD64|ARM64|ARM32)/)[0] 81 self.arch = arch_str.to_s.sub('PANDA_TARGET_','').downcase 82 end 83 self.arch = self.arch.to_sym 84 if self.arch == :amd64 || self.arch == :x64 85 self.arch = :x86_64 86 end 87 if self.arch == :arm 88 self.arch = :arm32 89 end 90 possible_arch = %w[arm64 arm32 x86_64 x86] 91 raise "Wrong arch: #{arch_str}" unless possible_arch.include?(self.arch.to_s) 92 93 # Read compiler arch info 94 arch_info = YAML.load_file("#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml")['arch_info'] 95 raise "Compiler config doesn't contain `arch_info`" unless arch_info 96 arch_info = arch_info[arch_info.index { |x| x['name'].to_sym == self.arch }] 97 raise "Arch info not found for #{self.arch}" unless arch_info 98 self.arch_info = OpenStruct.new(arch_info) 99 100 raise 'Supported IR APIs: ir-constructor, ir-builder, ir-inline' unless self.ir_api =~ /^ir-(constructor|builder|inline)$/ 101 end 102 103 def arch_64_bits? 104 self.arch == :x86_64 || self.arch == :arm64 105 end 106 107 def arm64? 108 self.arch == :arm64 109 end 110 111 def cpp_arch 112 @cpp_arch_map ||= { 113 arm32: "Arch::AARCH32", 114 arm64: "Arch::AARCH64", 115 x86_64: "Arch::X86_64" 116 } 117 @cpp_arch_map[self.arch] 118 end 119 120end 121