https://github.com/YuriPlyakhin created 
https://github.com/llvm/llvm-project/pull/217492

A direct `clang --target=spirv64-unknown-unknown --sycl-link a.bc` did not tell 
clang-sycl-linker which device it is finalizing for.
Derive the triple from the target the driver was given, and the architecture 
from -march=, and pass them as -triple=/-arch=.

An absent -march= means no specific device was requested. That is spelled as an 
absent -arch=, matching how clang-linker-wrapper renders an offload image that 
names no device.

A caller may also name these itself, via -Xlinker/-Wl, or (through 
clang-linker-wrapper) via -Xoffload-linker. clang-sycl-linker keeps the last 
value of each, so an explicitly given one has to win: detect them and derive 
nothing in that case.

With the driver deriving both values, the SYCL-specific forwarding in 
clang-linker-wrapper becomes redundant - it spelled the triple and the 
architecture out through -Xlinker after having already passed the very same 
strings as --target= and -march= - so drop it.

>From 571ceb1bd4d5521df80e9b3f3089bd7e32bc04d3 Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <[email protected]>
Date: Mon, 10 Aug 2026 18:10:18 +0200
Subject: [PATCH] [clang][SYCL] Tag the device image when finalizing with
 clang-sycl-linker

A direct `clang --target=spirv64-unknown-unknown --sycl-link a.bc` never
tells clang-sycl-linker which device it is finalizing for. The tool falls
back to sniffing the triple out of the first input module that carries
one, and errors out if no input does or if two inputs disagree, so what
the resulting device image is tagged with depends on the inputs rather
than on what was asked for. Derive the triple from the target the driver
was given, and the architecture from -march=, and pass them as
-triple=/-arch=.

An absent -march= means no specific device was requested. That is spelled
as an absent -arch=, matching how clang-linker-wrapper renders an offload
image that names no device.

A caller may also name these itself, via -Xlinker/-Wl, or (through
clang-linker-wrapper) via -Xoffload-linker. clang-sycl-linker keeps the
last value of each, so an explicitly given one has to win: detect them
and derive nothing in that case.

With the driver deriving both values, the SYCL-specific forwarding in
clang-linker-wrapper becomes redundant - it spelled the triple and the
architecture out through -Xlinker after having already passed the very
same strings as --target= and -march= - so drop it.

Co-Authored-By: Claude <[email protected]>
---
 clang/lib/Driver/ToolChains/SPIRV.cpp         | 17 +++++++++++
 clang/test/Driver/sycl-link-spirv-target.cpp  | 29 +++++++++++++++++++
 .../linker-wrapper-verbose.c                  |  2 +-
 .../clang-linker-wrapper/linker-wrapper.c     | 10 ++++++-
 .../ClangLinkerWrapper.cpp                    |  9 ++----
 5 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp 
b/clang/lib/Driver/ToolChains/SPIRV.cpp
index 5cc1eec74c1cc..3a5cc6f90d23f 100644
--- a/clang/lib/Driver/ToolChains/SPIRV.cpp
+++ b/clang/lib/Driver/ToolChains/SPIRV.cpp
@@ -184,6 +184,23 @@ void SPIRV::Linker::ConstructJob(Compilation &C, const 
JobAction &JA,
     // Use of --sycl-link will call the clang-sycl-linker instead of
     // the default linker (spirv-link).
     Linker = ToolChain.GetProgramPath("clang-sycl-linker");
+
+    // clang-sycl-linker needs the device target triple and architecture to
+    // finalize a device image.
+    bool HasTriple = false, HasArch = false;
+    for (const Arg *A :
+         Args.filtered(options::OPT_Xlinker, options::OPT_Wl_COMMA,
+                       options::OPT_Zlinker_input))
+      for (StringRef Val : A->getValues()) {
+        HasTriple |= Val.starts_with("-triple") || Val.starts_with("--triple");
+        HasArch |= Val.starts_with("-arch") || Val.starts_with("--arch");
+      }
+    if (!HasTriple)
+      CmdArgs.push_back(
+          Args.MakeArgString("-triple=" + ToolChain.getTripleString()));
+    StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ);
+    if (!HasArch && !Arch.empty())
+      CmdArgs.push_back(Args.MakeArgString("-arch=" + Arch));
     if (Args.hasArg(options::OPT_v))
       CmdArgs.push_back("-v");
   } else if (!llvm::sys::fs::can_execute(Linker) &&
diff --git a/clang/test/Driver/sycl-link-spirv-target.cpp 
b/clang/test/Driver/sycl-link-spirv-target.cpp
index 885621140a679..4858f860d94e3 100644
--- a/clang/test/Driver/sycl-link-spirv-target.cpp
+++ b/clang/test/Driver/sycl-link-spirv-target.cpp
@@ -14,3 +14,32 @@
 // RUN: %clangxx -### --target=spirv64 --sycl-link -v %t.bc 2>&1 \
 // RUN:   | FileCheck %s -check-prefix=VERBOSE
 // VERBOSE: "{{.*}}clang-sycl-linker{{.*}}" {{.*}}"-v"
+
+// Test that -triple is propagated from --target and passed to 
clang-sycl-linker.
+// Test that no -march= results in no -arch= in clang-sycl-linker command line.
+// RUN: touch %t.bc
+// RUN: %clangxx -### --target=spirv64-unknown-unknown --sycl-link %t.bc 2>&1 \
+// RUN:   | FileCheck %s -check-prefix=FINALIZE
+// FINALIZE: "{{.*}}clang-sycl-linker{{.*}}" "{{.*}}.bc" "-o" "a.out" 
"-triple=spirv64-unknown-unknown"{{$}}
+
+// Test that the target triple is passed on as spelled rather than padded out
+// to a full triple.
+// RUN: touch %t.bc
+// RUN: %clangxx -### --target=spirv64 --sycl-link %t.bc 2>&1 \
+// RUN:   | FileCheck %s -check-prefix=FINALIZE-SHORT
+// FINALIZE-SHORT: "{{.*}}clang-sycl-linker{{.*}}" "{{.*}}.bc" "-o" "a.out" 
"-triple=spirv64"{{$}}
+
+// Test that a requested device architecture is passed on as -arch=.
+// RUN: touch %t.bc
+// RUN: %clangxx -### --target=spirv64-unknown-unknown -march=foo --sycl-link 
%t.bc 2>&1 \
+// RUN:   | FileCheck %s -check-prefix=FINALIZE-ARCH
+// FINALIZE-ARCH: "{{.*}}clang-sycl-linker{{.*}}" "{{.*}}.bc" "-o" "a.out" 
"-triple=spirv64-unknown-unknown" "-arch=foo"{{$}}
+
+// Test that -triple=/-arch= passed through -Xlinker/-Wl take priority and that
+// --target/-march passed to clang do not cause duplication of -triple=/-arch=.
+// RUN: touch %t.bc
+// RUN: %clangxx -### --target=spirv64 --sycl-link -march=bmg_g21 -Xlinker 
-triple=spirv64-unknown-unknown -Xlinker -arch=bar %t.bc 2>&1 \
+// RUN:   | FileCheck %s -check-prefix=NODUP
+// RUN: %clangxx -### --target=spirv64 --sycl-link -march=bmg_g21 
-Wl,-triple=spirv64-unknown-unknown,-arch=bar %t.bc 2>&1 \
+// RUN:   | FileCheck %s -check-prefix=NODUP
+// NODUP: "{{.*}}clang-sycl-linker{{.*}}" "-triple=spirv64-unknown-unknown" 
"-arch=bar" "{{.*}}.bc" "-o" "a.out"{{$}}
diff --git 
a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-verbose.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-verbose.c
index 54bd856746fd3..7da80fc9ee41f 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-verbose.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-verbose.c
@@ -76,7 +76,7 @@
 // RUN:   --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s 
--check-prefix=SYCL
 
 // SYCL: llvm-offload-binary{{.*}} {{.*}}.o 
--image=kind=sycl,triple=spirv64-unknown-unknown,arch=generic,file={{.*}}.o
-// SYCL: clang{{.*}} --target=spirv64-unknown-unknown {{.*}} --sycl-link 
{{.*}}-triple=spirv64-unknown-unknown{{.*}}-arch=
+// SYCL: clang{{.*}} --target=spirv64-unknown-unknown {{.*}} --sycl-link{{$}}
 // SYCL: llvm-offload-wrapper{{.*}} --kind=sycl 
--triple=x86_64-unknown-linux-gnu -o [[BC:.*]].bc {{.*}}.img
 // SYCL: clang{{.*}} --no-default-config --target=x86_64-unknown-linux-gnu -c 
-fPIC -o {{.*}}.sycl.image.wrapper{{.*}}.o [[BC]].bc
 
diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index ca2743114cd7b..9db92e604847c 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -57,7 +57,15 @@ __attribute__((visibility("protected"), used)) int x;
 // RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
 // RUN:   --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s 
--check-prefix=SPIRV-LINK
 
-// SPIRV-LINK: clang{{.*}} -o {{.*}}.img -dumpdir a.out.spirv64..img. 
--target=spirv64-unknown-unknown {{.*}}.o --sycl-link -Xlinker 
-triple=spirv64-unknown-unknown -Xlinker -arch=
+// SPIRV-LINK: clang{{.*}} -o {{.*}}.img -dumpdir a.out.spirv64..img. 
--target=spirv64-unknown-unknown {{.*}}.o --sycl-link{{$}}
+
+// RUN: llvm-offload-binary -o %t.out \
+// RUN:   
--image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=foo
+// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o 
-fembed-offload-object=%t.out
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
+// RUN:   --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s 
--check-prefix=SPIRV-LINK-ARCH
+
+// SPIRV-LINK-ARCH: clang{{.*}} --target=spirv64-unknown-unknown -march=foo 
{{.*}}.o --sycl-link{{$}}
 
 // RUN: llvm-offload-binary -o %t.out \
 // RUN:   --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu \
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 399f07d7c0a70..ecc87ed5b53b6 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -603,14 +603,9 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
 
   // For linking device code with the SYCL offload kind, special handling is
   // required. Passing --sycl-link to clang results in a call to
-  // clang-sycl-linker. Additional linker flags required by clang-sycl-linker
-  // will be communicated via the -Xlinker option.
-  if (ActiveOffloadKindMask & OFK_SYCL) {
+  // clang-sycl-linker.
+  if (ActiveOffloadKindMask & OFK_SYCL)
     CmdArgs.push_back("--sycl-link");
-    CmdArgs.append(
-        {"-Xlinker", Args.MakeArgString("-triple=" + Triple.getTriple())});
-    CmdArgs.append({"-Xlinker", Args.MakeArgString("-arch=" + Arch)});
-  }
 
   for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ))
     CmdArgs.append({"-Xlinker", Args.MakeArgString(Arg)});

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to