Skip to content

[SYCL] Support --offload-compress in clang-linker-wrapper#22605

Open
bviyer wants to merge 14 commits into
syclfrom
bviyer-sycl-compress-support
Open

[SYCL] Support --offload-compress in clang-linker-wrapper#22605
bviyer wants to merge 14 commits into
syclfrom
bviyer-sycl-compress-support

Conversation

@bviyer

@bviyer bviyer commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Forward --offload-compress (and --offload-compression-level=) from the driver to clang-linker-wrapper under the new offloading driver. In wrapSYCLBinariesFromFile, zstd-compress each SYCL device image whose payload is at or above --offload-compression-threshold= (default 512 bytes) and tag it with the new BIF_Compressed image format so the SYCL runtime decompresses lazily via CompressedRTDeviceBinaryImage.

Significant help from Claude Opus 4.7.

@bviyer
bviyer requested review from YuriPlyakhin and maksimsab July 12, 2026 15:23
@bviyer
bviyer marked this pull request as ready for review July 14, 2026 14:05
@bviyer
bviyer requested review from a team as code owners July 14, 2026 14:05
// The --compress flag above is a different mechanism: for HIP only, it is
// forwarded verbatim to a clang-offload-bundler subprocess which does the
// compression itself.
def offload_compress : Flag<["--"], "offload-compress">,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding new flags could we just re-use the existing ones? Then I don't think we need any driver changes, it seems addOffloadCompressArgs should do what we need if we make clang-linker-wrapper do the right thing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. I made it use --compress and --compress-level=

BIF_Native, // Native Image kind
BIF_SPIRV, // SPIR-V
BIF_LLVMBC, // LLVM bitcode
BIF_CompressedNone // zstd-compressed image; format-of-original unknown

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could just call it BIF_Compressed unless we need different BIFCompressed versions for different original formats, which it seems like we don't

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

case SYCLBinaryImageFormat::BIF_LLVMBC:
return 3;
case SYCLBinaryImageFormat::BIF_CompressedNone:
return 4;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the SYCL runtime already knows how to handle this and the format matches the old offload model?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

"'--offload-compress' is specified but zstd is not available");

int Level = 10; // default zstd level, matches clang-offload-wrapper
int Threshold = 512; // skip compression below this many bytes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can h ave a shared function that both clang-offload-wrapper and clang-linker-wrapper use until we remove old offload model support. Maybe we could put it in llvm/lib/Frontend/Offloading/Utility.cpp?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed here ec31530. Its a bit messy.

@bviyer
bviyer requested a review from bader as a code owner July 15, 2026 23:27
@bviyer
bviyer force-pushed the bviyer-sycl-compress-support branch from 2361b30 to ec31530 Compare July 15, 2026 23:30
@bviyer
bviyer requested a review from sarnex July 15, 2026 23:32
@bader

bader commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

@bviyer, please, remove .gdbinit from PR.

@bviyer

bviyer commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@bviyer, please, remove .gdbinit from PR.

Sorry. Fixed.

@bader
bader removed their request for review July 15, 2026 23:52

@sarnex sarnex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice cleanup! some comments below

// CHECK-NO-COMPRESS-NOT: {{.*}}clang-linker-wrapper{{.*}}"--compress"

// --no-offload-compress overrides an earlier --offload-compress.
// RUN: %clangxx -### -fsycl --offload-new-driver --offload-compress \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we check the opposite case, where we have --no-offload-compress --offload-compress

// consume them here and zstd-compress each image payload in place, flipping
// its Format to BIF_Compressed. The SYCL runtime recognizes that tag and
// decompresses lazily via CompressedRTDeviceBinaryImage.
if (Args.hasArg(OPT_compress)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we move this all into a separate function like compressSYCLImages or something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// Forward-declared instead of #include "llvm/Frontend/Offloading/Utility.h"
// because pulling in that header (transitively llvm/Object/OffloadBinary.h)
// makes llvm::object::OffloadKind visible via `using namespace llvm::object`
// above, which collides with the local anonymous-namespace `enum OffloadKind`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO instead of this workaround we should fix the local anonymous namespace issue, maybe rename it to something that shows how it's different from the OffloadBinary.h one if really we need a separate enum

@bviyer bviyer Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to OffloadModelKind (didn't want to remove the kind since it was used in several places and looks like it means something).

// pre-refactor behavior which errored regardless of image kind or
// format. The guarded branch below would otherwise skip the check for
// non-SYCL / explicit-format images.
if (OffloadCompressDevImgs && !llvm::compression::zstd::isAvailable())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO changing the error behavior is fine, if we don't actually try to compress anything it's fine to not error, having this extra check is confusing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


for (auto &Image : Images) {
SmallVector<uint8_t, 0> CompressedBytes;
Expected<bool> Compressed = offloading::compressSYCLDeviceImage(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make it a bit clearer on what the return type is with something like

Expected<bool> DidCompressOrErr = ...
if (!DidCompressOrErr)
        return DidCompressOrErr.takeError();
bool DidCompres = *DidCompressOrErr;
/// use DidCompress

At first it was unclear to me what the bool represented so I think making it explicit would help readability

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. However, I didn't create a new variable called DidCompress I just used the check on (*DidCompressOrErr). Generally, I do not create new variables unless the item is used in multiple places.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we lost the LLVM_ENABLE_EXCEPTIONS handling which we probably need

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@sarnex sarnex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you forget to push your changes to the PR? i'm not seeing any new commits with fixes

@bviyer
bviyer requested a review from sarnex July 16, 2026 19:16

@sarnex sarnex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm thanks! just some final nits

/// clang-offload-wrapper also uses; the surrounding loop isn't shared
/// because that tool operates on one image at a time and emits an LLVM
/// Constant directly, not a SYCLImage list.
static Error compressSYCLImages(SmallVectorImpl<offloading::SYCLImage> &Images,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry instead can we put this in the namespace sycl starting at line ~515 and call it compressImages? Thanks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

/// tagging its Format as BIF_Compressed. --compress and --compression-level=
/// are the same flags HIP forwards to clang-offload-bundler; for SYCL we
/// consume them here. The per-image work delegates to
/// offloading::compressSYCLDeviceImage, which the old-driver

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not sure we need to mention the old offloading model here or anywhere in code comments in new offload model code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// enum.
enum OffloadKind {
// enum. Distinct from llvm::object::OffloadKind (in Object/OffloadBinary.h),
// which is the 16-bit bitmask on the OffloadBinary wire format

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not sure what wire format means

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it was an artifact of something I was typing. I reworded to "...in the OffloadBinary header."

// command-line-parsed tag with an extra Host slot and First/Last sentinels,
// serialized as a uint8_t into the SYCL runtime's sycl_device_binary_struct
// Kind field.
enum OffloadModelKind {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe OldOffloadKind?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

bviyer added 9 commits July 16, 2026 14:36
Forward --offload-compress (and --offload-compression-level=) from the
driver to clang-linker-wrapper under the new offloading driver. In
wrapSYCLBinariesFromFile, zstd-compress each SYCL device image whose
payload is at or above --offload-compression-threshold= (default 512
bytes) and tag it with the new BIF_CompressedNone image format so the
SYCL runtime decompresses lazily via CompressedRTDeviceBinaryImage.
ClangOffLoadWrappper and ClangLinkerWrapper.
@bviyer
bviyer force-pushed the bviyer-sycl-compress-support branch from e45280d to e79b396 Compare July 16, 2026 22:19
Comment thread llvm/include/llvm/Frontend/Offloading/Utility.h Outdated

@YuriPlyakhin YuriPlyakhin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update PR description: BIF_CompressedNone -> BIF_Compressed

@YuriPlyakhin YuriPlyakhin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a functional test for the new compression path to test changes in clang-linker-wrapper.cpp?
Test would run clang-linker-wrapper --compress and would verify the emitted image is tagged with BIF_Compressed.
Also it would check invalid value for --offload-compression-level= error message.
FYI: The old wrapper is tested by clang-offload-wrapper-zstd.c

Comment thread clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp Outdated
bviyer and others added 2 commits July 17, 2026 12:34
Co-authored-by: Yury Plyakhin <yury.plyakhin@intel.com>
Co-authored-by: Yury Plyakhin <yury.plyakhin@intel.com>
@bviyer

bviyer commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Please update PR description: BIF_CompressedNone -> BIF_Compressed

Fixed.

@bviyer

bviyer commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Could you please add a functional test for the new compression path to test changes in clang-linker-wrapper.cpp? Test would run clang-linker-wrapper --compress and would verify the emitted image is tagged with BIF_Compressed. Also it would check invalid value for --offload-compression-level= error message. FYI: The old wrapper is tested by clang-offload-wrapper-zstd.c

Added test here: 48bf119

@bviyer
bviyer requested a review from YuriPlyakhin July 17, 2026 17:56

// RUN: %clang -cc1 -fsycl-is-device -disable-llvm-passes -triple=spir64-unknown-unknown %s -emit-llvm-bc -o %t.device.bc
// RUN: llvm-offload-binary -o %t.fat --image=file=%t.device.bc,kind=sycl,triple=spir64-unknown-unknown
// RUN: %clang -cc1 %s -triple=x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.fat

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we also need x86-registered-target in REQUIRES

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +28 to +29
// CHECK-COMPRESS: [Compression] Original image size:
// CHECK-COMPRESS: [Compression] Compressed image size:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should be able to do basic math operations in Filecheck https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-numeric-substitution-blocks

could we at least verify the compressed size is smaller than the original?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@bviyer
bviyer requested a review from sarnex July 17, 2026 19:59

@sarnex sarnex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@sys-ce-bb

Copy link
Copy Markdown
Contributor

@intel/llvm-gatekeepers please consider merging

Comment on lines +8 to +12
// --- Prepare test data: build a bitcode module, pack it into an
// llvm-offload-binary, and embed it into an ELF object as the linker-wrapper
// input. The bitcode is large enough (well over the 512-byte compression
// threshold in wrapSYCLBinariesFromFile) that compression actually runs.

@YuriPlyakhin YuriPlyakhin Jul 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. I think comments are unnecessarily verbose.

Suggested change
// --- Prepare test data: build a bitcode module, pack it into an
// llvm-offload-binary, and embed it into an ELF object as the linker-wrapper
// input. The bitcode is large enough (well over the 512-byte compression
// threshold in wrapSYCLBinariesFromFile) that compression actually runs.
// Prepare test data. The bitcode is over the 512-byte compression
// threshold, so the compression actually runs.

Comment on lines +33 to +41
// Assert that the compressed size is strictly smaller than the original size
// (i.e. ORIG - COMP > 0). FileCheck's numeric matching form only supports the
// `==` constraint — there is no `<` or `>` — but sub() rejects underflow at
// expression-evaluation time. We attach sub(ORIG, COMP) to a CHECK-NOT
// pattern that begins with a sentinel string never present in the output:
// * when ORIG > COMP, sub() succeeds; the substituted pattern is
// "COMPRESSION_SIZE_CHECK<some-number>", which doesn't appear, so the
// CHECK-NOT is satisfied vacuously.
// * when COMP >= ORIG, sub() underflows and FileCheck fails the pattern.

@YuriPlyakhin YuriPlyakhin Jul 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. too verbose for me :)

Suggested change
// Assert that the compressed size is strictly smaller than the original size
// (i.e. ORIG - COMP > 0). FileCheck's numeric matching form only supports the
// `==` constraint — there is no `<` or `>` — but sub() rejects underflow at
// expression-evaluation time. We attach sub(ORIG, COMP) to a CHECK-NOT
// pattern that begins with a sentinel string never present in the output:
// * when ORIG > COMP, sub() succeeds; the substituted pattern is
// "COMPRESSION_SIZE_CHECK<some-number>", which doesn't appear, so the
// CHECK-NOT is satisfied vacuously.
// * when COMP >= ORIG, sub() underflows and FileCheck fails the pattern.
// Assert ORIG - COMP > 0.
// FileCheck's numeric matching form only supports the
// `==` constraint, but sub() rejects underflow at
// expression-evaluation time. We attach sub(ORIG, COMP) to a CHECK-NOT
// pattern that begins with a sentinel string never present in the output:
// * when ORIG > COMP, sub() succeeds; the substituted pattern is
// "COMPRESSION_SIZE_CHECK<some-number>", which doesn't appear, so the
// CHECK-NOT is satisfied.
// * when COMP >= ORIG, sub() underflows and FileCheck fails the pattern.

Comment on lines +43 to +44
// The tgt_device_image struct is { i16 Version, i8 Kind, i8 Format, ptr ... };
// Kind for SYCL is 4, Format for BIF_Compressed is also 4.

@YuriPlyakhin YuriPlyakhin Jul 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. All we need is to check BIF_Compressed and it is already explained in the comments above that it is 4. The check is fine, but I don't think we need to provide verbose comments explaining each small detail not related to the functionality we test.

Suggested change
// The tgt_device_image struct is { i16 Version, i8 Kind, i8 Format, ptr ... };
// Kind for SYCL is 4, Format for BIF_Compressed is also 4.

@YuriPlyakhin YuriPlyakhin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Few nits - all related to too verbose comments. Feel free to ignore. Thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants