• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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('--cpu-features=FEATURE,FEATURE', 'Supported CPU Features') { |v| self.cpu_features = v.split(',').map { |f| f.to_sym }}
35      opts.on('--ir-api=API', 'API to emit during C++ code generation') { |v| self.ir_api = v }
36      opts.on('--isa=PATH', 'ISA YAML file') { |v| self.isa = v }
37      opts.on('--plugins=PATH', 'Plugins file') { |v| self.plugins = v }
38      opts.on('--working-dir=PATH', 'Run in specified working directory') { |v| self.working_dir = v }
39    end.parse!
40
41    if Options.working_dir
42      Dir.mkdir(Options.working_dir) unless File.exists?(Options.working_dir)
43      Dir.chdir(Options.working_dir)
44    end
45
46    self.instructions_yaml = "#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml"
47    self.isapi = "#{self.ark_source_dir}/isa/isapi.rb"
48    self.commonapi = "#{self.ark_source_dir}/templates/common.rb"
49
50    # Collect compiler definitions
51    if self.definitions
52      new_definitions = OpenStruct.new
53      self.definitions.each do |define|
54        vals = define.split('=')
55        new_definitions[vals[0]] = vals.size > 1 ? vals[1] : true
56      end
57      self.definitions = new_definitions
58    else
59      self.definitions = OpenStruct.new
60    end
61    self.definitions.DEBUG = !self.definitions.NDEBUG
62
63    # Collect plugins files
64    if self.plugins
65      new_plugins = Hash.new { |h, k| h[k] = [] }
66      File.open(self.plugins).readlines.each do |plugin|
67        next if plugin.strip.empty?
68        full_plugin_path = "#{self.ark_source_dir}/#{plugin}".chop
69        line_matches = File.open(full_plugin_path).to_a.first.match(/# +plugin +(.*)/)
70        raise "Irtoc plugin doesn't specifiy its name: #{full_plugin_path}" unless line_matches
71        plugin_name = line_matches[1]
72        new_plugins[plugin_name] << full_plugin_path
73      end
74      self.plugins = new_plugins
75    else
76      self.plugins = Hash.new { |h, k| h[k] = [] }
77    end
78
79    # Determine target architecture
80    if self.arch.nil?
81      arch_str = self.definitions.marshal_dump.keys.grep(/PANDA_TARGET_(AMD64|ARM64|ARM32)/)[0]
82      self.arch = arch_str.to_s.sub('PANDA_TARGET_','').downcase
83    end
84    self.arch = self.arch.to_sym
85    if self.arch == :amd64 || self.arch == :x64
86      self.arch = :x86_64
87    end
88    if self.arch == :arm
89      self.arch = :arm32
90    end
91    possible_arch = %w[arm64 arm32 x86_64 x86]
92    raise "Wrong arch: #{arch_str}" unless possible_arch.include?(self.arch.to_s)
93
94    # Read compiler arch info
95    arch_info = YAML.load_file("#{self.ark_source_dir}/compiler/optimizer/ir/instructions.yaml")['arch_info']
96    raise "Compiler config doesn't contain `arch_info`" unless arch_info
97    arch_info = arch_info[arch_info.index { |x| x['name'].to_sym == self.arch }]
98    raise "Arch info not found for #{self.arch}" unless arch_info
99    self.arch_info = OpenStruct.new(arch_info)
100
101    # Determine CPU features. Notice: default-enabled CPU features ('sse42') must be reflected here.
102    # See the 'compiler/compiler.yaml' file.
103    if self.cpu_features.nil?
104      self.cpu_features = [:sse42]
105    end
106    possible_features = %w[none crc32 sse42 jscvt atomics]
107    self.cpu_features.each do |feature|
108      raise "Wrong cpu feature: #{feature}" unless possible_features.include?(feature.to_s)
109    end
110
111    raise 'Supported IR APIs: ir-constructor, ir-builder, ir-inline' unless self.ir_api =~ /^ir-(constructor|builder|inline)$/
112  end
113
114  def arch_64_bits?
115    self.arch == :x86_64 || self.arch == :arm64
116  end
117
118  def arm64?
119    self.arch == :arm64
120  end
121
122  def cpp_arch
123    @cpp_arch_map ||= {
124      arm32: "Arch::AARCH32",
125      arm64: "Arch::AARCH64",
126      x86_64: "Arch::X86_64"
127    }
128    @cpp_arch_map[self.arch]
129  end
130
131  def crc32_feature_enabled?
132    self.cpu_features.include?(:crc32)
133  end
134
135  def sse42_feature_enabled?
136    self.cpu_features.include?(:sse42)
137  end
138
139  def jscvt_feature_enabled?
140    self.cpu_features.include?(:jscvt)
141  end
142
143  def atomics_feature_enabled?
144    self.cpu_features.include?(:atomics)
145  end
146
147end
148