https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/125095
>From 11ae495099dac5536e1cfbae77385fca41983577 Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Thu, 30 Jan 2025 11:28:50 -0600 Subject: [PATCH 1/2] [Clang] Clean up fetching the offloading toolchain Summary: This patch cleans up how we query the offloading toolchain. We create a single that is more similar to the existing `getToolChain` driver function and make all the offloading handlers use it. --- clang/include/clang/Driver/Driver.h | 18 +-- clang/lib/Driver/Driver.cpp | 195 +++++++++++++-------------- clang/lib/Driver/ToolChains/Cuda.cpp | 2 +- clang/lib/Driver/ToolChains/Cuda.h | 2 +- 4 files changed, 104 insertions(+), 113 deletions(-) diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index f4a52cc529b79cd..b463dc2a93550e1 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -797,22 +797,14 @@ class Driver { const ToolChain &getToolChain(const llvm::opt::ArgList &Args, const llvm::Triple &Target) const; - /// @} - - /// Retrieves a ToolChain for a particular device \p Target triple - /// - /// \param[in] HostTC is the host ToolChain paired with the device - /// - /// \param[in] TargetDeviceOffloadKind (e.g. OFK_Cuda/OFK_OpenMP/OFK_SYCL) is - /// an Offloading action that is optionally passed to a ToolChain (used by - /// CUDA, to specify if it's used in conjunction with OpenMP) + /// Retrieves a ToolChain for a particular \p Target triple for offloading. /// /// Will cache ToolChains for the life of the driver object, and create them /// on-demand. - const ToolChain &getOffloadingDeviceToolChain( - const llvm::opt::ArgList &Args, const llvm::Triple &Target, - const ToolChain &HostTC, - const Action::OffloadKind &TargetDeviceOffloadKind) const; + const ToolChain &getOffloadToolChain(const llvm::opt::ArgList &Args, + const Action::OffloadKind Kind, + const llvm::Triple &Target, + const llvm::Triple &AuxTarget) const; /// Get bitmasks for which option flags to include and exclude based on /// the driver mode. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 5a4737fb381e6a0..20ca672a410547b 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -886,27 +886,21 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, return; } if (IsCuda && !UseLLVMOffload) { - const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); - const llvm::Triple &HostTriple = HostTC->getTriple(); - auto OFK = Action::OFK_Cuda; - auto CudaTriple = - getNVIDIAOffloadTargetTriple(*this, C.getInputArgs(), HostTriple); + auto CudaTriple = getNVIDIAOffloadTargetTriple( + *this, C.getInputArgs(), C.getDefaultToolChain().getTriple()); 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()]; - if (!CudaTC) { - CudaTC = std::make_unique<toolchains::CudaToolChain>( - *this, *CudaTriple, *HostTC, C.getInputArgs()); - - // Emit a warning if the detected CUDA version is too new. - CudaInstallationDetector &CudaInstallation = - static_cast<toolchains::CudaToolChain &>(*CudaTC).CudaInstallation; - if (CudaInstallation.isValid()) - CudaInstallation.WarnIfUnsupportedVersion(); - } - C.addOffloadDeviceToolChain(CudaTC.get(), OFK); + + auto &TC = + getOffloadToolChain(C.getInputArgs(), Action::OFK_Cuda, *CudaTriple, + C.getDefaultToolChain().getTriple()); + + // Emit a warning if the detected CUDA version is too new. + const CudaInstallationDetector &CudaInstallation = + static_cast<const toolchains::CudaToolChain &>(TC).CudaInstallation; + if (CudaInstallation.isValid()) + CudaInstallation.WarnIfUnsupportedVersion(); + C.addOffloadDeviceToolChain(&TC, Action::OFK_Cuda); } else if (IsHIP && !UseLLVMOffload) { if (auto *OMPTargetArg = C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { @@ -914,14 +908,15 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, << OMPTargetArg->getSpelling() << "HIP"; return; } - const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); - auto OFK = Action::OFK_HIP; + auto HIPTriple = getHIPOffloadTargetTriple(*this, C.getInputArgs()); if (!HIPTriple) return; - auto *HIPTC = &getOffloadingDeviceToolChain(C.getInputArgs(), *HIPTriple, - *HostTC, OFK); - C.addOffloadDeviceToolChain(HIPTC, OFK); + + auto &TC = + getOffloadToolChain(C.getInputArgs(), Action::OFK_HIP, *HIPTriple, + C.getDefaultToolChain().getTriple()); + C.addOffloadDeviceToolChain(&TC, Action::OFK_HIP); } if (IsCuda || IsHIP) @@ -1038,40 +1033,17 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, FoundNormalizedTriples[NormalizedName] = Val; // If the specified target is invalid, emit a diagnostic. - if (TT.getArch() == llvm::Triple::UnknownArch) + if (TT.getArch() == llvm::Triple::UnknownArch) { Diag(clang::diag::err_drv_invalid_omp_target) << Val; - else { - const ToolChain *TC; - // Device toolchains have to be selected differently. They pair host - // and device in their implementation. - if (TT.isNVPTX() || TT.isAMDGCN() || TT.isSPIRV()) { - const ToolChain *HostTC = - C.getSingleOffloadToolChain<Action::OFK_Host>(); - assert(HostTC && "Host toolchain should be always defined."); - auto &DeviceTC = - ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; - if (!DeviceTC) { - if (TT.isNVPTX()) - DeviceTC = std::make_unique<toolchains::CudaToolChain>( - *this, TT, *HostTC, C.getInputArgs()); - else if (TT.isAMDGCN()) - DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>( - *this, TT, *HostTC, C.getInputArgs()); - else if (TT.isSPIRV()) - DeviceTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>( - *this, TT, *HostTC, C.getInputArgs()); - else - assert(DeviceTC && "Device toolchain not defined."); - } - - TC = DeviceTC.get(); - } else - TC = &getToolChain(C.getInputArgs(), TT); - C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); - auto It = DerivedArchs.find(TT.getTriple()); - if (It != DerivedArchs.end()) - KnownArchs[TC] = It->second; + continue; } + + auto &TC = getOffloadToolChain(C.getInputArgs(), Action::OFK_OpenMP, TT, + C.getDefaultToolChain().getTriple()); + C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP); + auto It = DerivedArchs.find(TT.getTriple()); + if (It != DerivedArchs.end()) + KnownArchs[&TC] = It->second; } } else if (C.getInputArgs().hasArg(options::OPT_fopenmp_targets_EQ)) { Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); @@ -1103,9 +1075,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // getOffloadingDeviceToolChain, because the device toolchains we're // going to create will depend on both. const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); - for (const auto &TargetTriple : UniqueSYCLTriplesVec) { - auto SYCLTC = &getOffloadingDeviceToolChain( - C.getInputArgs(), TargetTriple, *HostTC, Action::OFK_SYCL); + for (const auto &TT : UniqueSYCLTriplesVec) { + auto SYCLTC = &getOffloadToolChain(C.getInputArgs(), Action::OFK_SYCL, TT, + HostTC->getTriple()); C.addOffloadDeviceToolChain(SYCLTC, Action::OFK_SYCL); } } @@ -6605,6 +6577,72 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { return std::string(Output); } +const ToolChain &Driver::getOffloadToolChain( + const llvm::opt::ArgList &Args, const Action::OffloadKind Kind, + const llvm::Triple &Target, const llvm::Triple &AuxTarget) const { + auto &TC = ToolChains[Target.str() + "/" + AuxTarget.str()]; + auto &HostTC = ToolChains[AuxTarget.str()]; + + assert(HostTC && "Host toolchain for offloading doesn't exit?"); + if (!TC) { + // Detect the toolchain based off of the target operating system. + switch (Target.getOS()) { + case llvm::Triple::CUDA: + TC = std::make_unique<toolchains::CudaToolChain>(*this, Target, *HostTC, + Args); + break; + case llvm::Triple::AMDHSA: + if (Kind == Action::OFK_HIP) + TC = std::make_unique<toolchains::HIPAMDToolChain>(*this, Target, + *HostTC, Args); + else if (Kind == Action::OFK_OpenMP) + TC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(*this, Target, + *HostTC, Args); + break; + default: + break; + } + } + if (!TC) { + // Detect the toolchain based off of the target architecture if that failed. + switch (Target.getArch()) { + case llvm::Triple::spir: + case llvm::Triple::spir64: + case llvm::Triple::spirv: + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + switch (Kind) { + case Action::OFK_SYCL: + TC = std::make_unique<toolchains::SYCLToolChain>(*this, Target, *HostTC, + Args); + break; + case Action::OFK_HIP: + TC = std::make_unique<toolchains::HIPSPVToolChain>(*this, Target, + *HostTC, Args); + break; + case Action::OFK_OpenMP: + TC = std::make_unique<toolchains::SPIRVOpenMPToolChain>(*this, Target, + *HostTC, Args); + break; + case Action::OFK_Cuda: + TC = std::make_unique<toolchains::CudaToolChain>(*this, Target, *HostTC, + Args); + break; + default: + break; + } + break; + default: + break; + } + } + + // If all else fails, just look up the normal toolchain for the target. + if (!TC) + return getToolChain(Args, Target); + return *TC; +} + const ToolChain &Driver::getToolChain(const ArgList &Args, const llvm::Triple &Target) const { @@ -6798,45 +6836,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, return *TC; } -const ToolChain &Driver::getOffloadingDeviceToolChain( - const ArgList &Args, const llvm::Triple &Target, const ToolChain &HostTC, - const Action::OffloadKind &TargetDeviceOffloadKind) const { - // Use device / host triples as the key into the ToolChains map because the - // device ToolChain we create depends on both. - auto &TC = ToolChains[Target.str() + "/" + HostTC.getTriple().str()]; - if (!TC) { - // Categorized by offload kind > arch rather than OS > arch like - // the normal getToolChain call, as it seems a reasonable way to categorize - // things. - switch (TargetDeviceOffloadKind) { - case Action::OFK_HIP: { - if (((Target.getArch() == llvm::Triple::amdgcn || - Target.getArch() == llvm::Triple::spirv64) && - Target.getVendor() == llvm::Triple::AMD && - Target.getOS() == llvm::Triple::AMDHSA) || - !Args.hasArgNoClaim(options::OPT_offload_EQ)) - TC = std::make_unique<toolchains::HIPAMDToolChain>(*this, Target, - HostTC, Args); - else if (Target.getArch() == llvm::Triple::spirv64 && - Target.getVendor() == llvm::Triple::UnknownVendor && - Target.getOS() == llvm::Triple::UnknownOS) - TC = std::make_unique<toolchains::HIPSPVToolChain>(*this, Target, - HostTC, Args); - break; - } - case Action::OFK_SYCL: - if (Target.isSPIROrSPIRV()) - TC = std::make_unique<toolchains::SYCLToolChain>(*this, Target, HostTC, - Args); - break; - default: - break; - } - } - assert(TC && "Could not create offloading device tool chain."); - return *TC; -} - bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // Say "no" if there is not exactly one input of a type clang understands. if (JA.size() != 1 || diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index c800e9cfa0a8d81..c7d5893085080fb 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -123,7 +123,7 @@ CudaVersion parseCudaHFile(llvm::StringRef Input) { } } // namespace -void CudaInstallationDetector::WarnIfUnsupportedVersion() { +void CudaInstallationDetector::WarnIfUnsupportedVersion() const { if (Version > CudaVersion::PARTIALLY_SUPPORTED) { std::string VersionString = CudaVersionToString(Version); if (!VersionString.empty()) diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 7a6a6fb209012e8..c2219ec47cfa979 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -74,7 +74,7 @@ class CudaInstallationDetector { std::string getLibDeviceFile(StringRef Gpu) const { return LibDeviceMap.lookup(Gpu); } - void WarnIfUnsupportedVersion(); + void WarnIfUnsupportedVersion() const; }; namespace tools { >From 7f3a138765e66930d84caa956b98b5a250c09c94 Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Tue, 4 Feb 2025 13:57:51 -0600 Subject: [PATCH 2/2] comments --- clang/lib/Driver/Driver.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 20ca672a410547b..50941d2aaa42981 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -6580,8 +6580,9 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { const ToolChain &Driver::getOffloadToolChain( const llvm::opt::ArgList &Args, const Action::OffloadKind Kind, const llvm::Triple &Target, const llvm::Triple &AuxTarget) const { - auto &TC = ToolChains[Target.str() + "/" + AuxTarget.str()]; - auto &HostTC = ToolChains[AuxTarget.str()]; + std::unique_ptr<ToolChain> &TC = + ToolChains[Target.str() + "/" + AuxTarget.str()]; + std::unique_ptr<ToolChain> &HostTC = ToolChains[AuxTarget.str()]; assert(HostTC && "Host toolchain for offloading doesn't exit?"); if (!TC) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits