diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index ed9637e7a443..ef9c953d86b1 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -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 &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 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 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 SYCLDeviceAsanLibs = { + "libsycl-asan", "libsycl-asan-cpu", "libsycl-asan-dg2", + "libsycl-asan-pvc"}; + const SmallVector 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 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 SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple, bool IsSpirvAOT) { @@ -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"}}; @@ -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 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 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())