Skip to content

Commit

Permalink
[Driver][SYCL] Move traits macros settings to enable new model (#14635)
Browse files Browse the repository at this point in the history
The SYCL device traits settings were being performed within the old
model specific action builder class. Move this to the SYCL toolchain
area to be accessible by both the new and old offloading model. Also
hookup the new offloading model portion of this.
  • Loading branch information
mdtoguchi authored Jul 20, 2024
1 parent 1891dc3 commit ea0c067
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 98 deletions.
112 changes: 15 additions & 97 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include "llvm/SYCLLowerIR/DeviceConfigFile.hpp"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ExitCodes.h"
Expand Down Expand Up @@ -6234,101 +6233,6 @@ class OffloadingActionBuilder final {
return FinalDeviceSections;
}

/// Reads device config file to find information about the SYCL targets in
/// `Targets`, and defines device traits macros accordingly.
void populateSYCLDeviceTraitsMacrosArgs(
Compilation &C, const DerivedArgList &Args,
const SmallVector<DeviceTargetInfo, 4> &Targets) const {
if (Targets.empty())
return;

const auto &TargetTable = DeviceConfigFile::TargetTable;
std::map<StringRef, unsigned int> AllDevicesHave;
std::map<StringRef, bool> AnyDeviceHas;
bool AnyDeviceHasAnyAspect = false;
unsigned int ValidTargets = 0;
for (const auto &[TC, BoundArch] : Targets) {
assert(TC && "Invalid SYCL Offload Toolchain");
// Try and find the device arch, if it's empty, try to search for either
// the whole Triple or just the 'ArchName' string.
auto TargetIt = TargetTable.end();
const llvm::Triple &TargetTriple = TC->getTriple();
const StringRef TargetArch{BoundArch};
if (!TargetArch.empty()) {
TargetIt = llvm::find_if(TargetTable, [&](const auto &Value) {
using namespace tools::SYCL;
StringRef Device{Value.first};
if (Device.consume_front(gen::AmdGPU))
return TargetArch == Device && TargetTriple.isAMDGCN();
if (Device.consume_front(gen::NvidiaGPU))
return TargetArch == Device && TargetTriple.isNVPTX();
if (Device.consume_front(gen::IntelGPU))
return TargetArch == Device && TargetTriple.isSPIRAOT();
return TargetArch == Device && isValidSYCLTriple(TargetTriple);
});
} else {
TargetIt = TargetTable.find(TargetTriple.str());
if (TargetIt == TargetTable.end())
TargetIt = TargetTable.find(TargetTriple.getArchName().str());
}

if (TargetIt != TargetTable.end()) {
const DeviceConfigFile::TargetInfo &Info = (*TargetIt).second;
++ValidTargets;
const auto &AspectList = Info.aspects;
const auto &MaySupportOtherAspects = Info.maySupportOtherAspects;
if (!AnyDeviceHasAnyAspect)
AnyDeviceHasAnyAspect = MaySupportOtherAspects;
for (const auto &Aspect : AspectList) {
// If target has an entry in the config file, the set of aspects
// supported by all devices supporting the target is 'AspectList'.
// If there's no entry, such set is empty.
const auto &AspectIt = AllDevicesHave.find(Aspect);
if (AspectIt != AllDevicesHave.end())
++AllDevicesHave[Aspect];
else
AllDevicesHave[Aspect] = 1;
// If target has an entry in the config file AND
// 'MaySupportOtherAspects' is false, the set of aspects supported
// by any device supporting the target is 'AspectList'. If there's
// no entry OR 'MaySupportOtherAspects' is true, such set contains
// all the aspects.
AnyDeviceHas[Aspect] = true;
}
}
}

// If there's no entry for the target in the device config file, the set
// of aspects supported by any device supporting the target contains all
// the aspects.
if (ValidTargets == 0)
AnyDeviceHasAnyAspect = true;

const Driver &D = C.getDriver();
if (AnyDeviceHasAnyAspect) {
// There exists some target that supports any given aspect.
constexpr static StringRef MacroAnyDeviceAnyAspect{
"-D__SYCL_ANY_DEVICE_HAS_ANY_ASPECT__=1"};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAnyDeviceAnyAspect);
} else {
// Some of the aspects are not supported at all by any of the targets.
// Thus, we need to define individual macros for each supported aspect.
for (const auto &[TargetKey, SupportedTarget] : AnyDeviceHas) {
assert(SupportedTarget);
const SmallString<64> MacroAnyDevice{
{"-D__SYCL_ANY_DEVICE_HAS_", TargetKey, "__=1"}};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAnyDevice);
}
}
for (const auto &[TargetKey, SupportedTargets] : AllDevicesHave) {
if (SupportedTargets != ValidTargets)
continue;
const SmallString<64> MacroAllDevices{
{"-D__SYCL_ALL_DEVICES_HAVE_", TargetKey, "__=1"}};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAllDevices);
}
}

bool initialize() override {
using namespace tools::SYCL;
// Get the SYCL toolchains. If we don't get any, the action builder will
Expand Down Expand Up @@ -6563,7 +6467,17 @@ class OffloadingActionBuilder final {
// Define macros associated with `any_device_has/all_devices_have`
// according to the aspects defined in the DeviceConfigFile for the SYCL
// targets.
populateSYCLDeviceTraitsMacrosArgs(C, Args, SYCLTargetInfoList);
// We are using the Traits population function in multiple offloading
// models. These use different containers for the toolchain and arch
// values. Convert the list for usage with the new model expectations.
SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs;
for (auto &TargetInfo : SYCLTargetInfoList) {
const ToolChain *TC = TargetInfo.TC;
StringRef Arch(TargetInfo.BoundArch);
std::pair<const ToolChain *, StringRef> TCAndArch(TC, Arch);
TCAndArchs.push_back(TCAndArch);
}
tools::SYCL::populateSYCLDeviceTraitsMacrosArgs(C, Args, TCAndArchs);

DeviceLinkerInputs.resize(SYCLTargetInfoList.size());
return false;
Expand Down Expand Up @@ -8003,6 +7917,10 @@ Action *Driver::BuildOffloadingActions(Compilation &C,

++TCAndArch;
}
// For SYCL based offloading, populate the device traits macros that are
// used during compilation.
if (Kind == Action::OFK_SYCL)
tools::SYCL::populateSYCLDeviceTraitsMacrosArgs(C, Args, TCAndArchs);
}

// HIP code in non-RDC mode will bundle the output if it invoked the linker.
Expand Down
95 changes: 95 additions & 0 deletions clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/SYCLLowerIR/DeviceConfigFile.hpp"
#include <algorithm>
#include <sstream>

Expand Down Expand Up @@ -384,6 +385,100 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
return LibraryList;
}

/// Reads device config file to find information about the SYCL targets in
/// `Targets`, and defines device traits macros accordingly.
void SYCL::populateSYCLDeviceTraitsMacrosArgs(
Compilation &C, const llvm::opt::ArgList &Args,
const SmallVectorImpl<std::pair<const ToolChain *, StringRef>> &Targets) {
if (Targets.empty())
return;

const auto &TargetTable = DeviceConfigFile::TargetTable;
std::map<StringRef, unsigned int> AllDevicesHave;
std::map<StringRef, bool> AnyDeviceHas;
bool AnyDeviceHasAnyAspect = false;
unsigned int ValidTargets = 0;
for (const auto &[TC, BoundArch] : Targets) {
assert(TC && "Invalid SYCL Offload Toolchain");
// Try and find the device arch, if it's empty, try to search for either
// the whole Triple or just the 'ArchName' string.
auto TargetIt = TargetTable.end();
const llvm::Triple &TargetTriple = TC->getTriple();
const StringRef TargetArch{BoundArch};
if (!TargetArch.empty()) {
TargetIt = llvm::find_if(TargetTable, [&](const auto &Value) {
using namespace tools::SYCL;
StringRef Device{Value.first};
if (Device.consume_front(gen::AmdGPU))
return TargetArch == Device && TargetTriple.isAMDGCN();
if (Device.consume_front(gen::NvidiaGPU))
return TargetArch == Device && TargetTriple.isNVPTX();
if (Device.consume_front(gen::IntelGPU))
return TargetArch == Device && TargetTriple.isSPIRAOT();
return TargetArch == Device;
});
} else {
TargetIt = TargetTable.find(TargetTriple.str());
if (TargetIt == TargetTable.end())
TargetIt = TargetTable.find(TargetTriple.getArchName().str());
}

if (TargetIt != TargetTable.end()) {
const DeviceConfigFile::TargetInfo &Info = (*TargetIt).second;
++ValidTargets;
const auto &AspectList = Info.aspects;
const auto &MaySupportOtherAspects = Info.maySupportOtherAspects;
if (!AnyDeviceHasAnyAspect)
AnyDeviceHasAnyAspect = MaySupportOtherAspects;
for (const auto &Aspect : AspectList) {
// If target has an entry in the config file, the set of aspects
// supported by all devices supporting the target is 'AspectList'.
// If there's no entry, such set is empty.
const auto &AspectIt = AllDevicesHave.find(Aspect);
if (AspectIt != AllDevicesHave.end())
++AllDevicesHave[Aspect];
else
AllDevicesHave[Aspect] = 1;
// If target has an entry in the config file AND
// 'MaySupportOtherAspects' is false, the set of aspects supported
// by any device supporting the target is 'AspectList'. If there's
// no entry OR 'MaySupportOtherAspects' is true, such set contains
// all the aspects.
AnyDeviceHas[Aspect] = true;
}
}
}
// If there's no entry for the target in the device config file, the set
// of aspects supported by any device supporting the target contains all
// the aspects.
if (ValidTargets == 0)
AnyDeviceHasAnyAspect = true;

const Driver &D = C.getDriver();
if (AnyDeviceHasAnyAspect) {
// There exists some target that supports any given aspect.
constexpr static StringRef MacroAnyDeviceAnyAspect{
"-D__SYCL_ANY_DEVICE_HAS_ANY_ASPECT__=1"};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAnyDeviceAnyAspect);
} else {
// Some of the aspects are not supported at all by any of the targets.
// Thus, we need to define individual macros for each supported aspect.
for (const auto &[TargetKey, SupportedTarget] : AnyDeviceHas) {
assert(SupportedTarget);
const SmallString<64> MacroAnyDevice{
{"-D__SYCL_ANY_DEVICE_HAS_", TargetKey, "__=1"}};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAnyDevice);
}
}
for (const auto &[TargetKey, SupportedTargets] : AllDevicesHave) {
if (SupportedTargets != ValidTargets)
continue;
const SmallString<64> MacroAllDevices{
{"-D__SYCL_ALL_DEVICES_HAVE_", TargetKey, "__=1"}};
D.addSYCLDeviceTraitsMacroArg(Args, MacroAllDevices);
}
}

// The list should match pre-built SYCL device library files located in
// compiler package. Once we add or remove any SYCL device library files,
// the list should be updated accordingly.
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/SYCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ SmallVector<std::string, 8> getDeviceLibraries(const Compilation &C,
const llvm::Triple &TargetTriple,
bool IsSpirvAOT);

// Populates the SYCL device traits macros.
void populateSYCLDeviceTraitsMacrosArgs(Compilation &C,
const llvm::opt::ArgList &Args,
const SmallVectorImpl<std::pair<const ToolChain *, StringRef>> &Targets);

bool shouldDoPerObjectFileLinking(const Compilation &C);
// Runs llvm-spirv to convert spirv to bc, llvm-link, which links multiple LLVM
// bitcode. Converts generated bc back to spirv using llvm-spirv, wraps with
Expand Down
8 changes: 7 additions & 1 deletion clang/test/Driver/sycl-device-traits-macros.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// TODO: macro settings only in old offloading model
/// Check that no device traits macros are defined if sycl is disabled:
// RUN: %clang -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-DISABLED %s
Expand All @@ -11,6 +10,8 @@
/// occurrences of the macro definition, one for host and one for device.
// RUN: %clang -fsycl --no-offload-new-driver -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-ENABLED %s
// RUN: %clang -fsycl --offload-new-driver -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-ENABLED %s
// CHECK-ENABLED-COUNT-2: "-D__SYCL_ANY_DEVICE_HAS_ANY_ASPECT__=1"

/// Check device traits macros are defined if sycl is enabled:
Expand All @@ -19,6 +20,8 @@
/// definition, one for host and one for each of the two devices.
// RUN: %clang -fsycl --no-offload-new-driver -fsycl-targets=spir64,spir64_gen -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-SYCL-TARGETS %s
// RUN: %clang -fsycl --offload-new-driver -fsycl-targets=spir64,spir64_gen -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-SYCL-TARGETS %s
// CHECK-SYCL-TARGETS-COUNT-3: "-D__SYCL_ANY_DEVICE_HAS_ANY_ASPECT__=1"

/// Check device traits macros are defined if sycl is enabled:
Expand All @@ -39,6 +42,9 @@
// RUN: %clangxx -fsycl --no-offload-new-driver -nogpulib -fsycl-targets=intel_gpu_pvc,amd_gpu_gfx906 \
// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-SYCL-TARGETS-NO-MAY-SUPPORT-OTHER-ASPECTS %s
// RUN: %clangxx -fsycl --offload-new-driver -nogpulib -fsycl-targets=intel_gpu_pvc,amd_gpu_gfx906 \
// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-SYCL-TARGETS-NO-MAY-SUPPORT-OTHER-ASPECTS %s
// CHECK-SYCL-TARGETS-NO-MAY-SUPPORT-OTHER-ASPECTS-NOT: "-D__SYCL_ANY_DEVICE_HAS_ANY_ASPECT__=1"
// CHECK-SYCL-TARGETS-NO-MAY-SUPPORT-OTHER-ASPECTS: "-D__SYCL_ANY_DEVICE_HAS_[[ASPECTi:[a-z0-9_]+]]__=1"
// CHECK-SYCL-TARGETS-NO-MAY-SUPPORT-OTHER-ASPECTS: "-D__SYCL_ALL_DEVICES_HAVE_[[ASPECTj:[a-z0-9_]+]]__=1"

0 comments on commit ea0c067

Please sign in to comment.