Fichiers
rocm-systems/bin/hipcc
T
Yaxun (Sam) Liu 0964d64071 Let hipcc not escape space between obj files extracted from library
hipcc extracts bundles from static libraries and pass them to clang. It should
not escape spaces between objects extracted from library.

Fixes: SWDEV-246544
Change-Id: Iad3902f28a43a3986917ee37a49f10382c329940
2020-08-07 09:34:27 -04:00

915 lignes
31 KiB
Perl
Fichiers exécutables

#!/usr/bin/perl -w
# Need perl > 5.10 to use logic-defined or
use 5.006; use v5.10.1;
use File::Basename;
use File::Temp qw/ :mktemp /;
use Cwd;
use Cwd 'abs_path';
# HIP compiler driver
# Will call NVCC or HCC (depending on target) and pass the appropriate include and library options for
# the target compiler and HIP infrastructure.
# Will pass-through options to the target compiler. The tools calling HIPCC must ensure the compiler
# options are appropriate for the target compiler.
# Environment variable HIP_PLATFORM control compilation path:
# HIP_PLATFORM='nvcc' or HIP_PLATFORM='hcc'.
# If HIP_PLATFORM is not set hipcc will attempt auto-detect based on if nvcc is found.
#
# Other environment variable controls:
# HIP_PATH : Path to HIP directory, default is one dir level above location of this script.
# CUDA_PATH : Path to CUDA SDK (default /usr/local/cuda). Used on NVIDIA platforms only.
# HCC_HOME : Path to HCC SDK (defaults to ../../hcc relative to this
# script's abs_path). Used on AMD platforms only.
# HSA_PATH : Path to HSA dir (defaults to ../../hsa relative to abs_path
# of this script). Used on AMD platforms only.
# HIP_ROCCLR_HOME : Path to HIP/ROCclr directory. Used on AMD platforms only.
# HIP_CLANG_PATH : Path to HIP-Clang (default to ../../llvm/bin relative to this
# script's abs_path). Used on AMD platforms only.
if(scalar @ARGV == 0){
print "No Arguments passed, exiting ...\n";
exit(-1);
}
#---
# Function to parse config file
sub parse_config_file {
my ($file, $config) = @_;
if (open (CONFIG, "$file")) {
while (<CONFIG>) {
my $config_line=$_;
chop ($config_line);
$config_line =~ s/^\s*//;
$config_line =~ s/\s*$//;
if (($config_line !~ /^#/) && ($config_line ne "")) {
my ($name, $value) = split (/=/, $config_line);
$$config{$name} = $value;
}
}
close(CONFIG);
}
}
$verbose = $ENV{'HIPCC_VERBOSE'} // 0;
# Verbose: 0x1=commands, 0x2=paths, 0x4=hipcc args
$isWindows = $^O eq 'MSWin32';
$HIPCC_COMPILE_FLAGS_APPEND=$ENV{'HIPCC_COMPILE_FLAGS_APPEND'};
$HIPCC_LINK_FLAGS_APPEND=$ENV{'HIPCC_LINK_FLAGS_APPEND'};
# Known HIP target names.
@knownTargets = ('gfx701', 'gfx801', 'gfx802', 'gfx803', 'gfx900', 'gfx906', 'gfx908', 'gfx1010', 'gfx1011', 'gfx1012');
#
# TODO: Fix rpath LDFLAGS settings
#
# Since this hipcc script gets installed at two uneven hierarchical levels,
# linked by symlink, the absolute path of this script should be used to
# derive HIP_PATH, as dirname $0 could be /opt/rocm/bin or /opt/rocm/hip/bin
# depending on how it gets invoked.
# ROCM_PATH which points to <rocm_install_dir> is determined based on whether
# we find .info/version in the parent of HIP_PATH or not. If it is found,
# ROCM_PATH is defined relative to HIP_PATH else it is hardcoded to /opt/rocm.
#
$HIP_PATH=$ENV{'HIP_PATH'} // dirname(Cwd::abs_path("$0/../")); # use parent directory of hipcc
if (-e "$HIP_PATH/../.info/version") {
$ROCM_PATH=$ENV{'ROCM_PATH'} // dirname("$HIP_PATH"); # use parent directory of HIP_PATH
} else {
$ROCM_PATH=$ENV{'ROCM_PATH'} // "/opt/rocm";
}
$HIP_ROCCLR_HOME=$ENV{'HIP_ROCCLR_HOME'};
$HIP_LIB_PATH=$ENV{'HIP_LIB_PATH'};
$HIP_CLANG_PATH=$ENV{'HIP_CLANG_PATH'};
$DEVICE_LIB_PATH=$ENV{'DEVICE_LIB_PATH'};
$HIP_CLANG_HCC_COMPAT_MODE=$ENV{'HIP_CLANG_HCC_COMPAT_MODE'}; # HCC compatibility mode
$HIP_COMPILE_CXX_AS_HIP=$ENV{'HIP_COMPILE_CXX_AS_HIP'} // "1";
if (defined $HIP_ROCCLR_HOME) {
$HIP_INFO_PATH= "$HIP_ROCCLR_HOME/lib/.hipInfo";
} else {
$HIP_INFO_PATH= "$HIP_PATH/lib/.hipInfo"; # use actual file
}
#---
# Read .hipInfo
my %hipConfig = ();
parse_config_file("$HIP_INFO_PATH", \%hipConfig);
#---
# Temporary directories
my @tmpDirs = ();
#---
# Create a new temporary directory and return it
sub get_temp_dir {
my $tmpdir = mkdtemp("/tmp/hipccXXXXXXXX");
push (@tmpDirs, $tmpdir);
return $tmpdir;
}
#---
# Delete all created temporary directories
sub delete_temp_dirs {
if (@tmpDirs) {
system ('rm -rf ' . join (' ', @tmpDirs));
}
return 0;
}
#---
#HIP_PLATFORM controls whether to use hcc (AMD) or nvcc as the platform:
#HIP_COMPILER controls whether to use hcc, clang or nvcc for compilation:
#HIP_RUNTIME controls whether to use HCC, ROCclr, or NVCC as the runtime:
if ($isWindows) {
# Windows cannot run perl natively, so hipcc will explicitly call perl
$HIP_PLATFORM= `perl $HIP_PATH/bin/hipconfig --platform`;
$HIP_VERSION= `perl $HIP_PATH/bin/hipconfig --version`;
$HIP_COMPILER= `perl $HIP_PATH/bin/hipconfig --compiler`;
$HIP_RUNTIME= `perl $HIP_PATH/bin/hipconfig --runtime`;
} else {
$HIP_PLATFORM= `$HIP_PATH/bin/hipconfig --platform`;
$HIP_VERSION= `$HIP_PATH/bin/hipconfig --version`;
$HIP_COMPILER= `$HIP_PATH/bin/hipconfig --compiler`;
$HIP_RUNTIME= `$HIP_PATH/bin/hipconfig --runtime`;
}
# If using ROCclr runtime, need to find HIP_ROCCLR_HOME
if (defined $HIP_RUNTIME and $HIP_RUNTIME eq "ROCclr" and !defined $HIP_ROCCLR_HOME) {
my $hipcc_dir = dirname($0);
if (-e "$hipcc_dir/../lib/bitcode") {
$HIP_ROCCLR_HOME = abs_path($hipcc_dir . "/..");
} else {
$HIP_ROCCLR_HOME = $HIP_PATH; # use HIP_PATH
}
$HIPCXXFLAGS .= "-D__HIP_ROCclr__";
$HIPCFLAGS .= "-D__HIP_ROCclr__";
}
if (defined $HIP_ROCCLR_HOME) {
if (!defined $HIP_CLANG_PATH and (-e "$HIP_ROCCLR_HOME/bin/clang" or -e "$HIP_ROCCLR_HOME/bin/clang.exe")) {
$HIP_CLANG_PATH = "$HIP_ROCCLR_HOME/bin";
}
if (!defined $DEVICE_LIB_PATH and -e "$HIP_ROCCLR_HOME/lib/bitcode") {
$DEVICE_LIB_PATH = "$HIP_ROCCLR_HOME/lib/bitcode";
}
$HIP_INCLUDE_PATH = "$HIP_ROCCLR_HOME/include";
if (!defined $HIP_LIB_PATH) {
$HIP_LIB_PATH = "$HIP_ROCCLR_HOME/lib";
}
}
if (defined $HIP_COMPILER and $HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
if (!defined $HIP_CLANG_PATH) {
$HIP_CLANG_PATH = "$ROCM_PATH/llvm/bin";
}
if (!defined $DEVICE_LIB_PATH) {
if (-e "$ROCM_PATH/amdgcn/bitcode") {
$DEVICE_LIB_PATH = "$ROCM_PATH/amdgcn/bitcode";
}
else {
# This path is to support an older build of the device library
# TODO: To be removed in the future.
$DEVICE_LIB_PATH = "$ROCM_PATH/lib";
}
}
}
if ($verbose & 0x2) {
print ("HIP_PATH=$HIP_PATH\n");
print ("HIP_PLATFORM=$HIP_PLATFORM\n");
print ("HIP_COMPILER=$HIP_COMPILER\n");
print ("HIP_RUNTIME=$HIP_RUNTIME\n");
}
# set if user explicitly requests -stdlib=libc++. (else we default to libstdc++ for better interop with g++):
$setStdLib = 0; # TODO - set to 0
$default_amdgpu_target = 1;
if ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
$HIPCC="$HIP_CLANG_PATH/clang++";
# If $HIPCC clang++ is not compiled, use clang instead
if ( ! -e $HIPCC ) {
$HIPCC="$HIP_CLANG_PATH/clang";
$HIPLDFLAGS = "--driver-mode=g++";
}
$HIP_CLANG_VERSION = `$HIPCC --version`;
$HIP_CLANG_VERSION=~/.*clang version ([^ ]+).*/;
$HIP_CLANG_VERSION=$1;
if (! defined $HIP_CLANG_INCLUDE_PATH) {
$HIP_CLANG_INCLUDE_PATH = abs_path("$HIP_CLANG_PATH/../lib/clang/$HIP_CLANG_VERSION/include");
}
if (! defined $HIP_INCLUDE_PATH) {
$HIP_INCLUDE_PATH = "$HIP_PATH/include";
}
if (! defined $HIP_LIB_PATH) {
$HIP_LIB_PATH = "$HIP_PATH/lib";
}
if ($verbose & 0x2) {
print ("ROCM_PATH=$ROCM_PATH\n");
if (defined $HIP_ROCCLR_HOME) {
print ("HIP_ROCCLR_HOME=$HIP_ROCCLR_HOME\n");
}
print ("HIP_CLANG_PATH=$HIP_CLANG_PATH\n");
print ("HIP_CLANG_INCLUDE_PATH=$HIP_CLANG_INCLUDE_PATH\n");
print ("HIP_INCLUDE_PATH=$HIP_INCLUDE_PATH\n");
print ("HIP_LIB_PATH=$HIP_LIB_PATH\n");
print ("DEVICE_LIB_PATH=$DEVICE_LIB_PATH\n");
}
if ($isWindows) {
$HIPCXXFLAGS .= " -std=c++14 -fms-extensions -fms-compatibility";
} else {
$HIPCXXFLAGS .= " -std=c++11";
}
$HIPCXXFLAGS .= " -isystem $HIP_CLANG_INCLUDE_PATH/..";
$HIPCFLAGS .= " -isystem $HIP_CLANG_INCLUDE_PATH/..";
$HIPLDFLAGS .= " -L$HIP_LIB_PATH";
if ($isWindows) {
$HIPLDFLAGS .= " -lamdhip64";
}
if ($HIP_CLANG_HCC_COMPAT_MODE) {
## Allow __fp16 as function parameter and return type.
$HIPCXXFLAGS .= " -Xclang -fallow-half-arguments-and-returns -D__HIP_HCC_COMPAT_MODE__=1";
}
$HSA_PATH=$ENV{'HSA_PATH'} // "$ROCM_PATH/hsa";
$HIPCXXFLAGS .= " -isystem $HSA_PATH/include";
$HIPCFLAGS .= " -isystem $HSA_PATH/include";
if ($HIP_RUNTIME ne "HCC" ) {
$HIPCXXFLAGS .= " -D__HIP_ROCclr__";
$HIPCFLAGS .= " -D__HIP_ROCclr__";
}
} elsif ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "hcc") {
$HIP_INCLUDE_PATH = "$HIP_PATH/include";
if (! defined $HIP_LIB_PATH) {
$HIP_LIB_PATH = "$HIP_PATH/lib";
}
$HSA_PATH=$ENV{'HSA_PATH'} // "$ROCM_PATH/hsa";
$HCC_HOME=$ENV{'HCC_HOME'} // $hipConfig{'HCC_HOME'} // "$ROCM_PATH/hcc";
$HCC_VERSION=`${HCC_HOME}/bin/hcc --version`;
$HCC_VERSION=~/.*based on HCC ([^ ]+).*/;
$HCC_VERSION=$1;
$HCC_VERSION_MAJOR=$HCC_VERSION;
$HCC_VERSION_MAJOR=~s/\..*//;
# HCC* may be used to compile src/hip_hcc.o (and also feed the HIPCXXFLAGS below)
$HCC = "$HCC_HOME/bin/hcc";
$HCCFLAGS = "-hc -D__HIPCC__ -isystem $HCC_HOME/include ";
$HIPCC=$HCC;
$HIPCXXFLAGS = $HCCFLAGS;
$HIPLDFLAGS = `${HCC_HOME}/bin/hcc-config --ldflags`;
#### GCC system includes workaround ####
$HCC_WA_FLAGS = " ";
$HOST_OSNAME= `cat /etc/os-release | grep "^ID\=" | cut -d= -f2 | tr -d '\n'`;
if ($HCC_VERSION_MAJOR eq 1) {
my $GCC_CUR_VER = `gcc -dumpversion`;
my $GPP_CUR_VER = `g++ -dumpversion`;
$GCC_CUR_VER =~ s/\R//g;
$GPP_CUR_VER =~ s/\R//g;
my @GPP_VER_FIELDS = split('\.', $GPP_CUR_VER);
# Only include the libstdc++ headers and libraries flags explicitly if the g++ is older than version 5.
# That's because HCC already uses libstdc++ by default if a newer g++/libstdc++ is available
# Cent OS 7 and RHEL 7.4 cannot use libstdc++ for compilation, default to libc++
if (${GCC_CUR_VER} eq ${GPP_CUR_VER} and $GPP_VER_FIELDS[0] < 5 and ($HOST_OSNAME ne "\"centos\"") and ($HOST_OSNAME ne "\"rhel\"")) {
$HCC_WA_FLAGS .= " -stdlib=libstdc++ -isystem /usr/include/x86_64-linux-gnu -isystem /usr/include/x86_64-linux-gnu/c++/${GCC_CUR_VER} -isystem /usr/include/c++/${GCC_CUR_VER} ";
# Add C++ libs for GCC.
$HIPLDFLAGS .= " -lstdc++";
}
}
# Force -stdlib=libc++ on UB14.04
$HOST_OSVER= `cat /etc/os-release | grep "^VERSION_ID\=" | cut -d= -f2 | tr -d '\n'`;
if ($HOST_OSNAME eq "ubuntu" and $HOST_OSVER eq "\"14.04\"") {
$HIPCXXFLAGS .= " -stdlib=libc++";
$setStdLib = 1;
}
$HIPCXXFLAGS .= " -isystem $HIP_PATH/include/hip/hcc_detail/cuda";
$HIPCFLAGS .= " -isystem $HIP_PATH/include/hip/hcc_detail/cuda";
$HIPCXXFLAGS .= " -isystem $HSA_PATH/include";
$HIPCFLAGS .= " -isystem $HSA_PATH/include";
$HIPCXXFLAGS .= " -Wno-deprecated-register";
$HIPCFLAGS .= " -Wno-deprecated-register";
$HIPLDFLAGS .= " -L$HSA_PATH/lib -L$ROCM_PATH/lib -lhsa-runtime64 -lhc_am ";
# $HIPLDFLAGS .= " -L$HCC_HOME/compiler/lib -lLLVMAMDGPUDesc -lLLVMAMDGPUUtils -lLLVMMC -lLLVMCore -lLLVMSupport ";
if (not $isWindows) {
$HIPLDFLAGS .= " -lm";
}
if ($verbose & 0x2) {
print ("HSA_PATH=$HSA_PATH\n");
print ("HCC_HOME=$HCC_HOME\n");
}
} elsif ($HIP_PLATFORM eq "nvcc") {
$CUDA_PATH=$ENV{'CUDA_PATH'} // '/usr/local/cuda';
$HIP_INCLUDE_PATH = "$HIP_PATH/include";
if ($verbose & 0x2) {
print ("CUDA_PATH=$CUDA_PATH\n");
}
$HIPCC="$CUDA_PATH/bin/nvcc";
$HIPCXXFLAGS .= " -Wno-deprecated-gpu-targets ";
$HIPCXXFLAGS .= " -isystem $CUDA_PATH/include";
$HIPCFLAGS .= " -isystem $CUDA_PATH/include";
$HIPLDFLAGS = " -Wno-deprecated-gpu-targets -lcuda -lcudart -L$CUDA_PATH/lib64";
} else {
printf ("error: unknown HIP_PLATFORM = '$HIP_PLATFORM'");
printf (" or HIP_COMPILER = '$HIP_COMPILER'");
exit (-1);
}
# Add paths to common HIP includes:
$HIPCXXFLAGS .= " -isystem $HIP_INCLUDE_PATH" ;
$HIPCFLAGS .= " -isystem $HIP_INCLUDE_PATH" ;
my $compileOnly = 0;
my $needCXXFLAGS = 0; # need to add CXX flags to compile step
my $needCFLAGS = 0; # need to add C flags to compile step
my $needLDFLAGS = 1; # need to add LDFLAGS to compile step.
my $hasC = 0; # options contain a c-style file
my $hasCXX = 0; # options contain a cpp-style file (NVCC must force recognition as GPU file)
my $hasCU = 0; # options contain a cu-style file (HCC must force recognition as GPU file)
my $hasHIP = 0; # options contain a hip-style file (HIP-Clang must pass offloading options)
my $needHipHcc = ($HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'hcc'); # set if we need to link hip_hcc.o from src tree. (some builds, ie cmake, provide their own)
my $printHipVersion = 0; # print HIP version
my $printCXXFlags = 0; # print HIPCXXFLAGS
my $printLDFlags = 0; # print HIPLDFLAGS
my $runCmd = 1;
my $buildDeps = 0;
my $linkType = 1;
my $setLinkType = 0;
my $coFormatv3 = 1;
if(defined $HIP_COMPILER and $HIP_COMPILER eq "hcc") {
$coFormatv3 = 0;
}
my $funcSupp = 0; # enable function support
my $rdc = 0; # whether -fgpu-rdc is on
my @options = ();
my @inputs = ();
if ($verbose & 0x4) {
print "hipcc-args: ", join (" ", @ARGV), "\n";
}
# Handle code object generation
my $ISACMD="";
if($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "hcc"){
$ISACMD .= "$HIP_PATH/bin/lpl ";
if($ARGV[0] eq "--genco"){
foreach $isaarg (@ARGV[1..$#ARGV]){
$ISACMD .= " ";
$ISACMD .= $isaarg;
}
if ($verbose & 0x1) {
print "hipcc-cmd: ", $ISACMD, "\n";
}
system($ISACMD) and die();
exit(0);
}
}
if(($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "hcc")){
$ENV{HCC_EXTRA_LIBRARIES}="\n";
}
if($HIP_PLATFORM eq "nvcc"){
$ISACMD .= "$HIP_PATH/bin/hipcc -ptx ";
if($ARGV[0] eq "--genco"){
foreach $isaarg (@ARGV[1..$#ARGV]){
$ISACMD .= " ";
$ISACMD .= $isaarg;
}
if ($verbose & 0x1) {
print "hipcc-cmd: ", $ISACMD, "\n";
}
system($ISACMD) and die();
exit(0);
}
}
# TODO: convert toolArgs to an array rather than a string
my $toolArgs = ""; # arguments to pass to the hcc or nvcc tool
my $optArg = ""; # -O args
my $targetOpt = '--amdgpu-target=';
my $targetsStr = "";
my $skipOutputFile = 0; # file followed by -o should not contibute in picking compiler flags
my $prevArg = ""; # previous argument
foreach $arg (@ARGV)
{
# Save $arg, it can get changed in the loop.
$trimarg = $arg;
# TODO: figure out why this space removal is wanted.
# TODO: If someone has gone to the effort of quoting the spaces to the shell
# TODO: why are we removing it here?
$trimarg =~ s/^\s+|\s+$//g; # Remive whitespace
my $swallowArg = 0;
my $escapeArg = 1;
if ($arg eq '-c' or $arg eq '--genco' or $arg eq '-E') {
$compileOnly = 1;
$needLDFLAGS = 0;
}
if ($skipOutputFile) {
# TODO: handle filename with shell metacharacters
$toolArgs .= " $arg";
$prevArg = $arg;
$skipOutputFile = 0;
next;
}
if ($arg eq '-o') {
$needLDFLAGS = 1;
$skipOutputFile = 1;
}
if(($trimarg eq '-stdlib=libc++') and ($setStdLib eq 0))
{
$HIPCXXFLAGS .= " -stdlib=libc++";
$setStdLib = 1;
}
# Check target selection option: --amdgpu-target=...
if (substr($arg, 0, length($targetOpt)) eq $targetOpt) {
# If targets string is not empty, add a comma before adding new target option value.
$targetsStr .= ($targetsStr ? ',' : '');
$targetsStr .= substr($arg, length($targetOpt));
$default_amdgpu_target = 0;
# hip-clang does not accept --amdgpu-target= options.
if ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
$swallowArg = 1;
}
}
# code object format parsing
if ($trimarg eq '-mcode-object-v3') {
$coFormatv3 = 1;
}
if ($trimarg eq '-mno-code-object-v3') {
$coFormatv3 = 0;
}
if (($arg =~ /--genco/) and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'clang' ) {
$arg = "--cuda-device-only";
}
if(($trimarg eq '-stdlib=libstdc++') and ($setStdLib eq 0) and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'hcc')
{
$HIPCXXFLAGS .= $HCC_WA_FLAGS;
$setStdLib = 1;
}
if($trimarg eq '--version') {
$printHipVersion = 1;
}
if($trimarg eq '--short-version') {
$printHipVersion = 1;
$runCmd = 0;
}
if($trimarg eq '--cxxflags') {
$printCXXFlags = 1;
$runCmd = 0;
}
if($trimarg eq '--ldflags') {
$printLDFlags = 1;
$runCmd = 0;
}
if($trimarg eq '-M') {
$compileOnly = 1;
$buildDeps = 1;
}
if($trimarg eq '-use_fast_math') {
$HIPCXXFLAGS .= " -DHIP_FAST_MATH ";
$HIPCFLAGS .= " -DHIP_FAST_MATH ";
}
if(($trimarg eq '-use-staticlib') and ($setLinkType eq 0))
{
$linkType = 0;
$setLinkType = 1;
$swallowArg = 1;
}
if(($trimarg eq '-use-sharedlib') and ($setLinkType eq 0))
{
$linkType = 1;
$setLinkType = 1;
}
if($arg =~ m/^-O/)
{
$optArg = $arg;
}
## process linker response file for hip-clang
## extract object files from static library and pass them directly to
## hip-clang in command line.
## ToDo: Remove this after hip-clang switch to lto and lld is able to
## handle clang-offload-bundler bundles.
if ($arg =~ m/^-Wl,@/ and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'clang') {
my $file = substr $arg, 5;
open my $in, "<:encoding(utf8)", $file or die "$file: $!";
my $new_arg = "";
my $tmpdir = get_temp_dir ();
my $new_file = "$tmpdir/response_file";
open my $out, ">", $new_file or die "$new_file: $!";
while (my $line = <$in>) {
chomp $line;
if ($line =~ m/\.a$/ || $line =~ m/\.lo$/) {
my $libFile = $line;
my $path = abs_path($line);
my @objs = split ('\n', `cd $tmpdir; ar xv $path`);
## Check if all files in .a are object files.
my $allIsObj = 1;
my $realObjs = "";
foreach my $obj (@objs) {
chomp $obj;
$obj =~ s/^x - //;
$obj = "$tmpdir/$obj";
my $fileType = `file $obj`;
my $isObj = ($fileType =~ m/ELF/ or $fileType =~ m/COFF/);
$allIsObj = ($allIsObj and $isObj);
if ($isObj) {
$realObjs = ($realObjs . " " . $obj);
} else {
push (@inputs, $obj);
$new_arg = "$new_arg $obj";
}
}
chomp $realObjs;
if ($allIsObj) {
print $out "$line\n";
} elsif ($realObjs) {
my($libBaseName, $libDir, $libExt) = fileparse($libFile);
$libBaseName = mktemp($libBaseName . "XXXX") . $libExt;
system("cd $tmpdir; ar c $libBaseName $realObjs");
print $out "$tmpdir/$libBaseName\n";
}
} elsif ($line =~ m/\.o$/) {
my $fileType = `file $line`;
my $isObj = ($fileType =~ m/ELF/ or $fileType =~ m/COFF/);
if ($isObj) {
print $out "$line\n";
} else {
push (@inputs, $line);
$new_arg = "$new_arg $line";
}
} else {
print $out "$line\n";
}
}
close $in;
close $out;
$arg = "$new_arg -Wl,\@$new_file";
$escapeArg = 0;
} elsif (($arg =~ m/\.a$/ || $arg =~ m/\.lo$/) &&
$HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'clang') {
## process static library for hip-clang
## extract object files from static library and pass them directly to
## hip-clang.
## ToDo: Remove this after hip-clang switch to lto and lld is able to
## handle clang-offload-bundler bundles.
my $new_arg = "";
my $tmpdir = get_temp_dir ();
my $libFile = $arg;
my $path = abs_path($arg);
my @objs = split ('\n', `cd $tmpdir; ar xv $path`);
## Check if all files in .a are object files.
my $allIsObj = 1;
my $realObjs = "";
foreach my $obj (@objs) {
chomp $obj;
$obj =~ s/^x - //;
$obj = "$tmpdir/$obj";
my $fileType = `file $obj`;
my $isObj = ($fileType =~ m/ELF/ or $fileType =~ m/COFF/);
if ($fileType =~ m/ELF/) {
my $sections = `readelf -e -W $obj`;
$isObj = !($sections =~ m/__CLANG_OFFLOAD_BUNDLE__/);
}
$allIsObj = ($allIsObj and $isObj);
if ($isObj) {
$realObjs = ($realObjs . " " . $obj);
} else {
push (@inputs, $obj);
if ($new_arg ne "") {
$new_arg .= " ";
}
$new_arg .= "$obj";
}
}
chomp $realObjs;
if ($allIsObj) {
$new_arg = $arg;
} elsif ($realObjs) {
my($libBaseName, $libDir, $libExt) = fileparse($libFile);
$libBaseName = mktemp($libBaseName . "XXXX") . $libExt;
system("cd $tmpdir; ar c $libBaseName $realObjs");
$new_arg .= " $tmpdir/$libBaseName";
}
$arg = "$new_arg";
$escapeArg = 0;
if ($toolArgs =~ m/-Xlinker$/) {
$toolArgs = substr $toolArgs, 0, -8;
chomp $toolArgs;
}
} elsif ($arg eq 'c' and $prevArg eq '-x') {
$hasC = 1;
$hasCXX = 0;
$hasHIP = 0;
} elsif ($arg eq 'c++' and $prevArg eq '-x') {
$hasC = 0;
$hasCXX = 1;
$hasHIP = 0;
} elsif ($arg eq 'hip' and $prevArg eq '-x') {
$hasC = 0;
$hasCXX = 0;
$hasHIP = 1;
} elsif ($arg =~ m/^-/) {
# options start with -
if ($arg eq '-fgpu-rdc') {
$rdc = 1;
} elsif ($arg eq '-fno-gpu-rdc') {
$rdc = 0;
}
# Process HIPCC options here:
if ($arg =~ m/^--hipcc/) {
$swallowArg = 1;
#if $arg eq "--hipcc_profile") { # Example argument here, hipcc
#
#}
if ($arg eq "--hipcc-func-supp") {
$funcSupp = 1;
} elsif ($arg eq "--hipcc-no-func-supp") {
$funcSupp = 0;
}
} else {
push (@options, $arg);
}
#print "O: <$arg>\n";
} elsif ($prevArg ne '-o') {
# input files and libraries
# Skip guessing if `-x {c|c++|hip}` is already specified.
if (not ($hasC or $hasCXX or $hasHIP)) {
if ($arg =~ /\.c$/) {
$hasC = 1;
$needCFLAGS = 1;
$toolArgs .= " -x c"
} elsif (($arg =~ /\.cpp$/) or ($arg =~ /\.cxx$/) or ($arg =~ /\.cc$/) ) {
$needCXXFLAGS = 1;
if ($HIP_COMPILE_CXX_AS_HIP eq '0' or $HIP_COMPILER ne "clang") {
$hasCXX = 1;
} elsif ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
$hasHIP = 1;
$toolArgs .= " -x hip";
}
} elsif ((($arg =~ /\.cu$/ or $arg =~ /\.cuh$/) and $HIP_COMPILE_CXX_AS_HIP ne '0') or ($arg =~ /\.hip$/)) {
$needCXXFLAGS = 1;
if ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
$hasHIP = 1;
$toolArgs .= " -x hip";
} else {
$hasCU = 1;
}
}
} elsif ($hasC) {
$needCFLAGS = 1;
} elsif ($hasCXX) {
$needCXXFLAGS = 1;
} else {
$needCXXFLAGS = 1;
}
push (@inputs, $arg);
#print "I: <$arg>\n";
}
# Produce a version of $arg where characters significant to the shell are
# quoted. One could quote everything of course but don't bother for
# common characters such as alphanumerics.
# Do the quoting here because sometimes the $arg is changed in the loop
# Important to have all of '-Xlinker' in the set of unquoted characters.
if (not $isWindows and $escapeArg) { # Windows needs different quoting, ignore for now
$arg =~ s/[^-a-zA-Z0-9_=+,.\/]/\\$&/g;
}
$toolArgs .= " $arg" unless $swallowArg;
$prevArg = $arg;
}
if($HIP_PLATFORM eq "hcc"){
# No AMDGPU target specified at commandline. So look for HCC_AMDGPU_TARGET
if($default_amdgpu_target eq 1) {
if (defined $ENV{HCC_AMDGPU_TARGET}) {
$targetsStr = $ENV{HCC_AMDGPU_TARGET};
} else {
# Else try using rocm_agent_enumerator
$ROCM_AGENT_ENUM = "${ROCM_PATH}/bin/rocm_agent_enumerator";
$targetsStr = `${ROCM_AGENT_ENUM} -t GPU`;
$targetsStr =~ s/\n/,/g;
}
$default_amdgpu_target = 0;
}
# Parse the targets collected in targetStr and set corresponding compiler options.
my @targets = split(',', $targetsStr);
if($HIP_COMPILER eq "hcc") {
$GPU_ARCH_OPT = " --amdgpu-target=";
} else {
$GPU_ARCH_OPT = " --cuda-gpu-arch=";
}
foreach my $val (@targets) {
# Ignore 'gfx000' target reported by rocm_agent_enumerator.
if ($val ne 'gfx000') {
# Construct an arch macro to be passed to the compiler.
# Example: gfx900 --> -D__HIP_ARCH_GFX900__=1
my $archMacro = ' -D__HIP_ARCH_' . uc($val) . '__=1 ';
# Add the arch option and macro to the compiler options.
$GPU_ARCH_ARG = $GPU_ARCH_OPT . $val;
$HIPLDARCHFLAGS .= $GPU_ARCH_ARG;
$HIPCXXFLAGS .= $archMacro;
if ($HIP_COMPILER eq 'clang' and $hasHIP) {
$HIPCXXFLAGS .= $GPU_ARCH_ARG;
}
# If the specified target is not in the list of known target names, emit a warning.
if (grep(/$val/, @knownTargets) eq 0) {
print "Warning: The specified HIP target: $val is unknown. Correct compilation is not guaranteed.\n";
}
}
}
# rocm_agent_enumerator failed! Throw an error and die if linking is required
if ($default_amdgpu_target eq 1 and $compileOnly eq 0) {
print "No valid AMD GPU target was either specified or found. Please specify a valid target using --amdgpu-target=" and die();
}
$ENV{HCC_EXTRA_LIBRARIES}="\n";
}
# hcc defaults to v2, so we need to convert to the appropriate flag
# hip-clang defaults to v3, so we don't need to do anything
if ($coFormatv3 and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'hcc') {
$HIPLDFLAGS .= " -mcode-object-v3";
$HIPCXXFLAGS .= " -mcode-object-v3";
}
if ($hasCXX and $HIP_PLATFORM eq 'nvcc') {
$HIPCXXFLAGS .= " -x cu";
}
if ($hasCU and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'hcc') {
$HIPCXXFLAGS .= " -x c++";
}
if ($buildDeps and $HIP_PLATFORM eq 'nvcc') {
$HIPCXXFLAGS .= " -M -D__CUDACC__";
$HIPCFLAGS .= " -M -D__CUDACC__";
}
if ($buildDeps and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'clang') {
$HIPCXXFLAGS .= " --cuda-host-only";
}
# Add --hip-link only if it is compile only and -fgpu-rdc is on.
if ($rdc and !$compileOnly and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'clang') {
$HIPLDFLAGS .= " --hip-link";
$HIPLDFLAGS .= $HIPLDARCHFLAGS;
}
if ($setStdLib eq 0 and $HIP_PLATFORM eq 'hcc' and $HIP_COMPILER eq 'hcc')
{
$HIPCXXFLAGS .= $HCC_WA_FLAGS;
}
if ($needHipHcc) {
if ($linkType eq 0) {
substr($HIPLDFLAGS,0,0) = " $HIP_LIB_PATH/libamdhip64.a " ;
} else {
substr($HIPLDFLAGS,0,0) = " -Wl,--enable-new-dtags -Wl,--rpath=$HIP_LIB_PATH:$ROCM_PATH/lib $HIP_LIB_PATH/libamdhip64.so ";
}
}
# hipcc currrently requires separate compilation of source files, ie it is not possible to pass
# CPP files combined with .O files
# Reason is that NVCC uses the file extension to determine whether to compile in CUDA mode or
# pass-through CPP mode.
if ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "clang") {
# Set default optimization level to -O3 for hip-clang.
if ($optArg eq "") {
$HIPCXXFLAGS .= " -O3";
$HIPCFLAGS .= " -O3";
$HIPLDFLAGS .= " -O3";
}
if (!$funcSupp and $optArg ne "-O0" and $hasHIP) {
$HIPCXXFLAGS .= " -mllvm -amdgpu-early-inline-all=true -mllvm -amdgpu-function-calls=false";
if ($needLDFLAGS and not $needCXXFLAGS) {
$HIPLDFLAGS .= " -mllvm -amdgpu-early-inline-all=true -mllvm -amdgpu-function-calls=false";
}
}
if ($hasHIP) {
if ($DEVICE_LIB_PATH ne "$ROCM_PATH/amdgcn/bitcode") {
$HIPCXXFLAGS .= " --hip-device-lib-path=$DEVICE_LIB_PATH";
}
if ($HIP_RUNTIME ne "HCC") {
$HIPCXXFLAGS .= " -fhip-new-launch-api";
}
}
if (not $isWindows) {
$HIPLDFLAGS .= " -lgcc_s -lgcc -lpthread -lm";
}
if (not $isWindows and not $compileOnly) {
if ($linkType eq 0) {
$toolArgs .= " -L$HIP_LIB_PATH -lamdhip64 -L$ROCM_PATH/lib -lhsa-runtime64 -ldl -lnuma ";
} else {
$toolArgs .= " -Wl,--enable-new-dtags -Wl,--rpath=$HIP_LIB_PATH:$ROCM_PATH/lib -lamdhip64 ";
}
# To support __fp16 and _Float16, explicitly link with compiler-rt
$toolArgs .= " -L$HIP_CLANG_PATH/../lib/clang/$HIP_CLANG_VERSION/lib/linux -lclang_rt.builtins-x86_64 "
}
}
if ($HIPCC_COMPILE_FLAGS_APPEND) {
$HIPCXXFLAGS .= " $HIPCC_COMPILE_FLAGS_APPEND";
$HIPCFLAGS .= " $HIPCC_COMPILE_FLAGS_APPEND";
}
if ($HIPCC_LINK_FLAGS_APPEND) {
$HIPLDFLAGS .= " $HIPCC_LINK_FLAGS_APPEND";
}
# TODO: convert CMD to an array rather than a string
my $CMD="$HIPCC";
if ($needCFLAGS) {
$CMD .= " $HIPCFLAGS";
}
if ($needCXXFLAGS) {
$CMD .= " $HIPCXXFLAGS";
}
if ($needLDFLAGS and not $compileOnly) {
$CMD .= " $HIPLDFLAGS";
}
$CMD .= " $toolArgs";
if ($verbose & 0x1) {
print "hipcc-cmd: ", $CMD, "\n";
}
if ($printHipVersion) {
if ($runCmd) {
print "HIP version: "
}
print $HIP_VERSION, "\n";
}
if ($printCXXFlags) {
print $HIPCXXFLAGS;
}
if ($printLDFlags) {
print $HIPLDFLAGS;
}
if ($runCmd) {
if ($HIP_PLATFORM eq "hcc" and $HIP_COMPILER eq "hcc" and exists($hipConfig{'HCC_VERSION'}) and $HCC_VERSION ne $hipConfig{'HCC_VERSION'}) {
print ("HIP ($HIP_PATH) was built using hcc $hipConfig{'HCC_VERSION'}, but you are using $HCC_HOME/hcc with version $HCC_VERSION from hipcc. Please rebuild HIP including cmake or update HCC_HOME variable.\n") ;
die unless $ENV{'HIP_IGNORE_HCC_VERSION'};
}
system ("$CMD");
if ($? == -1) {
print "failed to execute: $!\n";
exit($?);
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
exit($?);
}
else {
$CMD_EXIT_CODE = $? >> 8;
}
$? or delete_temp_dirs ();
exit($CMD_EXIT_CODE);
}
# vim: ts=4:sw=4:expandtab:smartindent