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())