https://github.com/asudarsa updated 
https://github.com/llvm/llvm-project/pull/135683

>From 597fda606efbcf10304fed4adc5dd85da34b3de3 Mon Sep 17 00:00:00 2001
From: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
Date: Mon, 14 Apr 2025 14:16:05 -0700
Subject: [PATCH 1/5] [SYCL] Add clang-linker-wrapper changes to call
 clang-sycl-linker for SYCL offloads

Device code linking happens inside clang-linker-wrapper. In the current
implementation, clang-linker-wrapper does the following:

1. Extracts device code. Input_1, Input_2,.....
2. Group device code according to target devices
Inputs[triple_1] = ....
Inputs[triple_2] = ....
3. For each group, i.e. Inputs[triple_i],
   a. Gather all the offload kinds found inside those inputs in
      ActiveOffloadKinds
   b. Link all images inside Inputs[triple_i] by calling
      clang --target=triple_i ....
   c. Create a copy of that linked image for each offload kind and add it to
      Output[Kind] list.

In SYCL compilation flow, there is a deviation in Step 3b. We call device code
splitting inside the 'clang --target=triple_i ....' call and the output is now
a 'packaged' file containing multiple device images. This deviation requires us
to capture the OffloadKind during the linking stage and pass it along to the
linking function (clang), so that clang can be called with a unique option
'--sycl-link' that will help us to call 'clang-sycl-linker' under the hood
(clang-sycl-linker will do SYCL specific linking).

Our current objective is to implement an end-to-end SYCL offloading flow and
get it working. We will eventually merge our approach with the community flow.

Signed-off-by: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
---
 clang/docs/ClangOffloadPackager.rst           |  2 +
 clang/test/Driver/linker-wrapper.c            | 10 +++
 .../ClangLinkerWrapper.cpp                    | 58 ++++++++++++-
 .../clang-sycl-linker/ClangSYCLLinker.cpp     | 84 ++++++++++++++-----
 llvm/lib/Object/OffloadBinary.cpp             |  3 +
 5 files changed, 134 insertions(+), 23 deletions(-)

diff --git a/clang/docs/ClangOffloadPackager.rst 
b/clang/docs/ClangOffloadPackager.rst
index 2b985e260e302..481069b5e4235 100644
--- a/clang/docs/ClangOffloadPackager.rst
+++ b/clang/docs/ClangOffloadPackager.rst
@@ -112,6 +112,8 @@ the following values for the :ref:`offload 
kind<table-offload_kind>` and the
     +------------+-------+---------------------------------------+
     | OFK_HIP    | 0x03  | The producer was HIP                  |
     +------------+-------+---------------------------------------+
+    | OFK_SYCL   | 0x04  | The producer was SYCL                 |
+    +------------+-------+---------------------------------------+
 
 The flags are used to signify certain conditions, such as the presence of
 debugging information or whether or not LTO was used. The string entry table is
diff --git a/clang/test/Driver/linker-wrapper.c 
b/clang/test/Driver/linker-wrapper.c
index 0c77c2b34216a..921c9a11d2d32 100644
--- a/clang/test/Driver/linker-wrapper.c
+++ b/clang/test/Driver/linker-wrapper.c
@@ -2,6 +2,7 @@
 // REQUIRES: x86-registered-target
 // REQUIRES: nvptx-registered-target
 // REQUIRES: amdgpu-registered-target
+// REQUIRES: spirv-registered-target
 
 // An externally visible variable so static libraries extract.
 __attribute__((visibility("protected"), used)) int x;
@@ -9,6 +10,7 @@ __attribute__((visibility("protected"), used)) int x;
 // RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.elf.o
 // RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.nvptx.bc
 // RUN: %clang -cc1 %s -triple amdgcn-amd-amdhsa -emit-llvm-bc -o %t.amdgpu.bc
+// RUN: %clang -cc1 %s -triple spirv64-unknown-unknown -emit-llvm-bc -o 
%t.spirv.bc
 
 // RUN: clang-offload-packager -o %t.out \
 // RUN:   
--image=file=%t.elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \
@@ -49,6 +51,14 @@ __attribute__((visibility("protected"), used)) int x;
 
 // AMDGPU-LTO-TEMPS: clang{{.*}} --target=amdgcn-amd-amdhsa -mcpu=gfx1030 
-flto {{.*}}-save-temps
 
+// RUN: clang-offload-packager -o %t.out \
+// RUN:   
--image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=generic
+// 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
+
+// SPIRV-LINK: clang{{.*}} -o {{.*}}.img --target=spirv64-unknown-unknown 
{{.*}}.o --sycl-link -Xlinker -triple=spirv64-unknown-unknown -Xlinker -arch=
+
 // RUN: clang-offload-packager -o %t.out \
 // RUN:   --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu \
 // 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 082355e6c716f..51bb274770a96 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -464,7 +464,8 @@ fatbinary(ArrayRef<std::pair<StringRef, StringRef>> 
InputFiles,
 } // namespace amdgcn
 
 namespace generic {
-Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args) 
{
+Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args,
+                          bool HasSYCLOffloadKind = false) {
   llvm::TimeTraceScope TimeScope("Clang");
   // Use `clang` to invoke the appropriate device tools.
   Expected<std::string> ClangPath =
@@ -554,6 +555,17 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args) {
   if (Args.hasArg(OPT_embed_bitcode))
     CmdArgs.push_back("-Wl,--lto-emit-llvm");
 
+  // 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 (HasSYCLOffloadKind) {
+    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)});
   for (StringRef Arg : Args.getAllArgValues(OPT_compiler_arg_EQ))
@@ -567,7 +579,8 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args) {
 } // namespace generic
 
 Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
-                               const ArgList &Args) {
+                               const ArgList &Args,
+                               bool HasSYCLOffloadKind = false) {
   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
   switch (Triple.getArch()) {
   case Triple::nvptx:
@@ -582,7 +595,7 @@ Expected<StringRef> linkDevice(ArrayRef<StringRef> 
InputFiles,
   case Triple::spirv64:
   case Triple::systemz:
   case Triple::loongarch64:
-    return generic::clang(InputFiles, Args);
+    return generic::clang(InputFiles, Args, HasSYCLOffloadKind);
   default:
     return createStringError(Triple.getArchName() +
                              " linking is not supported");
@@ -936,6 +949,38 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
       InputFiles.emplace_back(*FileNameOrErr);
     }
 
+    if (ActiveOffloadKindMask & OFK_SYCL) {
+      // Link the remaining device files using the device linker.
+      auto OutputOrErr = linkDevice(InputFiles, LinkerArgs, 
HasSYCLOffloadKind);
+      if (!OutputOrErr)
+        return OutputOrErr.takeError();
+      // Output is a packaged object of device images. Unpackage the images and
+      // copy them to Images[Kind]
+      ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+          MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
+      if (std::error_code EC = BufferOrErr.getError())
+        return createFileError(*OutputOrErr, EC);
+
+      MemoryBufferRef Buffer = **BufferOrErr;
+      SmallVector<OffloadFile> Binaries;
+      if (Error Err = extractOffloadBinaries(Buffer, Binaries))
+        return std::move(Err);
+      for (auto &OffloadFile : Binaries) {
+        auto TheBinary = OffloadFile.getBinary();
+        OffloadingImage TheImage{};
+        TheImage.TheImageKind = TheBinary->getImageKind();
+        TheImage.TheOffloadKind = TheBinary->getOffloadKind();
+        TheImage.StringData["triple"] = TheBinary->getTriple();
+        TheImage.StringData["arch"] = TheBinary->getArch();
+        TheImage.Image = MemoryBuffer::getMemBufferCopy(TheBinary->getImage());
+        Images[OFK_SYCL].emplace_back(std::move(TheImage));
+      }
+    }
+
+    // Exit early if no other offload kind found (other than OFK_SYCL).
+    if ((ActiveOffloadKindMask ^ OFK_SYCL) == 0) {
+      return Error::success();
+
     // Link the remaining device files using the device linker.
     auto OutputOrErr = linkDevice(InputFiles, LinkerArgs);
     if (!OutputOrErr)
@@ -944,7 +989,7 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
     // Store the offloading image for each linked output file.
     for (OffloadKind Kind = OFK_OpenMP; Kind != OFK_LAST;
          Kind = static_cast<OffloadKind>((uint16_t)(Kind) << 1)) {
-      if ((ActiveOffloadKindMask & Kind) == 0)
+      if (((ActiveOffloadKindMask & Kind) == 0) || (Kind == OFK_SYCL))
         continue;
       llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
           llvm::MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
@@ -988,6 +1033,11 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
              A.StringData["arch"] > B.StringData["arch"] ||
              A.TheOffloadKind < B.TheOffloadKind;
     });
+    if (Kind == OFK_SYCL) {
+      // TODO: Update once SYCL offload wrapping logic is available.
+      reportError(
+          createStringError("SYCL offload wrapping logic is not available"));
+    }
     auto BundledImagesOrErr = bundleLinkedOutput(Input, Args, Kind);
     if (!BundledImagesOrErr)
       return BundledImagesOrErr.takeError();
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp 
b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index c640deddc9e74..7c0b5de6ecb13 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -70,6 +70,8 @@ static StringRef OutputFile;
 /// Directory to dump SPIR-V IR if requested by user.
 static SmallString<128> SPIRVDumpDir;
 
+using OffloadingImage = OffloadBinary::OffloadingImage;
+
 static void printVersion(raw_ostream &OS) {
   OS << clang::getClangToolFullVersion("clang-sycl-linker") << '\n';
 }
@@ -168,10 +170,10 @@ Expected<SmallVector<std::string>> getInput(const ArgList 
&Args) {
 /// are LLVM IR bitcode files.
 // TODO: Support SPIR-V IR files.
 Expected<std::unique_ptr<Module>> getBitcodeModule(StringRef File,
-                                                   LLVMContext &C) {
+                                                   LLVMContext &Ctx) {
   SMDiagnostic Err;
 
-  auto M = getLazyIRFileModule(File, Err, C);
+  auto M = getLazyIRFileModule(File, Err, Ctx);
   if (M)
     return std::move(M);
   return createStringError(Err.getMessage());
@@ -211,16 +213,16 @@ Expected<SmallVector<std::string>> 
getSYCLDeviceLibs(const ArgList &Args) {
 /// 3. Link all the images gathered in Step 2 with the output of Step 1 using
 /// linkInModule API. LinkOnlyNeeded flag is used.
 Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
-                                   const ArgList &Args, LLVMContext &C) {
+                                   const ArgList &Args, LLVMContext &Ctx) {
   llvm::TimeTraceScope TimeScope("SYCL link device code");
 
   assert(InputFiles.size() && "No inputs to link");
 
-  auto LinkerOutput = std::make_unique<Module>("sycl-device-link", C);
+  auto LinkerOutput = std::make_unique<Module>("sycl-device-link", Ctx);
   Linker L(*LinkerOutput);
   // Link SYCL device input files.
   for (auto &File : InputFiles) {
-    auto ModOrErr = getBitcodeModule(File, C);
+    auto ModOrErr = getBitcodeModule(File, Ctx);
     if (!ModOrErr)
       return ModOrErr.takeError();
     if (L.linkInModule(std::move(*ModOrErr)))
@@ -235,7 +237,7 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> 
InputFiles,
   // Link in SYCL device library files.
   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
   for (auto &File : *SYCLDeviceLibFiles) {
-    auto LibMod = getBitcodeModule(File, C);
+    auto LibMod = getBitcodeModule(File, Ctx);
     if (!LibMod)
       return LibMod.takeError();
     if ((*LibMod)->getTargetTriple() == Triple) {
@@ -278,18 +280,18 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> 
InputFiles,
 /// Converts 'File' from LLVM bitcode to SPIR-V format using SPIR-V backend.
 /// 'Args' encompasses all arguments required for linking device code and will
 /// be parsed to generate options required to be passed into the backend.
-static Expected<StringRef> runSPIRVCodeGen(StringRef File, const ArgList &Args,
-                                           LLVMContext &C) {
+static Error runSPIRVCodeGen(StringRef File, const ArgList &Args,
+                             StringRef OutputFile, LLVMContext &Ctx) {
   llvm::TimeTraceScope TimeScope("SPIR-V code generation");
 
   // Parse input module.
-  SMDiagnostic Err;
-  std::unique_ptr<Module> M = parseIRFile(File, Err, C);
+  SMDiagnostic E;
+  std::unique_ptr<Module> M = parseIRFile(File, E, Ctx);
   if (!M)
-    return createStringError(Err.getMessage());
+    return createStringError(E.getMessage());
 
   if (Error Err = M->materializeAll())
-    return std::move(Err);
+    return Err;
 
   Triple TargetTriple(Args.getLastArgValue(OPT_triple_EQ));
   M->setTargetTriple(TargetTriple);
@@ -333,7 +335,7 @@ static Expected<StringRef> runSPIRVCodeGen(StringRef File, 
const ArgList &Args,
     errs() << formatv("SPIR-V Backend: input: {0}, output: {1}\n", File,
                       OutputFile);
 
-  return OutputFile;
+  return Error::success();
 }
 
 /// Performs the following steps:
@@ -342,17 +344,61 @@ static Expected<StringRef> runSPIRVCodeGen(StringRef 
File, const ArgList &Args,
 Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
   llvm::TimeTraceScope TimeScope("SYCL device linking");
 
-  LLVMContext C;
+  LLVMContext Ctx;
 
   // Link all input bitcode files and SYCL device library files, if any.
-  auto LinkedFile = linkDeviceCode(Files, Args, C);
+  auto LinkedFile = linkDeviceCode(Files, Args, Ctx);
   if (!LinkedFile)
     reportError(LinkedFile.takeError());
 
+  // TODO: SYCL post link functionality involves device code splitting and will
+  // result in multiple bitcode codes.
+  // The following lines are placeholders to represent multiple files and will
+  // be refactored once SYCL post link support is available.
+  SmallVector<std::string> SplitModules;
+  SplitModules.emplace_back(*LinkedFile);
+
   // SPIR-V code generation step.
-  auto SPVFile = runSPIRVCodeGen(*LinkedFile, Args, C);
-  if (!SPVFile)
-    return SPVFile.takeError();
+  for (size_t I = 0, E = SplitModules.size(); I != E; ++I) {
+    auto Stem = OutputFile.rsplit('.').first;
+    std::string SPVFile(Stem);
+    SPVFile.append("_" + utostr(I) + ".spv");
+    auto Err = runSPIRVCodeGen(SplitModules[I], Args, SPVFile, Ctx);
+    if (Err)
+      return std::move(Err);
+    SplitModules[I] = SPVFile;
+  }
+
+  // Write the final output into file.
+  int FD = -1;
+  if (std::error_code EC = sys::fs::openFileForWrite(OutputFile, FD))
+    return errorCodeToError(EC);
+  llvm::raw_fd_ostream FS(FD, /*shouldClose=*/true);
+
+  for (size_t I = 0, E = SplitModules.size(); I != E; ++I) {
+    auto File = SplitModules[I];
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
+        llvm::MemoryBuffer::getFileOrSTDIN(File);
+    if (std::error_code EC = FileOrErr.getError()) {
+      if (DryRun)
+        FileOrErr = MemoryBuffer::getMemBuffer("");
+      else
+        return createFileError(File, EC);
+    }
+    OffloadingImage TheImage{};
+    TheImage.TheImageKind = IMG_Object;
+    TheImage.TheOffloadKind = OFK_SYCL;
+    TheImage.StringData["triple"] =
+        Args.MakeArgString(Args.getLastArgValue(OPT_triple_EQ));
+    TheImage.StringData["arch"] =
+        Args.MakeArgString(Args.getLastArgValue(OPT_arch_EQ));
+    TheImage.Image = std::move(*FileOrErr);
+
+    llvm::SmallString<0> Buffer = OffloadBinary::write(TheImage);
+    if (Buffer.size() % OffloadBinary::getAlignment() != 0)
+      return createStringError("Offload binary has invalid size alignment");
+    FS << Buffer;
+  }
   return Error::success();
 }
 
@@ -394,7 +440,7 @@ int main(int argc, char **argv) {
   DryRun = Args.hasArg(OPT_dry_run);
   SaveTemps = Args.hasArg(OPT_save_temps);
 
-  OutputFile = "a.spv";
+  OutputFile = "a.out";
   if (Args.hasArg(OPT_o))
     OutputFile = Args.getLastArgValue(OPT_o);
 
diff --git a/llvm/lib/Object/OffloadBinary.cpp 
b/llvm/lib/Object/OffloadBinary.cpp
index 56687c9acb653..3fff6b6a09e08 100644
--- a/llvm/lib/Object/OffloadBinary.cpp
+++ b/llvm/lib/Object/OffloadBinary.cpp
@@ -301,6 +301,7 @@ OffloadKind object::getOffloadKind(StringRef Name) {
       .Case("openmp", OFK_OpenMP)
       .Case("cuda", OFK_Cuda)
       .Case("hip", OFK_HIP)
+      .Case("sycl", OFK_SYCL)
       .Default(OFK_None);
 }
 
@@ -312,6 +313,8 @@ StringRef object::getOffloadKindName(OffloadKind Kind) {
     return "cuda";
   case OFK_HIP:
     return "hip";
+  case OFK_SYCL:
+    return "sycl";
   default:
     return "none";
   }

>From 9790298bf43be657904519ec80cb80bcd8dbc6c4 Mon Sep 17 00:00:00 2001
From: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
Date: Mon, 14 Apr 2025 15:38:24 -0700
Subject: [PATCH 2/5] Update failing test

Signed-off-by: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
---
 clang/test/Driver/clang-sycl-linker-test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/Driver/clang-sycl-linker-test.cpp 
b/clang/test/Driver/clang-sycl-linker-test.cpp
index c399689653784..1dfba391fbc3e 100644
--- a/clang/test/Driver/clang-sycl-linker-test.cpp
+++ b/clang/test/Driver/clang-sycl-linker-test.cpp
@@ -8,7 +8,7 @@
 // RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o 
a.spv 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=SIMPLE-FO
 // SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc  libfiles:  
output: [[LLVMLINKOUT:.*]].bc
-// SIMPLE-FO-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a.spv
+// SIMPLE-FO-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a_0.spv
 //
 // Test the dry run of a simple case with device library files specified.
 // RUN: touch %T/lib1.bc
@@ -16,7 +16,7 @@
 // RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc 
--library-path=%T --device-libs=lib1.bc,lib2.bc -o a.spv 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=DEVLIBS
 // DEVLIBS: sycl-device-link: inputs: {{.*}}.bc  libfiles: {{.*}}lib1.bc, 
{{.*}}lib2.bc  output: [[LLVMLINKOUT:.*]].bc
-// DEVLIBS-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a.spv
+// DEVLIBS-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a_0.spv
 //
 // Test a simple case with a random file (not bitcode) as input.
 // RUN: touch %t.o

>From 67e994d00df788005313a3269d42751ec4b7cbea Mon Sep 17 00:00:00 2001
From: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
Date: Wed, 16 Apr 2025 10:22:16 -0700
Subject: [PATCH 3/5] Merge with recent changes

Signed-off-by: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
---
 .../ClangLinkerWrapper.cpp                    | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 51bb274770a96..13315bb0a4e1b 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -465,7 +465,7 @@ fatbinary(ArrayRef<std::pair<StringRef, StringRef>> 
InputFiles,
 
 namespace generic {
 Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args,
-                          bool HasSYCLOffloadKind = false) {
+                          uint16_t ActiveOffloadKindMask) {
   llvm::TimeTraceScope TimeScope("Clang");
   // Use `clang` to invoke the appropriate device tools.
   Expected<std::string> ClangPath =
@@ -559,7 +559,7 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
   // 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 (HasSYCLOffloadKind) {
+  if (ActiveOffloadKindMask & OFK_SYCL) {
     CmdArgs.push_back("--sycl-link");
     CmdArgs.append(
         {"-Xlinker", Args.MakeArgString("-triple=" + Triple.getTriple())});
@@ -580,7 +580,7 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
 
 Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
                                const ArgList &Args,
-                               bool HasSYCLOffloadKind = false) {
+                               uint16_t ActiveOffloadKindMask) {
   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
   switch (Triple.getArch()) {
   case Triple::nvptx:
@@ -595,7 +595,7 @@ Expected<StringRef> linkDevice(ArrayRef<StringRef> 
InputFiles,
   case Triple::spirv64:
   case Triple::systemz:
   case Triple::loongarch64:
-    return generic::clang(InputFiles, Args, HasSYCLOffloadKind);
+    return generic::clang(InputFiles, Args, ActiveOffloadKindMask);
   default:
     return createStringError(Triple.getArchName() +
                              " linking is not supported");
@@ -949,9 +949,13 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
       InputFiles.emplace_back(*FileNameOrErr);
     }
 
+    // Currently, SYCL device code linking process differs from generic device
+    // code linking.
+    // TODO: Align SYCL device code linking with generic linking.
     if (ActiveOffloadKindMask & OFK_SYCL) {
       // Link the remaining device files using the device linker.
-      auto OutputOrErr = linkDevice(InputFiles, LinkerArgs, 
HasSYCLOffloadKind);
+      auto OutputOrErr =
+          linkDevice(InputFiles, LinkerArgs, ActiveOffloadKindMask);
       if (!OutputOrErr)
         return OutputOrErr.takeError();
       // Output is a packaged object of device images. Unpackage the images and
@@ -978,11 +982,12 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
     }
 
     // Exit early if no other offload kind found (other than OFK_SYCL).
-    if ((ActiveOffloadKindMask ^ OFK_SYCL) == 0) {
+    if ((ActiveOffloadKindMask ^ OFK_SYCL) == 0)
       return Error::success();
 
     // Link the remaining device files using the device linker.
-    auto OutputOrErr = linkDevice(InputFiles, LinkerArgs);
+    auto OutputOrErr =
+        linkDevice(InputFiles, LinkerArgs, ActiveOffloadKindMask);
     if (!OutputOrErr)
       return OutputOrErr.takeError();
 

>From e083ac29f36d1e8fa53e30c4e0e17ba858776fd9 Mon Sep 17 00:00:00 2001
From: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
Date: Wed, 16 Apr 2025 14:11:07 -0700
Subject: [PATCH 4/5] Align clang-linker-wrapper flow with community flow

Signed-off-by: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
---
 clang/test/Driver/linker-wrapper.c            |  2 +-
 .../ClangLinkerWrapper.cpp                    | 53 ++++---------------
 2 files changed, 12 insertions(+), 43 deletions(-)

diff --git a/clang/test/Driver/linker-wrapper.c 
b/clang/test/Driver/linker-wrapper.c
index 921c9a11d2d32..a7e98e7351d98 100644
--- a/clang/test/Driver/linker-wrapper.c
+++ b/clang/test/Driver/linker-wrapper.c
@@ -54,7 +54,7 @@ __attribute__((visibility("protected"), used)) int x;
 // RUN: clang-offload-packager -o %t.out \
 // RUN:   
--image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=generic
 // 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: not 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 --target=spirv64-unknown-unknown 
{{.*}}.o --sycl-link -Xlinker -triple=spirv64-unknown-unknown -Xlinker -arch=
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 13315bb0a4e1b..96aecc768b6dc 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -805,6 +805,7 @@ bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const 
ArgList &Args,
   llvm::TimeTraceScope TimeScope("Bundle linked output");
   switch (Kind) {
   case OFK_OpenMP:
+  case OFK_SYCL:
     return bundleOpenMP(Images);
   case OFK_Cuda:
     return bundleCuda(Images, Args);
@@ -940,6 +941,14 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
     for (const auto &File : Input)
       ActiveOffloadKindMask |= File.getBinary()->getOffloadKind();
 
+    // Linking images of SYCL offload kind with images of other kind is not
+    // supported.
+    // TODO: Remove the above limitation.
+    if ((ActiveOffloadKindMask & OFK_SYCL) &&
+        ((ActiveOffloadKindMask ^ OFK_SYCL) != 0))
+      return createStringError("Linking images of SYCL offload kind with "
+                               "images of any other kind is not supported");
+
     // Write any remaining device inputs to an output file.
     SmallVector<StringRef> InputFiles;
     for (const OffloadFile &File : Input) {
@@ -949,42 +958,6 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
       InputFiles.emplace_back(*FileNameOrErr);
     }
 
-    // Currently, SYCL device code linking process differs from generic device
-    // code linking.
-    // TODO: Align SYCL device code linking with generic linking.
-    if (ActiveOffloadKindMask & OFK_SYCL) {
-      // Link the remaining device files using the device linker.
-      auto OutputOrErr =
-          linkDevice(InputFiles, LinkerArgs, ActiveOffloadKindMask);
-      if (!OutputOrErr)
-        return OutputOrErr.takeError();
-      // Output is a packaged object of device images. Unpackage the images and
-      // copy them to Images[Kind]
-      ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
-          MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
-      if (std::error_code EC = BufferOrErr.getError())
-        return createFileError(*OutputOrErr, EC);
-
-      MemoryBufferRef Buffer = **BufferOrErr;
-      SmallVector<OffloadFile> Binaries;
-      if (Error Err = extractOffloadBinaries(Buffer, Binaries))
-        return std::move(Err);
-      for (auto &OffloadFile : Binaries) {
-        auto TheBinary = OffloadFile.getBinary();
-        OffloadingImage TheImage{};
-        TheImage.TheImageKind = TheBinary->getImageKind();
-        TheImage.TheOffloadKind = TheBinary->getOffloadKind();
-        TheImage.StringData["triple"] = TheBinary->getTriple();
-        TheImage.StringData["arch"] = TheBinary->getArch();
-        TheImage.Image = MemoryBuffer::getMemBufferCopy(TheBinary->getImage());
-        Images[OFK_SYCL].emplace_back(std::move(TheImage));
-      }
-    }
-
-    // Exit early if no other offload kind found (other than OFK_SYCL).
-    if ((ActiveOffloadKindMask ^ OFK_SYCL) == 0)
-      return Error::success();
-
     // Link the remaining device files using the device linker.
     auto OutputOrErr =
         linkDevice(InputFiles, LinkerArgs, ActiveOffloadKindMask);
@@ -994,7 +967,7 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
     // Store the offloading image for each linked output file.
     for (OffloadKind Kind = OFK_OpenMP; Kind != OFK_LAST;
          Kind = static_cast<OffloadKind>((uint16_t)(Kind) << 1)) {
-      if (((ActiveOffloadKindMask & Kind) == 0) || (Kind == OFK_SYCL))
+      if ((ActiveOffloadKindMask & Kind) == 0)
         continue;
       llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
           llvm::MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
@@ -1011,6 +984,7 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
 
       std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
       OffloadingImage TheImage{};
+
       TheImage.TheImageKind =
           Args.hasArg(OPT_embed_bitcode) ? IMG_Bitcode : IMG_Object;
       TheImage.TheOffloadKind = Kind;
@@ -1038,11 +1012,6 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
              A.StringData["arch"] > B.StringData["arch"] ||
              A.TheOffloadKind < B.TheOffloadKind;
     });
-    if (Kind == OFK_SYCL) {
-      // TODO: Update once SYCL offload wrapping logic is available.
-      reportError(
-          createStringError("SYCL offload wrapping logic is not available"));
-    }
     auto BundledImagesOrErr = bundleLinkedOutput(Input, Args, Kind);
     if (!BundledImagesOrErr)
       return BundledImagesOrErr.takeError();

>From b934c64bb596eca9725cb1136b4706bbfc3ef19c Mon Sep 17 00:00:00 2001
From: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
Date: Wed, 16 Apr 2025 15:25:44 -0700
Subject: [PATCH 5/5] minor typo

Signed-off-by: Arvind Sudarsanam <arvind.sudarsa...@intel.com>
---
 clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 96aecc768b6dc..4e716e818a232 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -984,7 +984,6 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
 
       std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
       OffloadingImage TheImage{};
-
       TheImage.TheImageKind =
           Args.hasArg(OPT_embed_bitcode) ? IMG_Bitcode : IMG_Object;
       TheImage.TheOffloadKind = Kind;

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to