@@ -426,6 +426,141 @@ static bool checkPVCDevice(std::string SingleArg, std::string &DevArg) {
426426 return false ;
427427}
428428
429+ #if !defined(_WIN32)
430+ static void
431+ addSYCLDeviceSanitizerLibs (const Compilation &C, bool IsSpirvAOT,
432+ StringRef LibSuffix,
433+ SmallVector<std::string, 8 > &LibraryList) {
434+ const llvm::opt::ArgList &Args = C.getArgs ();
435+ enum { JIT = 0 , AOT_CPU, AOT_DG2, AOT_PVC };
436+ auto addSingleLibrary = [&](StringRef DeviceLibName) {
437+ SmallString<128 > LibName (DeviceLibName);
438+ llvm::sys::path::replace_extension (LibName, LibSuffix);
439+ LibraryList.push_back (Args.MakeArgString (LibName));
440+ };
441+
442+ // This function is used to check whether there is only one GPU device
443+ // (PVC or DG2) specified in AOT compilation mode. If yes, we can use
444+ // corresponding libsycl-asan-* to improve device sanitizer performance,
445+ // otherwise stick to fallback device sanitizer library used in JIT mode.
446+ auto getSpecificGPUTarget = [](const ArgStringList &CmdArgs) -> size_t {
447+ std::string DeviceArg = getDeviceArg (CmdArgs);
448+ if ((DeviceArg.empty ()) || (DeviceArg.find (" ," ) != std::string::npos))
449+ return JIT;
450+
451+ std::string Temp;
452+ if (checkPVCDevice (DeviceArg, Temp))
453+ return AOT_PVC;
454+
455+ if (DeviceArg == " dg2" )
456+ return AOT_DG2;
457+
458+ return JIT;
459+ };
460+
461+ auto getSingleBuildTarget = [&]() -> size_t {
462+ if (!IsSpirvAOT)
463+ return JIT;
464+
465+ llvm::opt::Arg *SYCLTarget = Args.getLastArg (options::OPT_fsycl_targets_EQ);
466+ if (!SYCLTarget || (SYCLTarget->getValues ().size () != 1 ))
467+ return JIT;
468+
469+ StringRef SYCLTargetStr = SYCLTarget->getValue ();
470+ if (SYCLTargetStr.starts_with (" spir64_x86_64" ))
471+ return AOT_CPU;
472+
473+ if (SYCLTargetStr == " intel_gpu_pvc" )
474+ return AOT_PVC;
475+
476+ if (SYCLTargetStr.starts_with (" intel_gpu_dg2" ))
477+ return AOT_DG2;
478+
479+ if (SYCLTargetStr.starts_with (" spir64_gen" )) {
480+ ArgStringList TargArgs;
481+ Args.AddAllArgValues (TargArgs, options::OPT_Xs, options::OPT_Xs_separate);
482+ Args.AddAllArgValues (TargArgs, options::OPT_Xsycl_backend);
483+ llvm::opt::Arg *A = nullptr ;
484+ if ((A = Args.getLastArg (options::OPT_Xsycl_backend_EQ)) &&
485+ StringRef (A->getValue ()).starts_with (" spir64_gen" ))
486+ TargArgs.push_back (A->getValue (1 ));
487+
488+ return getSpecificGPUTarget (TargArgs);
489+ }
490+
491+ return JIT;
492+ };
493+
494+ std::string SanitizeVal;
495+ size_t sanitizer_lib_idx = getSingleBuildTarget ();
496+ if (Arg *A = Args.getLastArg (options::OPT_fsanitize_EQ,
497+ options::OPT_fno_sanitize_EQ)) {
498+ if (A->getOption ().matches (options::OPT_fsanitize_EQ) &&
499+ A->getValues ().size () == 1 ) {
500+ SanitizeVal = A->getValue ();
501+ }
502+ } else {
503+ // User can pass -fsanitize=address to device compiler via
504+ // -Xsycl-target-frontend, sanitize device library must be
505+ // linked with user's device image if so.
506+ std::vector<std::string> EnabledDeviceSanitizers;
507+
508+ // NOTE: "-fsanitize=" applies to all device targets
509+ auto SyclFEArgVals = Args.getAllArgValues (options::OPT_Xsycl_frontend);
510+ auto SyclFEEQArgVals = Args.getAllArgValues (options::OPT_Xsycl_frontend_EQ);
511+ auto ArchDeviceVals = Args.getAllArgValues (options::OPT_Xarch_device);
512+
513+ std::vector<std::string> ArgVals (
514+ SyclFEArgVals.size () + SyclFEEQArgVals.size () + ArchDeviceVals.size ());
515+ ArgVals.insert (ArgVals.end (), SyclFEArgVals.begin (), SyclFEArgVals.end ());
516+ ArgVals.insert (ArgVals.end (), SyclFEEQArgVals.begin (),
517+ SyclFEEQArgVals.end ());
518+ ArgVals.insert (ArgVals.end (), ArchDeviceVals.begin (), ArchDeviceVals.end ());
519+
520+ // Driver will report error if more than one of address sanitizer, memory
521+ // sanitizer or thread sanitizer is enabled, so we only need to check first
522+ // one here.
523+ for (const std::string &Arg : ArgVals) {
524+ if (Arg.find (" -fsanitize=address" ) != std::string::npos) {
525+ SanitizeVal = " address" ;
526+ break ;
527+ }
528+ if (Arg.find (" -fsanitize=memory" ) != std::string::npos) {
529+ SanitizeVal = " memory" ;
530+ break ;
531+ }
532+ if (Arg.find (" -fsanitize=thread" ) != std::string::npos) {
533+ SanitizeVal = " thread" ;
534+ break ;
535+ }
536+ }
537+ }
538+
539+ const SmallVector<StringRef, 5 > SYCLDeviceAsanLibs = {
540+ " libsycl-asan" , " libsycl-asan-cpu" , " libsycl-asan-dg2" ,
541+ " libsycl-asan-pvc" };
542+ const SmallVector<StringRef, 5 > SYCLDeviceMsanLibs = {
543+ " libsycl-msan" , " libsycl-msan-cpu" ,
544+ // Currently, we only provide aot msan libdevice for PVC and CPU.
545+ // For DG2, we just use libsycl-msan as placeholder.
546+ " libsycl-msan" , " libsycl-msan-pvc" };
547+ const SmallVector<StringRef, 5 > SYCLDeviceTsanLibs = {
548+ " libsycl-tsan" , " libsycl-tsan-cpu" ,
549+ // Currently, we only provide aot tsan libdevice for PVC and CPU.
550+ // For DG2, we just use libsycl-tsan as placeholder.
551+ // TODO: replace "libsycl-tsan" with "libsycl-tsan-dg2" when DG2
552+ // AOT support is added.
553+ " libsycl-tsan" , " libsycl-tsan-pvc" };
554+
555+ if (SanitizeVal == " address" )
556+ addSingleLibrary (SYCLDeviceAsanLibs[sanitizer_lib_idx]);
557+ else if (SanitizeVal == " memory" )
558+ addSingleLibrary (SYCLDeviceMsanLibs[sanitizer_lib_idx]);
559+ else if (SanitizeVal == " thread" )
560+ addSingleLibrary (SYCLDeviceTsanLibs[sanitizer_lib_idx]);
561+ }
562+ #endif
563+
429564SmallVector<std::string, 8 >
430565SYCL::getDeviceLibraries (const Compilation &C, const llvm::Triple &TargetTriple,
431566 bool IsSpirvAOT) {
@@ -551,30 +686,6 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
551686 {" libsycl-itt-user-wrappers" , " internal" },
552687 {" libsycl-itt-compiler-wrappers" , " internal" },
553688 {" libsycl-itt-stubs" , " internal" }};
554- #if !defined(_WIN32)
555- const SYCLDeviceLibsList SYCLDeviceAsanLibs = {
556- {" libsycl-asan" , " internal" },
557- {" libsycl-asan-cpu" , " internal" },
558- {" libsycl-asan-dg2" , " internal" },
559- {" libsycl-asan-pvc" , " internal" }};
560- const SYCLDeviceLibsList SYCLDeviceMsanLibs = {
561- {" libsycl-msan" , " internal" },
562- {" libsycl-msan-cpu" , " internal" },
563- // Currently, we only provide aot msan libdevice for PVC and CPU.
564- // For DG2, we just use libsycl-msan as placeholder.
565- {" libsycl-msan" , " internal" },
566- {" libsycl-msan-pvc" , " internal" }};
567- const SYCLDeviceLibsList SYCLDeviceTsanLibs = {
568- {" libsycl-tsan" , " internal" },
569- {" libsycl-tsan-cpu" , " internal" },
570- // Currently, we only provide aot tsan libdevice for PVC and CPU.
571- // For DG2, we just use libsycl-tsan as placeholder.
572- // TODO: replace "libsycl-tsan" with "libsycl-tsan-dg2" when DG2
573- // AOT support is added.
574- {" libsycl-tsan" , " internal" },
575- {" libsycl-tsan-pvc" , " internal" }};
576- #endif
577-
578689 const SYCLDeviceLibsList SYCLNativeCpuDeviceLibs = {
579690 {" libsycl-nativecpu_utils" , " internal" }};
580691
@@ -616,119 +727,11 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
616727 options::OPT_fno_sycl_instrument_device_code, true ))
617728 addLibraries (SYCLDeviceAnnotationLibs);
618729
730+ // Currently, device sanitizer support is required by some developers on
731+ // Linux platform only, so compiler only provides device sanitizer libraries
732+ // on Linux platform.
619733#if !defined(_WIN32)
620-
621- auto addSingleLibrary = [&](const DeviceLibOptInfo &Lib) {
622- if (!DeviceLibLinkInfo[Lib.DeviceLibOption ])
623- return ;
624- SmallString<128 > LibName (Lib.DeviceLibName );
625- llvm::sys::path::replace_extension (LibName, LibSuffix);
626- LibraryList.push_back (Args.MakeArgString (LibName));
627- };
628-
629- // This function is used to check whether there is only one GPU device
630- // (PVC or DG2) specified in AOT compilation mode. If yes, we can use
631- // corresponding libsycl-asan-* to improve device sanitizer performance,
632- // otherwise stick to fallback device sanitizer library used in JIT mode.
633- auto getSpecificGPUTarget = [](const ArgStringList &CmdArgs) -> size_t {
634- std::string DeviceArg = getDeviceArg (CmdArgs);
635- if ((DeviceArg.empty ()) || (DeviceArg.find (" ," ) != std::string::npos))
636- return JIT;
637-
638- std::string Temp;
639- if (checkPVCDevice (DeviceArg, Temp))
640- return AOT_PVC;
641-
642- if (DeviceArg == " dg2" )
643- return AOT_DG2;
644-
645- return JIT;
646- };
647-
648- auto getSingleBuildTarget = [&]() -> size_t {
649- if (!IsSpirvAOT)
650- return JIT;
651-
652- llvm::opt::Arg *SYCLTarget = Args.getLastArg (options::OPT_fsycl_targets_EQ);
653- if (!SYCLTarget || (SYCLTarget->getValues ().size () != 1 ))
654- return JIT;
655-
656- StringRef SYCLTargetStr = SYCLTarget->getValue ();
657- if (SYCLTargetStr.starts_with (" spir64_x86_64" ))
658- return AOT_CPU;
659-
660- if (SYCLTargetStr == " intel_gpu_pvc" )
661- return AOT_PVC;
662-
663- if (SYCLTargetStr.starts_with (" intel_gpu_dg2" ))
664- return AOT_DG2;
665-
666- if (SYCLTargetStr.starts_with (" spir64_gen" )) {
667- ArgStringList TargArgs;
668- Args.AddAllArgValues (TargArgs, options::OPT_Xs, options::OPT_Xs_separate);
669- Args.AddAllArgValues (TargArgs, options::OPT_Xsycl_backend);
670- llvm::opt::Arg *A = nullptr ;
671- if ((A = Args.getLastArg (options::OPT_Xsycl_backend_EQ)) &&
672- StringRef (A->getValue ()).starts_with (" spir64_gen" ))
673- TargArgs.push_back (A->getValue (1 ));
674-
675- return getSpecificGPUTarget (TargArgs);
676- }
677-
678- return JIT;
679- };
680-
681- std::string SanitizeVal;
682- size_t sanitizer_lib_idx = getSingleBuildTarget ();
683- if (Arg *A = Args.getLastArg (options::OPT_fsanitize_EQ,
684- options::OPT_fno_sanitize_EQ)) {
685- if (A->getOption ().matches (options::OPT_fsanitize_EQ) &&
686- A->getValues ().size () == 1 ) {
687- SanitizeVal = A->getValue ();
688- }
689- } else {
690- // User can pass -fsanitize=address to device compiler via
691- // -Xsycl-target-frontend, sanitize device library must be
692- // linked with user's device image if so.
693- std::vector<std::string> EnabledDeviceSanitizers;
694-
695- // NOTE: "-fsanitize=" applies to all device targets
696- auto SyclFEArgVals = Args.getAllArgValues (options::OPT_Xsycl_frontend);
697- auto SyclFEEQArgVals = Args.getAllArgValues (options::OPT_Xsycl_frontend_EQ);
698- auto ArchDeviceVals = Args.getAllArgValues (options::OPT_Xarch_device);
699-
700- std::vector<std::string> ArgVals (
701- SyclFEArgVals.size () + SyclFEEQArgVals.size () + ArchDeviceVals.size ());
702- ArgVals.insert (ArgVals.end (), SyclFEArgVals.begin (), SyclFEArgVals.end ());
703- ArgVals.insert (ArgVals.end (), SyclFEEQArgVals.begin (),
704- SyclFEEQArgVals.end ());
705- ArgVals.insert (ArgVals.end (), ArchDeviceVals.begin (), ArchDeviceVals.end ());
706-
707- // Driver will report error if more than one of address sanitizer, memory
708- // sanitizer or thread sanitizer is enabled, so we only need to check first
709- // one here.
710- for (const std::string &Arg : ArgVals) {
711- if (Arg.find (" -fsanitize=address" ) != std::string::npos) {
712- SanitizeVal = " address" ;
713- break ;
714- }
715- if (Arg.find (" -fsanitize=memory" ) != std::string::npos) {
716- SanitizeVal = " memory" ;
717- break ;
718- }
719- if (Arg.find (" -fsanitize=thread" ) != std::string::npos) {
720- SanitizeVal = " thread" ;
721- break ;
722- }
723- }
724- }
725-
726- if (SanitizeVal == " address" )
727- addSingleLibrary (SYCLDeviceAsanLibs[sanitizer_lib_idx]);
728- else if (SanitizeVal == " memory" )
729- addSingleLibrary (SYCLDeviceMsanLibs[sanitizer_lib_idx]);
730- else if (SanitizeVal == " thread" )
731- addSingleLibrary (SYCLDeviceTsanLibs[sanitizer_lib_idx]);
734+ addSYCLDeviceSanitizerLibs (C, IsSpirvAOT, LibSuffix, LibraryList);
732735#endif
733736
734737 if (TargetTriple.isNativeCPU ())
0 commit comments