Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
275 changes: 139 additions & 136 deletions clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,141 @@ static bool checkPVCDevice(std::string SingleArg, std::string &DevArg) {
return false;
}

#if !defined(_WIN32)
static void
addSYCLDeviceSanitizerLibs(const Compilation &C, bool IsSpirvAOT,
StringRef LibSuffix,
SmallVector<std::string, 8> &LibraryList) {
const llvm::opt::ArgList &Args = C.getArgs();
enum { JIT = 0, AOT_CPU, AOT_DG2, AOT_PVC };
auto addSingleLibrary = [&](StringRef DeviceLibName) {
SmallString<128> LibName(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;
};

std::string SanitizeVal;
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) {
SanitizeVal = A->getValue();
}
} else {
// User can pass -fsanitize=address to device compiler via
// -Xsycl-target-frontend, sanitize device library must be
// linked with user's device image if so.
std::vector<std::string> EnabledDeviceSanitizers;

// NOTE: "-fsanitize=" applies to all device targets
auto SyclFEArgVals = Args.getAllArgValues(options::OPT_Xsycl_frontend);
auto SyclFEEQArgVals = Args.getAllArgValues(options::OPT_Xsycl_frontend_EQ);
auto ArchDeviceVals = Args.getAllArgValues(options::OPT_Xarch_device);

std::vector<std::string> ArgVals(
SyclFEArgVals.size() + SyclFEEQArgVals.size() + ArchDeviceVals.size());
ArgVals.insert(ArgVals.end(), SyclFEArgVals.begin(), SyclFEArgVals.end());
ArgVals.insert(ArgVals.end(), SyclFEEQArgVals.begin(),
SyclFEEQArgVals.end());
ArgVals.insert(ArgVals.end(), ArchDeviceVals.begin(), ArchDeviceVals.end());

// Driver will report error if more than one of address sanitizer, memory
// sanitizer or thread sanitizer is enabled, so we only need to check first
// one here.
for (const std::string &Arg : ArgVals) {
if (Arg.find("-fsanitize=address") != std::string::npos) {
SanitizeVal = "address";
break;
}
if (Arg.find("-fsanitize=memory") != std::string::npos) {
SanitizeVal = "memory";
break;
}
if (Arg.find("-fsanitize=thread") != std::string::npos) {
SanitizeVal = "thread";
break;
}
}
}

const SmallVector<StringRef, 5> SYCLDeviceAsanLibs = {
"libsycl-asan", "libsycl-asan-cpu", "libsycl-asan-dg2",
"libsycl-asan-pvc"};
const SmallVector<StringRef, 5> SYCLDeviceMsanLibs = {
"libsycl-msan", "libsycl-msan-cpu",
// Currently, we only provide aot msan libdevice for PVC and CPU.
// For DG2, we just use libsycl-msan as placeholder.
"libsycl-msan", "libsycl-msan-pvc"};
const SmallVector<StringRef, 5> SYCLDeviceTsanLibs = {
"libsycl-tsan", "libsycl-tsan-cpu",
// Currently, we only provide aot tsan libdevice for PVC and CPU.
// For DG2, we just use libsycl-tsan as placeholder.
// TODO: replace "libsycl-tsan" with "libsycl-tsan-dg2" when DG2
// AOT support is added.
"libsycl-tsan", "libsycl-tsan-pvc"};

if (SanitizeVal == "address")
addSingleLibrary(SYCLDeviceAsanLibs[sanitizer_lib_idx]);
else if (SanitizeVal == "memory")
addSingleLibrary(SYCLDeviceMsanLibs[sanitizer_lib_idx]);
else if (SanitizeVal == "thread")
addSingleLibrary(SYCLDeviceTsanLibs[sanitizer_lib_idx]);
}
#endif

SmallVector<std::string, 8>
SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
bool IsSpirvAOT) {
Expand Down Expand Up @@ -551,30 +686,6 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
{"libsycl-itt-user-wrappers", "internal"},
{"libsycl-itt-compiler-wrappers", "internal"},
{"libsycl-itt-stubs", "internal"}};
#if !defined(_WIN32)
const SYCLDeviceLibsList SYCLDeviceAsanLibs = {
{"libsycl-asan", "internal"},
{"libsycl-asan-cpu", "internal"},
{"libsycl-asan-dg2", "internal"},
{"libsycl-asan-pvc", "internal"}};
const SYCLDeviceLibsList SYCLDeviceMsanLibs = {
{"libsycl-msan", "internal"},
{"libsycl-msan-cpu", "internal"},
// Currently, we only provide aot msan libdevice for PVC and CPU.
// For DG2, we just use libsycl-msan as placeholder.
{"libsycl-msan", "internal"},
{"libsycl-msan-pvc", "internal"}};
const SYCLDeviceLibsList SYCLDeviceTsanLibs = {
{"libsycl-tsan", "internal"},
{"libsycl-tsan-cpu", "internal"},
// Currently, we only provide aot tsan libdevice for PVC and CPU.
// For DG2, we just use libsycl-tsan as placeholder.
// TODO: replace "libsycl-tsan" with "libsycl-tsan-dg2" when DG2
// AOT support is added.
{"libsycl-tsan", "internal"},
{"libsycl-tsan-pvc", "internal"}};
#endif

const SYCLDeviceLibsList SYCLNativeCpuDeviceLibs = {
{"libsycl-nativecpu_utils", "internal"}};

Expand Down Expand Up @@ -616,119 +727,11 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
options::OPT_fno_sycl_instrument_device_code, true))
addLibraries(SYCLDeviceAnnotationLibs);

// Currently, device sanitizer support is required by some developers on
// Linux platform only, so compiler only provides device sanitizer libraries
// on Linux platform.
#if !defined(_WIN32)

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;
};

std::string SanitizeVal;
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) {
SanitizeVal = A->getValue();
}
} else {
// User can pass -fsanitize=address to device compiler via
// -Xsycl-target-frontend, sanitize device library must be
// linked with user's device image if so.
std::vector<std::string> EnabledDeviceSanitizers;

// NOTE: "-fsanitize=" applies to all device targets
auto SyclFEArgVals = Args.getAllArgValues(options::OPT_Xsycl_frontend);
auto SyclFEEQArgVals = Args.getAllArgValues(options::OPT_Xsycl_frontend_EQ);
auto ArchDeviceVals = Args.getAllArgValues(options::OPT_Xarch_device);

std::vector<std::string> ArgVals(
SyclFEArgVals.size() + SyclFEEQArgVals.size() + ArchDeviceVals.size());
ArgVals.insert(ArgVals.end(), SyclFEArgVals.begin(), SyclFEArgVals.end());
ArgVals.insert(ArgVals.end(), SyclFEEQArgVals.begin(),
SyclFEEQArgVals.end());
ArgVals.insert(ArgVals.end(), ArchDeviceVals.begin(), ArchDeviceVals.end());

// Driver will report error if more than one of address sanitizer, memory
// sanitizer or thread sanitizer is enabled, so we only need to check first
// one here.
for (const std::string &Arg : ArgVals) {
if (Arg.find("-fsanitize=address") != std::string::npos) {
SanitizeVal = "address";
break;
}
if (Arg.find("-fsanitize=memory") != std::string::npos) {
SanitizeVal = "memory";
break;
}
if (Arg.find("-fsanitize=thread") != std::string::npos) {
SanitizeVal = "thread";
break;
}
}
}

if (SanitizeVal == "address")
addSingleLibrary(SYCLDeviceAsanLibs[sanitizer_lib_idx]);
else if (SanitizeVal == "memory")
addSingleLibrary(SYCLDeviceMsanLibs[sanitizer_lib_idx]);
else if (SanitizeVal == "thread")
addSingleLibrary(SYCLDeviceTsanLibs[sanitizer_lib_idx]);
addSYCLDeviceSanitizerLibs(C, IsSpirvAOT, LibSuffix, LibraryList);
#endif

if (TargetTriple.isNativeCPU())
Expand Down