github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_rocm.tpl (about) 1 #!/usr/bin/env python 2 """Crosstool wrapper for compiling ROCm programs. 3 4 SYNOPSIS: 5 crosstool_wrapper_driver_rocm [options passed in by cc_library() 6 or cc_binary() rule] 7 8 DESCRIPTION: 9 This script is expected to be called by the cc_library() or cc_binary() bazel 10 rules. When the option "-x rocm" is present in the list of arguments passed 11 to this script, it invokes the hipcc compiler. Most arguments are passed 12 as is as a string to --compiler-options of hipcc. When "-x rocm" is not 13 present, this wrapper invokes gcc with the input arguments as is. 14 """ 15 16 from __future__ import print_function 17 18 __author__ = 'whchung@gmail.com (Wen-Heng (Jack) Chung)' 19 20 from argparse import ArgumentParser 21 import os 22 import subprocess 23 import re 24 import sys 25 import pipes 26 27 # Template values set by rocm_configure.bzl. 28 CPU_COMPILER = ('%{cpu_compiler}') 29 GCC_HOST_COMPILER_PATH = ('%{gcc_host_compiler_path}') 30 31 HIPCC_PATH = '%{hipcc_path}' 32 PREFIX_DIR = os.path.dirname(GCC_HOST_COMPILER_PATH) 33 HIPCC_ENV = '%{hipcc_env}' 34 HIPCC_IS_HIPCLANG = '%{hipcc_is_hipclang}'=="True" 35 HIP_RUNTIME_PATH = '%{hip_runtime_path}' 36 HIP_RUNTIME_LIBRARY = '%{hip_runtime_library}' 37 HCC_RUNTIME_PATH = '%{hcc_runtime_path}' 38 HCC_RUNTIME_LIBRARY = '%{hcc_runtime_library}' 39 ROCR_RUNTIME_PATH = '%{rocr_runtime_path}' 40 ROCR_RUNTIME_LIBRARY = '%{rocr_runtime_library}' 41 VERBOSE = '%{crosstool_verbose}'=='1' 42 43 def Log(s): 44 print('gpus/crosstool: {0}'.format(s)) 45 46 47 def GetOptionValue(argv, option): 48 """Extract the list of values for option from the argv list. 49 50 Args: 51 argv: A list of strings, possibly the argv passed to main(). 52 option: The option whose value to extract, without the leading '-'. 53 54 Returns: 55 A list of values, either directly following the option, 56 (eg., -opt val1 val2) or values collected from multiple occurrences of 57 the option (eg., -opt val1 -opt val2). 58 """ 59 60 parser = ArgumentParser() 61 parser.add_argument('-' + option, nargs='*', action='append') 62 args, _ = parser.parse_known_args(argv) 63 if not args or not vars(args)[option]: 64 return [] 65 else: 66 return sum(vars(args)[option], []) 67 68 69 def GetHostCompilerOptions(argv): 70 """Collect the -isystem, -iquote, and --sysroot option values from argv. 71 72 Args: 73 argv: A list of strings, possibly the argv passed to main(). 74 75 Returns: 76 The string that can be used as the --compiler-options to hipcc. 77 """ 78 79 parser = ArgumentParser() 80 parser.add_argument('-isystem', nargs='*', action='append') 81 parser.add_argument('-iquote', nargs='*', action='append') 82 parser.add_argument('--sysroot', nargs=1) 83 parser.add_argument('-g', nargs='*', action='append') 84 parser.add_argument('-fno-canonical-system-headers', action='store_true') 85 86 args, _ = parser.parse_known_args(argv) 87 88 opts = '' 89 90 if args.isystem: 91 opts += ' -isystem ' + ' -isystem '.join(sum(args.isystem, [])) 92 if args.iquote: 93 opts += ' -iquote ' + ' -iquote '.join(sum(args.iquote, [])) 94 if args.g: 95 opts += ' -g' + ' -g'.join(sum(args.g, [])) 96 #if args.fno_canonical_system_headers: 97 # opts += ' -fno-canonical-system-headers' 98 if args.sysroot: 99 opts += ' --sysroot ' + args.sysroot[0] 100 101 return opts 102 103 def GetHipccOptions(argv): 104 """Collect the -hipcc_options values from argv. 105 106 Args: 107 argv: A list of strings, possibly the argv passed to main(). 108 109 Returns: 110 The string that can be passed directly to hipcc. 111 """ 112 113 parser = ArgumentParser() 114 parser.add_argument('-hipcc_options', nargs='*', action='append') 115 116 args, _ = parser.parse_known_args(argv) 117 118 if args.hipcc_options: 119 options = _update_options(sum(args.hipcc_options, [])) 120 return ' '.join(['--'+a for a in options]) 121 return '' 122 123 124 def InvokeHipcc(argv, log=False): 125 """Call hipcc with arguments assembled from argv. 126 127 Args: 128 argv: A list of strings, possibly the argv passed to main(). 129 log: True if logging is requested. 130 131 Returns: 132 The return value of calling os.system('hipcc ' + args) 133 """ 134 135 host_compiler_options = GetHostCompilerOptions(argv) 136 hipcc_compiler_options = GetHipccOptions(argv) 137 opt_option = GetOptionValue(argv, 'O') 138 m_options = GetOptionValue(argv, 'm') 139 m_options = ''.join([' -m' + m for m in m_options if m in ['32', '64']]) 140 include_options = GetOptionValue(argv, 'I') 141 out_file = GetOptionValue(argv, 'o') 142 depfiles = GetOptionValue(argv, 'MF') 143 defines = GetOptionValue(argv, 'D') 144 defines = ''.join([' -D' + define for define in defines]) 145 undefines = GetOptionValue(argv, 'U') 146 undefines = ''.join([' -U' + define for define in undefines]) 147 std_options = GetOptionValue(argv, 'std') 148 hipcc_allowed_std_options = ["c++11"] 149 std_options = ''.join([' -std=' + define 150 for define in std_options if define in hipcc_allowed_std_options]) 151 152 # The list of source files get passed after the -c option. I don't know of 153 # any other reliable way to just get the list of source files to be compiled. 154 src_files = GetOptionValue(argv, 'c') 155 156 if len(src_files) == 0: 157 return 1 158 if len(out_file) != 1: 159 return 1 160 161 opt = (' -O2' if (len(opt_option) > 0 and int(opt_option[0]) > 0) 162 else ' -g') 163 164 includes = (' -I ' + ' -I '.join(include_options) 165 if len(include_options) > 0 166 else '') 167 168 # Unfortunately, there are other options that have -c prefix too. 169 # So allowing only those look like C/C++ files. 170 src_files = [f for f in src_files if 171 re.search('\.cpp$|\.cc$|\.c$|\.cxx$|\.C$', f)] 172 srcs = ' '.join(src_files) 173 out = ' -o ' + out_file[0] 174 175 hipccopts = ' ' 176 hipccopts += ' ' + hipcc_compiler_options 177 # Use -fno-gpu-rdc by default for early GPU kernel finalization 178 # This flag would trigger GPU kernels be generated at compile time, instead 179 # of link time. This allows the default host compiler (gcc) be used as the 180 # linker for TensorFlow on ROCm platform. 181 hipccopts += ' -fno-gpu-rdc ' 182 hipccopts += undefines 183 hipccopts += defines 184 hipccopts += std_options 185 hipccopts += m_options 186 187 if depfiles: 188 # Generate the dependency file 189 depfile = depfiles[0] 190 cmd = (HIPCC_PATH + ' ' + hipccopts + 191 host_compiler_options + 192 ' ' + GCC_HOST_COMPILER_PATH + 193 ' -I .' + includes + ' ' + srcs + ' -M -o ' + depfile) 194 if log: Log(cmd) 195 exit_status = os.system(cmd) 196 if exit_status != 0: 197 return exit_status 198 199 cmd = (HIPCC_PATH + ' ' + hipccopts + 200 host_compiler_options + ' -fPIC' + 201 ' ' + GCC_HOST_COMPILER_PATH + 202 ' -I .' + opt + includes + ' -c ' + srcs + out) 203 204 # TODO(zhengxq): for some reason, 'gcc' needs this help to find 'as'. 205 # Need to investigate and fix. 206 cmd = 'PATH=' + PREFIX_DIR + ':$PATH '\ 207 + HIPCC_ENV.replace(';', ' ') + ' '\ 208 + cmd 209 if log: Log(cmd) 210 if VERBOSE: print(cmd) 211 return os.system(cmd) 212 213 214 def main(): 215 # ignore PWD env var 216 os.environ['PWD']='' 217 218 parser = ArgumentParser() 219 parser.add_argument('-x', nargs=1) 220 parser.add_argument('--rocm_log', action='store_true') 221 parser.add_argument('-pass-exit-codes', action='store_true') 222 args, leftover = parser.parse_known_args(sys.argv[1:]) 223 224 if VERBOSE: print('PWD=' + os.getcwd()) 225 if VERBOSE: print('HIPCC_ENV=' + HIPCC_ENV) 226 227 if args.x and args.x[0] == 'rocm': 228 # compilation for GPU objects 229 if args.rocm_log: Log('-x rocm') 230 leftover = [pipes.quote(s) for s in leftover] 231 if args.rocm_log: Log('using hipcc') 232 return InvokeHipcc(leftover, log=args.rocm_log) 233 234 elif args.pass_exit_codes: 235 # link 236 # with hipcc compiler invoked with -fno-gpu-rdc by default now, it's ok to 237 # use host compiler as linker, but we have to link with HCC/HIP runtime. 238 # Such restriction would be revised further as the bazel script get 239 # improved to fine tune dependencies to ROCm libraries. 240 gpu_linker_flags = [flag for flag in sys.argv[1:] 241 if not flag.startswith(('--rocm_log'))] 242 243 gpu_linker_flags.append('-L' + ROCR_RUNTIME_PATH) 244 gpu_linker_flags.append('-Wl,-rpath=' + ROCR_RUNTIME_PATH) 245 gpu_linker_flags.append('-l' + ROCR_RUNTIME_LIBRARY) 246 # do not link with HCC runtime library in case hip-clang toolchain is used 247 if not HIPCC_IS_HIPCLANG: 248 gpu_linker_flags.append('-L' + HCC_RUNTIME_PATH) 249 gpu_linker_flags.append('-Wl,-rpath=' + HCC_RUNTIME_PATH) 250 gpu_linker_flags.append('-l' + HCC_RUNTIME_LIBRARY) 251 gpu_linker_flags.append('-L' + HIP_RUNTIME_PATH) 252 gpu_linker_flags.append('-Wl,-rpath=' + HIP_RUNTIME_PATH) 253 gpu_linker_flags.append('-l' + HIP_RUNTIME_LIBRARY) 254 255 if VERBOSE: print(' '.join([CPU_COMPILER] + gpu_linker_flags)) 256 return subprocess.call([CPU_COMPILER] + gpu_linker_flags) 257 258 else: 259 # compilation for host objects 260 261 # Strip our flags before passing through to the CPU compiler for files which 262 # are not -x rocm. We can't just pass 'leftover' because it also strips -x. 263 # We not only want to pass -x to the CPU compiler, but also keep it in its 264 # relative location in the argv list (the compiler is actually sensitive to 265 # this). 266 cpu_compiler_flags = [flag for flag in sys.argv[1:] 267 if not flag.startswith(('--rocm_log'))] 268 269 # XXX: SE codes need to be built with gcc, but need this macro defined 270 cpu_compiler_flags.append("-D__HIP_PLATFORM_HCC__") 271 if VERBOSE: print(' '.join([CPU_COMPILER] + cpu_compiler_flags)) 272 return subprocess.call([CPU_COMPILER] + cpu_compiler_flags) 273 274 if __name__ == '__main__': 275 sys.exit(main())