[Clang][NFC] Clean up fetching the offloading toolchain (#125095)

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.
This commit is contained in:
Joseph Huber
2025-02-06 16:35:53 -06:00
committed by GitHub
parent 8d925a1c72
commit 6e2f08b2f8
4 changed files with 104 additions and 112 deletions

View File

@@ -797,22 +797,14 @@ private:
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.

View File

@@ -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,73 @@ 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 {
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) {
// 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 +6837,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 ||

View File

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

View File

@@ -74,7 +74,7 @@ public:
std::string getLibDeviceFile(StringRef Gpu) const {
return LibDeviceMap.lookup(Gpu);
}
void WarnIfUnsupportedVersion();
void WarnIfUnsupportedVersion() const;
};
namespace tools {