Skip to content

Commit

Permalink
[SYCL] Add asan AOT libdevice for different GPU/CPU (#15939)
Browse files Browse the repository at this point in the history
Device address sanitizer libraries can be optimized in AOT compilation
mode, some redundant code checking which device current kernel is
running on can be removed. This PR creates corresponding AOT address
sanitizer device libraries for CPU, PVC, DG2 target and link them
according to real AOT target. This PR also renames previous
libsycl-sanitizer to libsycl-asan since current device sanitizer only
supports address sanitizer and memory sanitizer will be added in the
future.

---------

Signed-off-by: jinge90 <[email protected]>
  • Loading branch information
jinge90 authored Nov 11, 2024
1 parent 22cb417 commit 7dd09d9
Show file tree
Hide file tree
Showing 14 changed files with 460 additions and 85 deletions.
233 changes: 158 additions & 75 deletions clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,84 @@ static bool selectBfloatLibs(const llvm::Triple &Triple, const Compilation &C,
return NeedLibs;
}

struct OclocInfo {
const char *DeviceName;
const char *PackageName;
const char *Version;
SmallVector<int, 8> HexValues;
};

// The PVCDevices data structure is organized by device name, with the
// corresponding ocloc split release, version and possible Hex representations
// of various PVC devices. This information is gathered from the following:
// https://github.com/intel/compute-runtime/blob/master/shared/source/dll/devices/devices_base.inl
// https://github.com/intel/compute-runtime/blob/master/shared/source/dll/devices/devices_additional.inl
static OclocInfo PVCDevices[] = {
{"pvc-sdv", "gen12+", "12.60.1", {}},
{"pvc",
"gen12+",
"12.60.7",
{0x0BD0, 0x0BD5, 0x0BD6, 0x0BD7, 0x0BD8, 0x0BD9, 0x0BDA, 0x0BDB}}};

static std::string getDeviceArg(const ArgStringList &CmdArgs) {
bool DeviceSeen = false;
std::string DeviceArg;
for (StringRef Arg : CmdArgs) {
// -device <arg> comes in as a single arg, split up all potential space
// separated values.
SmallVector<StringRef> SplitArgs;
Arg.split(SplitArgs, ' ');
for (StringRef SplitArg : SplitArgs) {
if (DeviceSeen) {
DeviceArg = SplitArg.str();
break;
}
if (SplitArg == "-device")
DeviceSeen = true;
}
if (DeviceSeen)
break;
}

return DeviceArg;
}

static bool checkPVCDevice(std::string SingleArg, std::string &DevArg) {
// Handle shortened versions.
bool CheckShortVersion = true;
for (auto Char : SingleArg) {
if (!std::isdigit(Char) && Char != '.') {
CheckShortVersion = false;
break;
}
}
// Check for device, version or hex (literal values)
for (unsigned int I = 0; I < std::size(PVCDevices); I++) {
if (StringRef(SingleArg).equals_insensitive(PVCDevices[I].DeviceName) ||
StringRef(SingleArg).equals_insensitive(PVCDevices[I].Version)) {
DevArg = SingleArg;
return true;
}

for (int HexVal : PVCDevices[I].HexValues) {
int Value = 0;
if (!StringRef(SingleArg).getAsInteger(0, Value) && Value == HexVal) {
// TODO: Pass back the hex string to use for -device_options when
// IGC is updated to allow. Currently -device_options only accepts
// the device ID (i.e. pvc) or the version (12.60.7).
return true;
}
}
if (CheckShortVersion &&
StringRef(PVCDevices[I].Version).starts_with(SingleArg)) {
DevArg = SingleArg;
return true;
}
}

return false;
}

SmallVector<std::string, 8>
SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
bool IsSpirvAOT) {
Expand All @@ -360,6 +438,8 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
StringRef DeviceLibOption;
};

enum { JIT = 0, AOT_CPU, AOT_DG2, AOT_PVC };

// Currently, all SYCL device libraries will be linked by default.
llvm::StringMap<bool> DeviceLibLinkInfo = {
{"libc", true}, {"libm-fp32", true}, {"libm-fp64", true},
Expand Down Expand Up @@ -460,8 +540,11 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
{"libsycl-itt-compiler-wrappers", "internal"},
{"libsycl-itt-stubs", "internal"}};
#if !defined(_WIN32)
const SYCLDeviceLibsList SYCLDeviceSanitizerLibs = {
{"libsycl-sanitizer", "internal"}};
const SYCLDeviceLibsList SYCLDeviceAsanLibs = {
{"libsycl-asan", "internal"},
{"libsycl-asan-cpu", "internal"},
{"libsycl-asan-dg2", "internal"},
{"libsycl-asan-pvc", "internal"}};
#endif

const SYCLDeviceLibsList SYCLNativeCpuDeviceLibs = {
Expand Down Expand Up @@ -493,6 +576,66 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
}
};

auto addSingleLibrary = [&](const DeviceLibOptInfo &Lib) {
if (!DeviceLibLinkInfo[Lib.DeviceLibOption])
return;
SmallString<128> LibName(Lib.DeviceLibName);
llvm::sys::path::replace_extension(LibName, LibSuffix);
LibraryList.push_back(Args.MakeArgString(LibName));
};

// This function is used to check whether there is only one GPU device
// (PVC or DG2) specified in AOT compilation mode. If yes, we can use
// corresponding libsycl-asan-* to improve device sanitizer performance,
// otherwise stick to fallback device sanitizer library used in JIT mode.
auto getSpecificGPUTarget = [](const ArgStringList &CmdArgs) -> size_t {
std::string DeviceArg = getDeviceArg(CmdArgs);
if ((DeviceArg.empty()) || (DeviceArg.find(",") != std::string::npos))
return JIT;

std::string Temp;
if (checkPVCDevice(DeviceArg, Temp))
return AOT_PVC;

if (DeviceArg == "dg2")
return AOT_DG2;

return JIT;
};

auto getSingleBuildTarget = [&]() -> size_t {
if (!IsSpirvAOT)
return JIT;

llvm::opt::Arg *SYCLTarget = Args.getLastArg(options::OPT_fsycl_targets_EQ);
if (!SYCLTarget || (SYCLTarget->getValues().size() != 1))
return JIT;

StringRef SYCLTargetStr = SYCLTarget->getValue();
if (SYCLTargetStr.starts_with("spir64_x86_64"))
return AOT_CPU;

if (SYCLTargetStr == "intel_gpu_pvc")
return AOT_PVC;

if (SYCLTargetStr.starts_with("intel_gpu_dg2"))
return AOT_DG2;

if (SYCLTargetStr.starts_with("spir64_gen")) {
ArgStringList TargArgs;
Args.AddAllArgValues(TargArgs, options::OPT_Xs, options::OPT_Xs_separate);
Args.AddAllArgValues(TargArgs, options::OPT_Xsycl_backend);
llvm::opt::Arg *A = nullptr;
if ((A = Args.getLastArg(options::OPT_Xsycl_backend_EQ)) &&
StringRef(A->getValue()).starts_with("spir64_gen"))
TargArgs.push_back(A->getValue(1));

return getSpecificGPUTarget(TargArgs);
}

return JIT;
};

addLibraries(SYCLDeviceWrapperLibs);
if (IsSpirvAOT)
addLibraries(SYCLDeviceFallbackLibs);
Expand All @@ -512,13 +655,14 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
addLibraries(SYCLDeviceAnnotationLibs);

#if !defined(_WIN32)
size_t sanitizer_lib_idx = getSingleBuildTarget();
if (Arg *A = Args.getLastArg(options::OPT_fsanitize_EQ,
options::OPT_fno_sanitize_EQ)) {
if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
A->getValues().size() == 1) {
std::string SanitizeVal = A->getValue();
if (SanitizeVal == "address")
addLibraries(SYCLDeviceSanitizerLibs);
addSingleLibrary(SYCLDeviceAsanLibs[sanitizer_lib_idx]);
}
} else {
// User can pass -fsanitize=address to device compiler via
Expand Down Expand Up @@ -546,7 +690,7 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
}

if (IsDeviceAsanEnabled)
addLibraries(SYCLDeviceSanitizerLibs);
addSingleLibrary(SYCLDeviceAsanLibs[sanitizer_lib_idx]);
}
#endif

Expand Down Expand Up @@ -663,7 +807,10 @@ static llvm::SmallVector<StringRef, 16> SYCLDeviceLibList{
#if defined(_WIN32)
"msvc-math",
#else
"sanitizer",
"asan",
"asan-pvc",
"asan-cpu",
"asan-dg2",
#endif
"imf",
"imf-fp64",
Expand Down Expand Up @@ -1131,87 +1278,23 @@ void SYCL::fpga::BackendCompiler::ConstructJob(
C.addCommand(std::move(Cmd));
}

struct OclocInfo {
const char *DeviceName;
const char *PackageName;
const char *Version;
SmallVector<int, 8> HexValues;
};

// The PVCDevices data structure is organized by device name, with the
// corresponding ocloc split release, version and possible Hex representations
// of various PVC devices. This information is gathered from the following:
// https://github.com/intel/compute-runtime/blob/master/shared/source/dll/devices/devices_base.inl
// https://github.com/intel/compute-runtime/blob/master/shared/source/dll/devices/devices_additional.inl
static OclocInfo PVCDevices[] = {
{"pvc-sdv", "gen12+", "12.60.1", {}},
{"pvc",
"gen12+",
"12.60.7",
{0x0BD0, 0x0BD5, 0x0BD6, 0x0BD7, 0x0BD8, 0x0BD9, 0x0BDA, 0x0BDB}}};

// Determine if any of the given arguments contain any PVC based values for
// the -device option.
static bool hasPVCDevice(const ArgStringList &CmdArgs, std::string &DevArg) {
bool DeviceSeen = false;
StringRef DeviceArg;
for (StringRef Arg : CmdArgs) {
// -device <arg> comes in as a single arg, split up all potential space
// separated values.
SmallVector<StringRef> SplitArgs;
Arg.split(SplitArgs, ' ');
for (StringRef SplitArg : SplitArgs) {
if (DeviceSeen) {
DeviceArg = SplitArg;
break;
}
if (SplitArg == "-device")
DeviceSeen = true;
}
if (DeviceSeen)
break;
}
if (DeviceArg.empty())
std::string Res = getDeviceArg(CmdArgs);
if (Res.empty())
return false;

// Go through all of the arguments to '-device' and determine if any of these
// are pvc based. We only match literal values and will not find a match
// when ranges or wildcards are used.
// Here we parse the targets, tokenizing via ','
StringRef DeviceArg(Res.c_str());
SmallVector<StringRef> SplitArgs;
DeviceArg.split(SplitArgs, ",");
for (const auto &SingleArg : SplitArgs) {
StringRef OclocTarget;
// Handle shortened versions.
bool CheckShortVersion = true;
for (auto Char : SingleArg.str()) {
if (!std::isdigit(Char) && Char != '.') {
CheckShortVersion = false;
break;
}
}
// Check for device, version or hex (literal values)
for (unsigned int I = 0; I < std::size(PVCDevices); I++) {
if (SingleArg.equals_insensitive(PVCDevices[I].DeviceName) ||
SingleArg.equals_insensitive(PVCDevices[I].Version)) {
DevArg = SingleArg.str();
return true;
}
for (int HexVal : PVCDevices[I].HexValues) {
int Value = 0;
if (!SingleArg.getAsInteger(0, Value) && Value == HexVal) {
// TODO: Pass back the hex string to use for -device_options when
// IGC is updated to allow. Currently -device_options only accepts
// the device ID (i.e. pvc) or the version (12.60.7).
return true;
}
}
if (CheckShortVersion &&
StringRef(PVCDevices[I].Version).starts_with(SingleArg)) {
DevArg = SingleArg.str();
return true;
}
}
bool IsPVC = checkPVCDevice(SingleArg.str(), DevArg);
if (IsPVC)
return true;
}
return false;
}
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Loading

0 comments on commit 7dd09d9

Please sign in to comment.