https://github.com/srividya-sundaram updated https://github.com/llvm/llvm-project/pull/194744
>From c83935594b5bcdd2a7744fcd0d4527b7e8734e4f Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 28 Apr 2026 15:01:38 -0700 Subject: [PATCH 1/8] [Driver][SYCL][Windows] Add runtime library linking with CRT validation, phase1 --- .../clang/Basic/DiagnosticDriverKinds.td | 5 + clang/include/clang/Options/Options.td | 2 + clang/lib/Driver/ToolChains/MSVC.cpp | 108 +++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 469045948a47c..690228317e2be 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -93,6 +93,11 @@ def err_drv_hipspv_no_hip_path : Error< "'--hip-path' must be specified when offloading to SPIR-V unless '-nogpuinc' " "is given">; +// SYCL Windows-specific diagnostics +def err_drv_sycl_requires_dynamic_crt : Error< + "SYCL requires dynamic C++ runtime (/MD or /MDd); " + "static C++ runtime (/MT or /MTd) is not supported">; + def err_drv_no_spv_tools : Error<"cannot find SPIR-V Tools binary '%0', which " "is required for SPIR-V compilation. " "It can be obtained from your system package " diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index c16c41ad4057d..9bc8c981cb014 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -7566,6 +7566,8 @@ def fsycl : Flag<["-"], "fsycl">, HelpText<"Enable SYCL C++ extensions">; def fno_sycl : Flag<["-"], "fno-sycl">, HelpText<"Disable SYCL C++ extensions">; +def nolibsycl : Flag<["-"], "nolibsycl">, + HelpText<"Do not link the SYCL runtime library">; def fsycl_device_only : Flag<["-"], "fsycl-device-only">, Alias<offload_device_only>, HelpText<"Compile SYCL code for device only">; def fsycl_host_only : Flag<["-"], "fsycl-host-only">, diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index f57440855fce4..2e052f6e282b1 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -85,9 +85,109 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath")); } + // ========================================================================== + // SYCL: Auto-add /MD if no C++ runtime specified + // SYCL requires dynamic C++ runtime because STL objects cross DLL boundaries + // This must happen BEFORE other CRT handling logic + // ========================================================================== + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_nolibsycl) && + !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nostartfiles)) { + + bool HasExplicitCRT = false; + + // Check if user already specified a CRT flag + if (Args.hasArg(options::OPT__SLASH_MT) || + Args.hasArg(options::OPT__SLASH_MTd) || + Args.hasArg(options::OPT__SLASH_MD) || + Args.hasArg(options::OPT__SLASH_MDd) || + Args.hasArg(options::OPT_fms_runtime_lib_EQ)) + HasExplicitCRT = true; + + // Auto-add /MD if no CRT specified (makes dynamic CRT the default for SYCL) + if (!HasExplicitCRT) { + CmdArgs.push_back("/MD"); + } + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { - CmdArgs.push_back("-defaultlib:libcmt"); + + // ======================================================================== + // SYCL: Validate CRT compatibility and add SYCL runtime libraries + // ======================================================================== + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_nolibsycl)) { + + // ---------------------------------------------------------------------- + // STEP 1: Validate that static CRT is not being used + // ---------------------------------------------------------------------- + bool HasStaticCRT = false; + + // Check for explicit /MT or /MTd flags + if (Args.hasArg(options::OPT__SLASH_MT) || + Args.hasArg(options::OPT__SLASH_MTd)) { + HasStaticCRT = true; + } + + // Check -fms-runtime-lib flag + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeLib = A->getValue(); + if (RuntimeLib == "static" || RuntimeLib == "static_dbg") { + HasStaticCRT = true; + } + } + + // Reject static CRT with SYCL + if (HasStaticCRT) { + TC.getDriver().Diag(diag::err_drv_sycl_requires_dynamic_crt); + // Continue to show other potential errors, but skip SYCL library + // linking + } else { + // -------------------------------------------------------------------- + // STEP 2: Add SYCL library search path + // -------------------------------------------------------------------- + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + TC.getDriver().Dir + "/../lib")); + + // -------------------------------------------------------------------- + // STEP 3: Determine if this is a debug build + // Only check DYNAMIC CRT flags (/MDd), never static (/MTd) + // -------------------------------------------------------------------- + bool IsDebugBuild = false; + + // Method 1: Check -fms-runtime-lib=dll_dbg + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeVal = A->getValue(); + if (RuntimeVal == "dll_dbg") + IsDebugBuild = true; + } + + // Method 2: Check for /MDd flag (dynamic debug CRT) + if (Args.hasArg(options::OPT__SLASH_MDd)) + IsDebugBuild = true; + + // -------------------------------------------------------------------- + // STEP 4: Add appropriate SYCL runtime library + // Using LLVMSYCL for LLVM naming convention + // -------------------------------------------------------------------- + if (IsDebugBuild) { + // Debug build: link debug SYCL runtime + CmdArgs.push_back("-defaultlib:LLVMSYCLd.lib"); + } else { + // Release build: link release SYCL runtime + CmdArgs.push_back("-defaultlib:LLVMSYCL.lib"); + } + + // Add msvcrt for SYCL (dynamic CRT) + CmdArgs.push_back("-defaultlib:msvcrt"); + } + } else { + // Original logic for non-SYCL builds + CmdArgs.push_back("-defaultlib:libcmt"); + } + CmdArgs.push_back("-defaultlib:oldnames"); } @@ -162,6 +262,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getVFS().exists(CRTPath)) CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath)); + // ========================================================================== + // SYCL: Suppress LNK4078 warning (multiple .llvm.offloading sections) + // ========================================================================== + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) + CmdArgs.push_back("/IGNORE:4078"); + CmdArgs.push_back("-nologo"); if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) >From 0e6636be0f146b5f0eaa09823b4cd8592235b97c Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 28 Apr 2026 15:28:43 -0700 Subject: [PATCH 2/8] Add SYCL RT lib path for windows and test. --- clang/lib/Driver/ToolChains/SYCL.cpp | 65 ++++++++++++++++++++-------- clang/test/Driver/sycl-windows.cpp | 65 ++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 clang/test/Driver/sycl-windows.cpp diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 55a697df5081e..7e7c1d6a31d6a 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -23,25 +23,52 @@ SYCLInstallationDetector::SYCLInstallationDetector( // directory in SYCLRTLibPath for use by the linker. StringRef SysRoot = D.SysRoot; SmallString<128> DriverDir(D.Dir); - SmallString<128> LibPath(DriverDir); - llvm::sys::path::append(LibPath, "..", "lib", HostTriple.str(), - "libLLVMSYCL.so"); - // Flat lib path for LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF builds, - // where the library is installed directly in lib/ with no triple subdir. - SmallString<128> FlatLibPath(DriverDir); - llvm::sys::path::append(FlatLibPath, "..", "lib", "libLLVMSYCL.so"); - - if (DriverDir.starts_with(SysRoot) && - Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { - // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON: library is in lib/<triple>/ - if (D.getVFS().exists(LibPath)) - llvm::sys::path::append(DriverDir, "..", "lib", HostTriple.str()); - // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF: library is in lib/ - else if (D.getVFS().exists(FlatLibPath)) - llvm::sys::path::append(DriverDir, "..", "lib"); - else - return; // Neither path exists : broken install, leave SYCLRTLibPath unset - SYCLRTLibPath = DriverDir; + + if (HostTriple.isOSWindows()) { + // ======================================================================== + // Windows: Check for LLVMSYCL.lib + // NOTE: Only checks for release library; debug variant is selected via + // CRT flags in MSVC.cpp, not filesystem detection + // ======================================================================== + if (DriverDir.starts_with(SysRoot) && + Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { + SmallString<128> LibDir(DriverDir); + llvm::sys::path::append(LibDir, "..", "lib"); + + // Verify SYCL runtime library exists + SmallString<256> SYCLLibPath(LibDir); + llvm::sys::path::append(SYCLLibPath, "LLVMSYCL.lib"); + + if (D.getVFS().exists(SYCLLibPath)) { + SYCLRTLibPath = LibDir; + } + } + } else { + // ======================================================================== + // Linux/Unix: Check for libLLVMSYCL.so (existing logic) + // ======================================================================== + SmallString<128> LibPath(DriverDir); + llvm::sys::path::append(LibPath, "..", "lib", HostTriple.str(), + "libLLVMSYCL.so"); + // Flat lib path for LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF builds, + // where the library is installed directly in lib/ with no triple subdir. + SmallString<128> FlatLibPath(DriverDir); + llvm::sys::path::append(FlatLibPath, "..", "lib", "libLLVMSYCL.so"); + + if (DriverDir.starts_with(SysRoot) && + Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { + // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON: library is in lib/<triple>/ + if (D.getVFS().exists(LibPath)) + llvm::sys::path::append(DriverDir, "..", "lib", HostTriple.str()); + // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF: library is in lib/ + else if (D.getVFS().exists(FlatLibPath)) + llvm::sys::path::append(DriverDir, "..", "lib"); + else + return; // Neither path exists : broken install, leave SYCLRTLibPath + // unset + + SYCLRTLibPath = DriverDir; + } } } diff --git a/clang/test/Driver/sycl-windows.cpp b/clang/test/Driver/sycl-windows.cpp new file mode 100644 index 0000000000000..4fae8da6d0f37 --- /dev/null +++ b/clang/test/Driver/sycl-windows.cpp @@ -0,0 +1,65 @@ +/// Windows SYCL runtime library linking tests + + +/// Test 1: Auto-/MD is added when no CRT specified +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-AUTO-MD %s +// CHECK-AUTO-MD: "/MD" +// CHECK-AUTO-MD: "-defaultlib:LLVMSYCL.lib" + +/// Test 2: /MT is rejected with clear error +// RUN: not %clang_cl -fsycl /MT --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-MT-ERROR %s +// CHECK-MT-ERROR: error: SYCL requires dynamic C++ runtime + +/// Test 3: /MTd is also rejected +// RUN: not %clang_cl -fsycl /MTd --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-MTD-ERROR %s +// CHECK-MTD-ERROR: error: SYCL requires dynamic C++ runtime + +/// Test 4: /MD uses release library +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-RELEASE %s +// CHECK-RELEASE: "-defaultlib:LLVMSYCL.lib" +// CHECK-RELEASE-NOT: LLVMSYCLd.lib + +/// Test 5: /MDd uses debug library +// RUN: %clang_cl -### -fsycl /MDd --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-DEBUG %s +// CHECK-DEBUG: "-defaultlib:LLVMSYCLd.lib" +// CHECK-DEBUG-NOT: "-defaultlib:LLVMSYCL.lib" + +/// Test 6: -fms-runtime-lib=static is rejected +// RUN: not %clang_cl -fsycl -fms-runtime-lib=static \ +// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-STATIC-ERROR %s +// CHECK-STATIC-ERROR: error: SYCL requires dynamic C++ runtime + +/// Test 7: -fms-runtime-lib=dll_dbg uses debug library +// RUN: %clang_cl -### -fsycl -fms-runtime-lib=dll_dbg \ +// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-FLAG-DEBUG %s +// CHECK-FLAG-DEBUG: "-defaultlib:LLVMSYCLd.lib" + +/// Test 8: LNK4078 warning is suppressed +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-IGNORE %s +// CHECK-IGNORE: "/IGNORE:4078" + +/// Test 9: -nolibsycl skips library linking and CRT check +// RUN: %clang_cl -### -fsycl -nolibsycl /MT \ +// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-NOLIBSYCL %s +// CHECK-NOLIBSYCL-NOT: error: +// CHECK-NOLIBSYCL-NOT: "-defaultlib:LLVMSYCL + +/// Test 10: Explicit /MD doesn't cause duplicate flag +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-NO-DUP %s +// CHECK-NO-DUP: "/MD" +// CHECK-NO-DUP-NOT: "/MD"{{.*}}"/MD" + +/// Test 11: Library search path is added +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-LIBPATH %s +// CHECK-LIBPATH: "-libpath:{{.*}}{{[/\\]+}}lib" >From 4479f02c843373eb3dc7c11f1215124dec3328d4 Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 28 Apr 2026 15:51:35 -0700 Subject: [PATCH 3/8] Update test. --- clang/lib/Driver/ToolChains/MSVC.cpp | 124 +++++++++++++-------------- clang/test/Driver/sycl-windows.cpp | 9 +- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 2e052f6e282b1..4b0fa4627980f 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -111,83 +111,81 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && - !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { + // ========================================================================== + // SYCL: Validate CRT compatibility and add SYCL runtime libraries + // This needs to run for both CL mode and regular mode + // ========================================================================== + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_nolibsycl) && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - // ======================================================================== - // SYCL: Validate CRT compatibility and add SYCL runtime libraries - // ======================================================================== - if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && - !Args.hasArg(options::OPT_nolibsycl)) { + // ------------------------------------------------------------------------ + // STEP 1: Validate that static CRT is not being used + // ------------------------------------------------------------------------ + bool HasStaticCRT = false; - // ---------------------------------------------------------------------- - // STEP 1: Validate that static CRT is not being used - // ---------------------------------------------------------------------- - bool HasStaticCRT = false; + // Check for explicit /MT or /MTd flags + if (Args.hasArg(options::OPT__SLASH_MT) || + Args.hasArg(options::OPT__SLASH_MTd)) { + HasStaticCRT = true; + } - // Check for explicit /MT or /MTd flags - if (Args.hasArg(options::OPT__SLASH_MT) || - Args.hasArg(options::OPT__SLASH_MTd)) { + // Check -fms-runtime-lib flag + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeLib = A->getValue(); + if (RuntimeLib == "static" || RuntimeLib == "static_dbg") { HasStaticCRT = true; } + } - // Check -fms-runtime-lib flag - if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { - StringRef RuntimeLib = A->getValue(); - if (RuntimeLib == "static" || RuntimeLib == "static_dbg") { - HasStaticCRT = true; - } - } + // Reject static CRT with SYCL + if (HasStaticCRT) { + TC.getDriver().Diag(diag::err_drv_sycl_requires_dynamic_crt); + // Continue to show other potential errors, but skip SYCL library linking + } else { + // ---------------------------------------------------------------------- + // STEP 2: Add SYCL library search path + // ---------------------------------------------------------------------- + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + TC.getDriver().Dir + "/../lib")); - // Reject static CRT with SYCL - if (HasStaticCRT) { - TC.getDriver().Diag(diag::err_drv_sycl_requires_dynamic_crt); - // Continue to show other potential errors, but skip SYCL library - // linking - } else { - // -------------------------------------------------------------------- - // STEP 2: Add SYCL library search path - // -------------------------------------------------------------------- - CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - TC.getDriver().Dir + "/../lib")); - - // -------------------------------------------------------------------- - // STEP 3: Determine if this is a debug build - // Only check DYNAMIC CRT flags (/MDd), never static (/MTd) - // -------------------------------------------------------------------- - bool IsDebugBuild = false; - - // Method 1: Check -fms-runtime-lib=dll_dbg - if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { - StringRef RuntimeVal = A->getValue(); - if (RuntimeVal == "dll_dbg") - IsDebugBuild = true; - } + // ---------------------------------------------------------------------- + // STEP 3: Determine if this is a debug build + // Only check DYNAMIC CRT flags (/MDd), never static (/MTd) + // ---------------------------------------------------------------------- + bool IsDebugBuild = false; - // Method 2: Check for /MDd flag (dynamic debug CRT) - if (Args.hasArg(options::OPT__SLASH_MDd)) + // Method 1: Check -fms-runtime-lib=dll_dbg + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeVal = A->getValue(); + if (RuntimeVal == "dll_dbg") IsDebugBuild = true; + } - // -------------------------------------------------------------------- - // STEP 4: Add appropriate SYCL runtime library - // Using LLVMSYCL for LLVM naming convention - // -------------------------------------------------------------------- - if (IsDebugBuild) { - // Debug build: link debug SYCL runtime - CmdArgs.push_back("-defaultlib:LLVMSYCLd.lib"); - } else { - // Release build: link release SYCL runtime - CmdArgs.push_back("-defaultlib:LLVMSYCL.lib"); - } + // Method 2: Check for /MDd flag (dynamic debug CRT) + if (Args.hasArg(options::OPT__SLASH_MDd)) + IsDebugBuild = true; - // Add msvcrt for SYCL (dynamic CRT) - CmdArgs.push_back("-defaultlib:msvcrt"); + // ---------------------------------------------------------------------- + // STEP 4: Add appropriate SYCL runtime library + // Using LLVMSYCL for LLVM naming convention + // ---------------------------------------------------------------------- + if (IsDebugBuild) { + // Debug build: link debug SYCL runtime + CmdArgs.push_back("-defaultlib:LLVMSYCLd.lib"); + } else { + // Release build: link release SYCL runtime + CmdArgs.push_back("-defaultlib:LLVMSYCL.lib"); } - } else { - // Original logic for non-SYCL builds - CmdArgs.push_back("-defaultlib:libcmt"); + + // Add msvcrt for SYCL (dynamic CRT) + CmdArgs.push_back("-defaultlib:msvcrt"); } + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && + !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { + CmdArgs.push_back("-defaultlib:libcmt"); CmdArgs.push_back("-defaultlib:oldnames"); } diff --git a/clang/test/Driver/sycl-windows.cpp b/clang/test/Driver/sycl-windows.cpp index 4fae8da6d0f37..86c09c4014cff 100644 --- a/clang/test/Driver/sycl-windows.cpp +++ b/clang/test/Driver/sycl-windows.cpp @@ -53,11 +53,12 @@ // CHECK-NOLIBSYCL-NOT: error: // CHECK-NOLIBSYCL-NOT: "-defaultlib:LLVMSYCL -/// Test 10: Explicit /MD doesn't cause duplicate flag +/// Test 10: Explicit /MD results in correct libraries // RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc %s 2>&1 \ -// RUN: | FileCheck -check-prefix=CHECK-NO-DUP %s -// CHECK-NO-DUP: "/MD" -// CHECK-NO-DUP-NOT: "/MD"{{.*}}"/MD" +// RUN: | FileCheck -check-prefix=CHECK-EXPLICIT-MD %s +// CHECK-EXPLICIT-MD: clang-linker-wrapper" +// CHECK-EXPLICIT-MD-SAME: "-defaultlib:LLVMSYCL.lib" +// CHECK-EXPLICIT-MD-SAME: "-defaultlib:msvcrt" /// Test 11: Library search path is added // RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ >From 5472767ebbcce78ba79912c4be36d336140548fb Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 5 May 2026 15:39:42 -0700 Subject: [PATCH 4/8] Embeds SYCL library dependency via `--dependent-lib` at compiler stage. --- clang/lib/Driver/ToolChains/Clang.cpp | 26 +++++++++ clang/lib/Driver/ToolChains/MSVC.cpp | 76 ++++++--------------------- clang/lib/Driver/ToolChains/SYCL.cpp | 6 +-- clang/test/Driver/sycl-windows.cpp | 65 +++++++++++++---------- 4 files changed, 80 insertions(+), 93 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index cfa3031431498..be6803c2c3b09 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4911,6 +4911,32 @@ static void ProcessVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("--dependent-lib=oldnames"); } + // SYCL: Add SYCL runtime library dependency + // SYCL runtime is a required dependency similar to CRT, so we use + // --dependent-lib to embed it in the object file metadata + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_nolibsycl) && + !Args.hasArg(options::OPT_fms_omit_default_lib)) { + + // Determine debug vs release based on CRT flags + bool IsDebugBuild = false; + + // Check -fms-runtime-lib=dll_dbg + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeVal = A->getValue(); + if (RuntimeVal == "dll_dbg") + IsDebugBuild = true; + } + + // Check for /MDd flag (dynamic debug CRT) + if (Args.hasArg(options::OPT__SLASH_MDd)) + IsDebugBuild = true; + + // Add appropriate SYCL runtime library dependency + CmdArgs.push_back(IsDebugBuild ? "--dependent-lib=LLVMSYCLd" + : "--dependent-lib=LLVMSYCL"); + } + // All Arm64EC object files implicitly add softintrin.lib. This is necessary // even if the file doesn't actually refer to any of the routines because // the CRT itself has incomplete dependency markings. diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 4b0fa4627980f..8af89949da7cf 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -85,11 +85,9 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath")); } - // ========================================================================== // SYCL: Auto-add /MD if no C++ runtime specified // SYCL requires dynamic C++ runtime because STL objects cross DLL boundaries // This must happen BEFORE other CRT handling logic - // ========================================================================== if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && !Args.hasArg(options::OPT_nolibsycl) && !Args.hasArg(options::OPT_nostdlib) && @@ -111,75 +109,31 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - // ========================================================================== - // SYCL: Validate CRT compatibility and add SYCL runtime libraries - // This needs to run for both CL mode and regular mode - // ========================================================================== + // SYCL requires dynamic CRT because STL objects cross DLL boundaries. + // Library dependency is added via --dependent-lib at compiler stage. + // Here we validate CRT compatibility and add the library search path. if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && !Args.hasArg(options::OPT_nolibsycl) && !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - // ------------------------------------------------------------------------ - // STEP 1: Validate that static CRT is not being used - // ------------------------------------------------------------------------ - bool HasStaticCRT = false; + // Check if static CRT is being used. + bool HasStaticCRT = Args.hasArg(options::OPT__SLASH_MT) || + Args.hasArg(options::OPT__SLASH_MTd); - // Check for explicit /MT or /MTd flags - if (Args.hasArg(options::OPT__SLASH_MT) || - Args.hasArg(options::OPT__SLASH_MTd)) { - HasStaticCRT = true; - } - - // Check -fms-runtime-lib flag if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { StringRef RuntimeLib = A->getValue(); - if (RuntimeLib == "static" || RuntimeLib == "static_dbg") { + if (RuntimeLib == "static" || RuntimeLib == "static_dbg") HasStaticCRT = true; - } } - // Reject static CRT with SYCL if (HasStaticCRT) { TC.getDriver().Diag(diag::err_drv_sycl_requires_dynamic_crt); - // Continue to show other potential errors, but skip SYCL library linking } else { - // ---------------------------------------------------------------------- - // STEP 2: Add SYCL library search path - // ---------------------------------------------------------------------- - CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - TC.getDriver().Dir + "/../lib")); - - // ---------------------------------------------------------------------- - // STEP 3: Determine if this is a debug build - // Only check DYNAMIC CRT flags (/MDd), never static (/MTd) - // ---------------------------------------------------------------------- - bool IsDebugBuild = false; - - // Method 1: Check -fms-runtime-lib=dll_dbg - if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { - StringRef RuntimeVal = A->getValue(); - if (RuntimeVal == "dll_dbg") - IsDebugBuild = true; - } - - // Method 2: Check for /MDd flag (dynamic debug CRT) - if (Args.hasArg(options::OPT__SLASH_MDd)) - IsDebugBuild = true; - - // ---------------------------------------------------------------------- - // STEP 4: Add appropriate SYCL runtime library - // Using LLVMSYCL for LLVM naming convention - // ---------------------------------------------------------------------- - if (IsDebugBuild) { - // Debug build: link debug SYCL runtime - CmdArgs.push_back("-defaultlib:LLVMSYCLd.lib"); - } else { - // Release build: link release SYCL runtime - CmdArgs.push_back("-defaultlib:LLVMSYCL.lib"); - } - - // Add msvcrt for SYCL (dynamic CRT) - CmdArgs.push_back("-defaultlib:msvcrt"); + // Add library search path so linker can find LLVMSYCL[d].lib. + SmallString<128> LibPath(TC.getDriver().Dir); + llvm::sys::path::append(LibPath, "..", "lib"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-libpath:") + LibPath)); } } @@ -260,9 +214,9 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getVFS().exists(CRTPath)) CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath)); - // ========================================================================== - // SYCL: Suppress LNK4078 warning (multiple .llvm.offloading sections) - // ========================================================================== + // SYCL offload compilation creates .llvm.offloading sections in each object + // file to store device code and metadata. Suppress linker warning about + // multiple sections with different attributes (LNK4078). if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) CmdArgs.push_back("/IGNORE:4078"); diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 7e7c1d6a31d6a..3398036f3b54a 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -25,18 +25,16 @@ SYCLInstallationDetector::SYCLInstallationDetector( SmallString<128> DriverDir(D.Dir); if (HostTriple.isOSWindows()) { - // ======================================================================== // Windows: Check for LLVMSYCL.lib // NOTE: Only checks for release library; debug variant is selected via // CRT flags in MSVC.cpp, not filesystem detection - // ======================================================================== if (DriverDir.starts_with(SysRoot) && Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { SmallString<128> LibDir(DriverDir); llvm::sys::path::append(LibDir, "..", "lib"); // Verify SYCL runtime library exists - SmallString<256> SYCLLibPath(LibDir); + SmallString<128> SYCLLibPath(LibDir); llvm::sys::path::append(SYCLLibPath, "LLVMSYCL.lib"); if (D.getVFS().exists(SYCLLibPath)) { @@ -44,9 +42,7 @@ SYCLInstallationDetector::SYCLInstallationDetector( } } } else { - // ======================================================================== // Linux/Unix: Check for libLLVMSYCL.so (existing logic) - // ======================================================================== SmallString<128> LibPath(DriverDir); llvm::sys::path::append(LibPath, "..", "lib", HostTriple.str(), "libLLVMSYCL.so"); diff --git a/clang/test/Driver/sycl-windows.cpp b/clang/test/Driver/sycl-windows.cpp index 86c09c4014cff..14ec16fe4f63e 100644 --- a/clang/test/Driver/sycl-windows.cpp +++ b/clang/test/Driver/sycl-windows.cpp @@ -1,66 +1,77 @@ /// Windows SYCL runtime library linking tests +// +// NOTE: SYCL runtime library dependency is added at compiler stage via +// --dependent-lib (embedded in object file), similar to CRT libraries. +// Tests check for --dependent-lib in compiler (-cc1) output and +// -libpath: in linker output. - -/// Test 1: Auto-/MD is added when no CRT specified -// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +/// Test 1: Auto-/MD and release library dependency +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-AUTO-MD %s -// CHECK-AUTO-MD: "/MD" -// CHECK-AUTO-MD: "-defaultlib:LLVMSYCL.lib" +// CHECK-AUTO-MD: "-cc1" +// CHECK-AUTO-MD: "--dependent-lib=LLVMSYCL" +// CHECK-AUTO-MD: clang-linker-wrapper" +// CHECK-AUTO-MD-SAME: "/MD" +// CHECK-AUTO-MD-SAME: "-libpath:{{.*}}{{[/\\]+}}lib" /// Test 2: /MT is rejected with clear error -// RUN: not %clang_cl -fsycl /MT --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: not %clang_cl -fsycl /MT --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-MT-ERROR %s // CHECK-MT-ERROR: error: SYCL requires dynamic C++ runtime /// Test 3: /MTd is also rejected -// RUN: not %clang_cl -fsycl /MTd --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: not %clang_cl -fsycl /MTd --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-MTD-ERROR %s // CHECK-MTD-ERROR: error: SYCL requires dynamic C++ runtime /// Test 4: /MD uses release library -// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-RELEASE %s -// CHECK-RELEASE: "-defaultlib:LLVMSYCL.lib" -// CHECK-RELEASE-NOT: LLVMSYCLd.lib +// CHECK-RELEASE: "-cc1" +// CHECK-RELEASE: "--dependent-lib=LLVMSYCL" +// CHECK-RELEASE-NOT: LLVMSYCLd /// Test 5: /MDd uses debug library -// RUN: %clang_cl -### -fsycl /MDd --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: %clang_cl -### -fsycl /MDd --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-DEBUG %s -// CHECK-DEBUG: "-defaultlib:LLVMSYCLd.lib" -// CHECK-DEBUG-NOT: "-defaultlib:LLVMSYCL.lib" +// CHECK-DEBUG: "-cc1" +// CHECK-DEBUG: "--dependent-lib=LLVMSYCLd" +// CHECK-DEBUG-NOT: "--dependent-lib=LLVMSYCL" /// Test 6: -fms-runtime-lib=static is rejected // RUN: not %clang_cl -fsycl -fms-runtime-lib=static \ -// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-STATIC-ERROR %s // CHECK-STATIC-ERROR: error: SYCL requires dynamic C++ runtime /// Test 7: -fms-runtime-lib=dll_dbg uses debug library // RUN: %clang_cl -### -fsycl -fms-runtime-lib=dll_dbg \ -// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-FLAG-DEBUG %s -// CHECK-FLAG-DEBUG: "-defaultlib:LLVMSYCLd.lib" +// CHECK-FLAG-DEBUG: "-cc1" +// CHECK-FLAG-DEBUG: "--dependent-lib=LLVMSYCLd" /// Test 8: LNK4078 warning is suppressed -// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-IGNORE %s +// CHECK-IGNORE: clang-linker-wrapper" // CHECK-IGNORE: "/IGNORE:4078" -/// Test 9: -nolibsycl skips library linking and CRT check +/// Test 9: -nolibsycl skips library dependency and CRT check // RUN: %clang_cl -### -fsycl -nolibsycl /MT \ -// RUN: --target=x86_64-pc-windows-msvc %s 2>&1 \ +// RUN: --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-NOLIBSYCL %s // CHECK-NOLIBSYCL-NOT: error: -// CHECK-NOLIBSYCL-NOT: "-defaultlib:LLVMSYCL +// CHECK-NOLIBSYCL-NOT: "--dependent-lib=LLVMSYCL" -/// Test 10: Explicit /MD results in correct libraries -// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc %s 2>&1 \ +/// Test 10: Explicit /MD results in correct library +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-EXPLICIT-MD %s -// CHECK-EXPLICIT-MD: clang-linker-wrapper" -// CHECK-EXPLICIT-MD-SAME: "-defaultlib:LLVMSYCL.lib" -// CHECK-EXPLICIT-MD-SAME: "-defaultlib:msvcrt" +// CHECK-EXPLICIT-MD: "-cc1" +// CHECK-EXPLICIT-MD: "--dependent-lib=LLVMSYCL" -/// Test 11: Library search path is added -// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc %s 2>&1 \ +/// Test 11: Library search path is added at linker stage +// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-LIBPATH %s +// CHECK-LIBPATH: clang-linker-wrapper" // CHECK-LIBPATH: "-libpath:{{.*}}{{[/\\]+}}lib" >From 5536e79a31d08d38de99abf6b7356f110f91806f Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 5 May 2026 15:45:23 -0700 Subject: [PATCH 5/8] Clang format. --- clang/lib/Driver/ToolChains/MSVC.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 8af89949da7cf..66afcc45c0ed5 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -132,8 +132,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add library search path so linker can find LLVMSYCL[d].lib. SmallString<128> LibPath(TC.getDriver().Dir); llvm::sys::path::append(LibPath, "..", "lib"); - CmdArgs.push_back( - Args.MakeArgString(Twine("-libpath:") + LibPath)); + CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + LibPath)); } } >From 9672d4b1bd1a410b434cb49a0ba98ca433df4fa0 Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 5 May 2026 19:26:18 -0700 Subject: [PATCH 6/8] clang with MSVC target: -defaultlib: at linker stage addition. --- clang/lib/Driver/ToolChains/Clang.cpp | 9 +++-- clang/lib/Driver/ToolChains/MSVC.cpp | 55 ++++++++++++++------------- clang/lib/Driver/ToolChains/SYCL.cpp | 6 +-- clang/test/Driver/sycl-windows.cpp | 37 +++++++++++++----- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index be6803c2c3b09..984dc32b3d245 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4928,9 +4928,12 @@ static void ProcessVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, IsDebugBuild = true; } - // Check for /MDd flag (dynamic debug CRT) - if (Args.hasArg(options::OPT__SLASH_MDd)) - IsDebugBuild = true; + // Check for /MDd flag (dynamic debug CRT), use getLastArg to handle + // overriding options (e.g., /MDd /MD -> /MD wins) + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) { + if (A->getOption().matches(options::OPT__SLASH_MDd)) + IsDebugBuild = true; + } // Add appropriate SYCL runtime library dependency CmdArgs.push_back(IsDebugBuild ? "--dependent-lib=LLVMSYCLd" diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 66afcc45c0ed5..f1622bb07d037 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -85,30 +85,6 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath")); } - // SYCL: Auto-add /MD if no C++ runtime specified - // SYCL requires dynamic C++ runtime because STL objects cross DLL boundaries - // This must happen BEFORE other CRT handling logic - if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && - !Args.hasArg(options::OPT_nolibsycl) && - !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { - - bool HasExplicitCRT = false; - - // Check if user already specified a CRT flag - if (Args.hasArg(options::OPT__SLASH_MT) || - Args.hasArg(options::OPT__SLASH_MTd) || - Args.hasArg(options::OPT__SLASH_MD) || - Args.hasArg(options::OPT__SLASH_MDd) || - Args.hasArg(options::OPT_fms_runtime_lib_EQ)) - HasExplicitCRT = true; - - // Auto-add /MD if no CRT specified (makes dynamic CRT the default for SYCL) - if (!HasExplicitCRT) { - CmdArgs.push_back("/MD"); - } - } - // SYCL requires dynamic CRT because STL objects cross DLL boundaries. // Library dependency is added via --dependent-lib at compiler stage. // Here we validate CRT compatibility and add the library search path. @@ -116,9 +92,9 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nolibsycl) && !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - // Check if static CRT is being used. - bool HasStaticCRT = Args.hasArg(options::OPT__SLASH_MT) || - Args.hasArg(options::OPT__SLASH_MTd); + // Check if static CRT is being used. Use getLastArg to handle overriding + // options (e.g., /MT /MD -> /MD wins). + bool HasStaticCRT = false; if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { StringRef RuntimeLib = A->getValue(); @@ -126,6 +102,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, HasStaticCRT = true; } + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) { + if (A->getOption().matches(options::OPT__SLASH_MT) || + A->getOption().matches(options::OPT__SLASH_MTd)) + HasStaticCRT = true; + } + if (HasStaticCRT) { TC.getDriver().Diag(diag::err_drv_sycl_requires_dynamic_crt); } else { @@ -140,6 +122,25 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); CmdArgs.push_back("-defaultlib:oldnames"); + + // SYCL: Add runtime library for clang (non-clang-cl) with MSVC target. + // For clang-cl, --dependent-lib is used at compiler stage instead. + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_nolibsycl)) { + bool IsDebugBuild = false; + if (const Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef RuntimeVal = A->getValue(); + if (RuntimeVal == "dll_dbg") + IsDebugBuild = true; + } + // Check for /MDd flag, use getLastArg to handle overriding options + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) { + if (A->getOption().matches(options::OPT__SLASH_MDd)) + IsDebugBuild = true; + } + CmdArgs.push_back(IsDebugBuild ? "-defaultlib:LLVMSYCLd" + : "-defaultlib:LLVMSYCL"); + } } // If the VC environment hasn't been configured (perhaps because the user diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 3398036f3b54a..1d86a548fe4e5 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -26,8 +26,8 @@ SYCLInstallationDetector::SYCLInstallationDetector( if (HostTriple.isOSWindows()) { // Windows: Check for LLVMSYCL.lib - // NOTE: Only checks for release library; debug variant is selected via - // CRT flags in MSVC.cpp, not filesystem detection + // NOTE: Only checks for LLVMSYCL.lib existence (release variant). + // Debug vs release library selection happens at link time based on CRT flags. if (DriverDir.starts_with(SysRoot) && Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { SmallString<128> LibDir(DriverDir); @@ -42,7 +42,7 @@ SYCLInstallationDetector::SYCLInstallationDetector( } } } else { - // Linux/Unix: Check for libLLVMSYCL.so (existing logic) + // Linux/Unix: Check for libLLVMSYCL.so SmallString<128> LibPath(DriverDir); llvm::sys::path::append(LibPath, "..", "lib", HostTriple.str(), "libLLVMSYCL.so"); diff --git a/clang/test/Driver/sycl-windows.cpp b/clang/test/Driver/sycl-windows.cpp index 14ec16fe4f63e..d9431a9c3beaa 100644 --- a/clang/test/Driver/sycl-windows.cpp +++ b/clang/test/Driver/sycl-windows.cpp @@ -5,14 +5,13 @@ // Tests check for --dependent-lib in compiler (-cc1) output and // -libpath: in linker output. -/// Test 1: Auto-/MD and release library dependency -// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc -- %s 2>&1 \ -// RUN: | FileCheck -check-prefix=CHECK-AUTO-MD %s -// CHECK-AUTO-MD: "-cc1" -// CHECK-AUTO-MD: "--dependent-lib=LLVMSYCL" -// CHECK-AUTO-MD: clang-linker-wrapper" -// CHECK-AUTO-MD-SAME: "/MD" -// CHECK-AUTO-MD-SAME: "-libpath:{{.*}}{{[/\\]+}}lib" +/// Test 1: /MD (explicit) and release library dependency +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc -- %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-MD %s +// CHECK-MD: "-cc1" +// CHECK-MD: "--dependent-lib=LLVMSYCL" +// CHECK-MD: clang-linker-wrapper" +// CHECK-MD-SAME: "-libpath:{{.*}}{{[/\\]+}}lib" /// Test 2: /MT is rejected with clear error // RUN: not %clang_cl -fsycl /MT --target=x86_64-pc-windows-msvc -- %s 2>&1 \ @@ -71,7 +70,27 @@ // CHECK-EXPLICIT-MD: "--dependent-lib=LLVMSYCL" /// Test 11: Library search path is added at linker stage -// RUN: %clang_cl -### -fsycl --target=x86_64-pc-windows-msvc -- %s 2>&1 \ +// RUN: %clang_cl -### -fsycl /MD --target=x86_64-pc-windows-msvc -- %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-LIBPATH %s // CHECK-LIBPATH: clang-linker-wrapper" // CHECK-LIBPATH: "-libpath:{{.*}}{{[/\\]+}}lib" + +/// Test 12: clang (non-clang-cl) with MSVC target uses -defaultlib: +// RUN: %clang -### -fsycl -fms-runtime-lib=dll --target=x86_64-pc-windows-msvc -- %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-CLANG-DEFAULTLIB %s +// CHECK-CLANG-DEFAULTLIB: clang-linker-wrapper" +// CHECK-CLANG-DEFAULTLIB: "-libpath:{{.*}}{{[/\\]+}}lib" +// CHECK-CLANG-DEFAULTLIB: "-defaultlib:LLVMSYCL" + +/// Test 13: clang with -fms-runtime-lib=dll_dbg uses debug library via -defaultlib: +// RUN: %clang -### -fsycl -fms-runtime-lib=dll_dbg --target=x86_64-pc-windows-msvc -- %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-CLANG-DEBUG %s +// CHECK-CLANG-DEBUG: clang-linker-wrapper" +// CHECK-CLANG-DEBUG: "-defaultlib:LLVMSYCLd" + +/// Test 14: Default CRT behavior - release library when no CRT flag specified +// RUN: %clang -### -fsycl -fms-runtime-lib=dll --target=x86_64-pc-windows-msvc -- %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-DEFAULT-CRT %s +// CHECK-DEFAULT-CRT: "-cc1" +// CHECK-DEFAULT-CRT: "--dependent-lib=LLVMSYCL" +// CHECK-DEFAULT-CRT-NOT: LLVMSYCLd >From d4f202a0df39727a8d7996b8ef63c21b5a85e7e5 Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Tue, 5 May 2026 20:01:20 -0700 Subject: [PATCH 7/8] Fix clang format. --- clang/lib/Driver/ToolChains/SYCL.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 1d86a548fe4e5..a03f99029b9bc 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -27,7 +27,8 @@ SYCLInstallationDetector::SYCLInstallationDetector( if (HostTriple.isOSWindows()) { // Windows: Check for LLVMSYCL.lib // NOTE: Only checks for LLVMSYCL.lib existence (release variant). - // Debug vs release library selection happens at link time based on CRT flags. + // Debug vs release library selection happens at link time based on CRT + // flags. if (DriverDir.starts_with(SysRoot) && Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { SmallString<128> LibDir(DriverDir); >From 6e692290d3f5748c60e72aa749b3785b0fa2d415 Mon Sep 17 00:00:00 2001 From: srividya sundaram <[email protected]> Date: Wed, 6 May 2026 10:52:54 -0700 Subject: [PATCH 8/8] Remove /M* checks and braces. --- clang/lib/Driver/ToolChains/MSVC.cpp | 5 ----- clang/lib/Driver/ToolChains/SYCL.cpp | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index f1622bb07d037..c9c555d04ad11 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -133,11 +133,6 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (RuntimeVal == "dll_dbg") IsDebugBuild = true; } - // Check for /MDd flag, use getLastArg to handle overriding options - if (const Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) { - if (A->getOption().matches(options::OPT__SLASH_MDd)) - IsDebugBuild = true; - } CmdArgs.push_back(IsDebugBuild ? "-defaultlib:LLVMSYCLd" : "-defaultlib:LLVMSYCL"); } diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index a03f99029b9bc..7400924ab6bdd 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -38,9 +38,8 @@ SYCLInstallationDetector::SYCLInstallationDetector( SmallString<128> SYCLLibPath(LibDir); llvm::sys::path::append(SYCLLibPath, "LLVMSYCL.lib"); - if (D.getVFS().exists(SYCLLibPath)) { + if (D.getVFS().exists(SYCLLibPath)) SYCLRTLibPath = LibDir; - } } } else { // Linux/Unix: Check for libLLVMSYCL.so _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
