diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -627,8 +627,10 @@ def err_drv_ssp_missing_offset_argument : Error< "'%0' is used without '-mstack-protector-guard-offset', and there is no default">; -def err_drv_only_one_offload_target_supported_in : Error< - "Only one offload target is supported in %0.">; +def err_drv_only_one_offload_target_supported : Error< + "only one offload target is supported">; def err_drv_invalid_or_unsupported_offload_target : Error< - "Invalid or unsupported offload target: '%0'.">; + "invalid or unsupported offload target: '%0'">; +def err_drv_cuda_offload_only_emit_bc : Error< + "CUDA offload target is supported only along with --emit-llvm">; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1143,8 +1143,7 @@ // languages and accept other values such as CPU/GPU architectures, // offload kinds and target aliases. def offload_EQ : CommaJoined<["--"], "offload=">, Flags<[NoXarchOption]>, - HelpText<"Specify comma-separated list of offloading target triples" - " (HIP only)">; + HelpText<"Specify comma-separated list of offloading target triples (CUDA and HIP only)">; // C++ Coroutines TS defm coroutines_ts : BoolFOption<"coroutines-ts", diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -103,39 +103,58 @@ using namespace llvm::opt; static llvm::Optional -getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) { - if (Args.hasArg(options::OPT_offload_EQ)) { - auto HIPOffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ); +getOffloadTargetTriple(const Driver &D, const ArgList &Args) { + auto OffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ); + // Offload compilation flow does not support multiple targets for now. We + // need the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too) + // to support multiple tool chains first. + switch (OffloadTargets.size()) { + default: + D.Diag(diag::err_drv_only_one_offload_target_supported); + return llvm::None; + case 0: + D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << ""; + return llvm::None; + case 1: + break; + } + return llvm::Triple(OffloadTargets[0]); +} - // HIP compilation flow does not support multiple targets for now. We need - // the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too) to - // support multiple tool chains first. - switch (HIPOffloadTargets.size()) { - default: - D.Diag(diag::err_drv_only_one_offload_target_supported_in) << "HIP"; - return llvm::None; - case 0: - D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << ""; - return llvm::None; - case 1: - break; - } - llvm::Triple TT(HIPOffloadTargets[0]); - if (TT.getArch() == llvm::Triple::amdgcn && - TT.getVendor() == llvm::Triple::AMD && - TT.getOS() == llvm::Triple::AMDHSA) - return TT; - if (TT.getArch() == llvm::Triple::spirv64 && - TT.getVendor() == llvm::Triple::UnknownVendor && - TT.getOS() == llvm::Triple::UnknownOS) +static llvm::Optional +getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args, + const llvm::Triple &HostTriple) { + if (!Args.hasArg(options::OPT_offload_EQ)) { + return llvm::Triple(HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda"); + } + auto TT = getOffloadTargetTriple(D, Args); + if (TT && (TT->getArch() == llvm::Triple::spirv32 || + TT->getArch() == llvm::Triple::spirv64)) { + if (Args.hasArg(options::OPT_emit_llvm)) return TT; - D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) - << HIPOffloadTargets[0]; + D.Diag(diag::err_drv_cuda_offload_only_emit_bc); return llvm::None; } - - static const llvm::Triple T("amdgcn-amd-amdhsa"); // Default HIP triple. - return T; + D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str(); + return llvm::None; +} +static llvm::Optional +getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) { + if (!Args.hasArg(options::OPT_offload_EQ)) { + return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple. + } + auto TT = getOffloadTargetTriple(D, Args); + if (!TT) + return llvm::None; + if (TT->getArch() == llvm::Triple::amdgcn && + TT->getVendor() == llvm::Triple::AMD && + TT->getOS() == llvm::Triple::AMDHSA) + return TT; + if (TT->getArch() == llvm::Triple::spirv64) + return TT; + D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str(); + return llvm::None; } // static @@ -719,17 +738,17 @@ if (IsCuda) { const ToolChain *HostTC = C.getSingleOffloadToolChain(); const llvm::Triple &HostTriple = HostTC->getTriple(); - StringRef DeviceTripleStr; auto OFK = Action::OFK_Cuda; - DeviceTripleStr = - HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda"; - llvm::Triple CudaTriple(DeviceTripleStr); + auto CudaTriple = + getNVIDIAOffloadTargetTriple(*this, C.getInputArgs(), HostTriple); + if (!CudaTriple) + return; // Use the CUDA and host triples as the key into the ToolChains map, // because the device toolchain we create depends on both. - auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()]; + auto &CudaTC = ToolChains[CudaTriple->str() + "/" + HostTriple.str()]; if (!CudaTC) { CudaTC = std::make_unique( - *this, CudaTriple, *HostTC, C.getInputArgs(), OFK); + *this, *CudaTriple, *HostTC, C.getInputArgs(), OFK); } C.addOffloadDeviceToolChain(CudaTC.get(), OFK); } else if (IsHIP) { diff --git a/clang/test/Driver/cuda-device-triple.cu b/clang/test/Driver/cuda-device-triple.cu new file mode 100644 --- /dev/null +++ b/clang/test/Driver/cuda-device-triple.cu @@ -0,0 +1,6 @@ +// REQUIRES: clang-driver + +// RUN: %clang -### -emit-llvm --cuda-device-only \ +// RUN: -nocudalib -nocudainc --offload=spirv32-unknown-unknown -c %s 2>&1 | FileCheck %s + +// CHECK: clang{{.*}}" "-cc1" "-triple" "spirv32-unknown-unknown" {{.*}} "-fcuda-is-device" {{.*}} diff --git a/clang/test/Driver/invalid-offload-options.cpp b/clang/test/Driver/invalid-offload-options.cpp --- a/clang/test/Driver/invalid-offload-options.cpp +++ b/clang/test/Driver/invalid-offload-options.cpp @@ -9,7 +9,7 @@ // RUN: --hip-path=%S/Inputs/hipspv -nogpuinc -nogpulib %s \ // RUN: 2>&1 | FileCheck --check-prefix=INVALID-TARGET %s -// INVALID-TARGET: error: Invalid or unsupported offload target: '{{.*}}' +// INVALID-TARGET: error: invalid or unsupported offload target: '{{.*}}' // In the future we should be able to specify multiple targets for HIP // compilation but currently it is not supported. @@ -22,7 +22,7 @@ // RUN: --hip-path=%S/Inputs/hipspv -nogpuinc -nogpulib %s \ // RUN: 2>&1 | FileCheck --check-prefix=TOO-MANY-TARGETS %s -// TOO-MANY-TARGETS: error: Only one offload target is supported in HIP. +// TOO-MANY-TARGETS: error: only one offload target is supported // RUN: %clang -### -x hip -target x86_64-linux-gnu -nogpuinc -nogpulib \ // RUN: --offload=amdgcn-amd-amdhsa --offload-arch=gfx900 %s \