Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 79 additions & 7 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,20 @@ OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
this->OffloadKind = Components.front();
ArrayRef<StringRef> TripleSlice{&Components[1], /*length=*/4};
llvm::Triple T = llvm::Triple(llvm::join(TripleSlice, "-"));

// SYCL bundle entry IDs use a 3-component triple followed by the target ID,
Comment thread
sarnex marked this conversation as resolved.
// e.g. sycl-spir64_gen-unknown-unknown-pvc, so the last component is the
// target ID rather than the environment.
if (this->OffloadKind == "sycl" && Components.size() == 5 &&
T.getEnvironment() == llvm::Triple::UnknownEnvironment &&
Comment thread
sarnex marked this conversation as resolved.
!clang::StringToOffloadArch(Components.back().split(':').first)
Comment thread
sarnex marked this conversation as resolved.
.isUnknown()) {
this->TargetID = Components.back();
this->Triple =
llvm::Triple(T.getArchName(), T.getVendorName(), T.getOSName());
return;
}

this->Triple = llvm::Triple(T.getArchName(), T.getVendorName(), T.getOSName(),
T.getEnvironmentName());
}
Expand Down Expand Up @@ -1714,6 +1728,18 @@ bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
return false;
}

// SYCL device code without a target ID (e.g. -fsycl-targets=spir64_gen)
// stays compatible with any target ID of the same triple.
if (CodeObjectInfo.OffloadKind == "sycl" &&
(CodeObjectInfo.TargetID.empty() || TargetInfo.TargetID.empty())) {
Comment thread
sarnex marked this conversation as resolved.
DEBUG_WITH_TYPE("CodeObjectCompatibility",
dbgs() << "Compatible: SYCL code object without target ID "
"\t[CodeObject: "
<< CodeObjectInfo.str()
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
return true;
}
Comment thread
srividya-sundaram marked this conversation as resolved.

// Incompatible if Processors mismatch.
llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
std::optional<StringRef> CodeObjectProc = clang::parseTargetID(
Expand Down Expand Up @@ -1954,6 +1980,39 @@ Error OffloadBundler::UnbundleFiles() {
if (Error Err = FH->ReadHeader(Input.getBuffer()))
return Err;

// A SYCL code object without a target ID is compatible with any target ID
// of the same triple (see isCodeObjectCompatible). Only use such a match
// when the blob has no entry with an exactly matching target ID, so that
// the result does not depend on the order of the entries.
std::set<StringRef> BundleIDs;
{
Expected<std::unique_ptr<FileHandler>> IDHandlerOrErr =
CreateFileHandler(Input, BundlerConfig);
if (!IDHandlerOrErr)
Comment thread
sarnex marked this conversation as resolved.
return IDHandlerOrErr.takeError();
if (Error Err = (*IDHandlerOrErr)->getBundleIDs(Input, BundleIDs))
return Err;
}
// Returns false only if exactly one of the SYCL bundle entry (CodeObject)
// and the requested -targets ID (Target) has a target ID, e.g. entry
// sycl-spir64_gen-unknown-unknown and target
// sycl-spir64_gen-unknown-unknown-pvc. Such a match relies on the ID-less
// fallback. Only whether a target ID is present is checked, not its value.
auto TargetIDPresenceMatches = [](const OffloadTargetInfo &CodeObject,
const OffloadTargetInfo &Target) {
return CodeObject.OffloadKind != "sycl" ||
CodeObject.TargetID.empty() == Target.TargetID.empty();
};
// Returns true if the blob has an entry that matches \p Target without the
// ID-less fallback.
auto HasExactEntry = [&](const OffloadTargetInfo &Target) {
return llvm::any_of(BundleIDs, [&](StringRef ID) {
OffloadTargetInfo CodeObject(ID, BundlerConfig);
return TargetIDPresenceMatches(CodeObject, Target) &&
isCodeObjectCompatible(CodeObject, Target);
});
};

// Drain worklist entries satisfied by this blob.
while (!Worklist.empty()) {
Expected<std::optional<StringRef>> CurTripleOrErr =
Expand All @@ -1971,13 +2030,26 @@ Error OffloadBundler::UnbundleFiles() {
return createStringError(errc::invalid_argument,
"invalid bundle id read from the bundle");

auto Output = Worklist.begin();
for (auto E = Worklist.end(); Output != E; Output++) {
if (isCodeObjectCompatible(
OffloadTargetInfo(CurTriple, BundlerConfig),
OffloadTargetInfo((*Output).first(), BundlerConfig)))
break;
}
OffloadTargetInfo CodeObject(CurTriple, BundlerConfig);
// First, look for a requested -targets ID (Target) that this bundle
// entry (CodeObject) matches exactly, e.g. entry
// sycl-spir64_gen-unknown-unknown-pvc for target
// sycl-spir64_gen-unknown-unknown-pvc.
auto Output = llvm::find_if(Worklist, [&](const auto &W) {
OffloadTargetInfo Target(W.first(), BundlerConfig);
return TargetIDPresenceMatches(CodeObject, Target) &&
isCodeObjectCompatible(CodeObject, Target);
});
// Otherwise, an ID-less SYCL entry (e.g. sycl-spir64_gen-unknown-unknown)
// may be used for a target with a target ID, or the reverse, but only if
// the blob has no exact entry for that target.
if (Output == Worklist.end())
Output = llvm::find_if(Worklist, [&](const auto &W) {
OffloadTargetInfo Target(W.first(), BundlerConfig);
Comment thread
srividya-sundaram marked this conversation as resolved.
return !TargetIDPresenceMatches(CodeObject, Target) &&
isCodeObjectCompatible(CodeObject, Target) &&
!HasExactEntry(Target);
});

if (Output == Worklist.end())
continue;
Expand Down
80 changes: 80 additions & 0 deletions clang/test/OffloadTools/clang-offload-bundler/sycl-target-id.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// REQUIRES: x86-registered-target

// SYCL bundle entry IDs use a 3-component triple followed by the target ID,
// e.g. sycl-spir64_gen-unknown-unknown-pvc. Check that each target ID is
// unbundled to its own code object.

// RUN: %clang -O0 -target x86_64-unknown-linux-gnu %s -c -o %t.o
// RUN: echo 'host' > %t.host
// RUN: echo 'tgt1' > %t.tgt1
// RUN: echo 'tgt2' > %t.tgt2

// Text bundles.
// RUN: clang-offload-bundler -type=ii -input=%t.host -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.ii \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-spir64_gen-unknown-unknown-tgllp,sycl-spir64_gen-unknown-unknown-pvc
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.ii -output=%t.res1 -output=%t.res2 -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-tgllp,sycl-spir64_gen-unknown-unknown-pvc
// RUN: diff %t.tgt1 %t.res1
// RUN: diff %t.tgt2 %t.res2
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-pvc
// RUN: diff %t.tgt2 %t.res

// RUN: clang-offload-bundler -type=ii -input=%t.host -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.nv.ii \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-nvptx64-nvidia-cuda-sm_80,sycl-nvptx64-nvidia-cuda-sm_90
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.nv.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-nvptx64-nvidia-cuda-sm_90
// RUN: diff %t.tgt2 %t.res

// Object bundles, as produced for -fsycl-targets=intel_gpu_* with and without
// -fno-sycl-rdc. With -fno-sycl-rdc, the old offloading model names the SPIR
// AOT triple spir64_gen_image.
// RUN: clang-offload-bundler -type=o -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.o \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-spir64_gen-unknown-unknown-tgllp,sycl-spir64_gen-unknown-unknown-pvc
// RUN: clang-offload-bundler -type=o -input=%t.bundle.o -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-pvc
// RUN: diff %t.tgt2 %t.res
Comment thread
srividya-sundaram marked this conversation as resolved.
// RUN: clang-offload-bundler -type=o -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.image.o \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-spir64_gen_image-unknown-unknown-tgllp,sycl-spir64_gen_image-unknown-unknown-pvc
// RUN: clang-offload-bundler -type=o -input=%t.bundle.image.o -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen_image-unknown-unknown-pvc
Comment thread
srividya-sundaram marked this conversation as resolved.
// RUN: diff %t.tgt2 %t.res

// A SYCL code object without a target ID is still compatible with any target
// ID of the same triple, and vice versa.
// RUN: clang-offload-bundler -type=ii -input=%t.host -input=%t.tgt1 -output=%t.bundle.noid.ii \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-spir64_gen-unknown-unknown
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.noid.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-pvc
// RUN: diff %t.tgt1 %t.res
// With no exact match for a target without a target ID, the first compatible
// entry is used (tgllp here, as it comes before pvc in the bundle).
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown
Comment thread
srividya-sundaram marked this conversation as resolved.
// RUN: diff %t.tgt1 %t.res

// With entries both with and without a target ID, an exact target ID match is
// used regardless of the order of the entries.
// RUN: echo 'noid' > %t.noid
// RUN: clang-offload-bundler -type=ii -input=%t.host -input=%t.noid -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.mixed.ii \
// RUN: -targets=host-x86_64-unknown-linux-gnu,sycl-spir64_gen-unknown-unknown,sycl-spir64_gen-unknown-unknown-tgllp,sycl-spir64_gen-unknown-unknown-pvc
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.mixed.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-pvc
// RUN: diff %t.tgt2 %t.res
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.mixed.ii -output=%t.res1 -output=%t.res2 -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-tgllp,sycl-spir64_gen-unknown-unknown
// RUN: diff %t.tgt1 %t.res1
// RUN: diff %t.noid %t.res2
// The entry without a target ID is used for a target ID with no exact entry.
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.mixed.ii -output=%t.res -unbundle \
// RUN: -targets=sycl-spir64_gen-unknown-unknown-acm_g10
// RUN: diff %t.noid %t.res

// 4-component triples are unaffected.
// RUN: clang-offload-bundler -type=ii -input=%t.host -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.hip.ii \
// RUN: -targets=host-x86_64-unknown-linux-gnu,hipv4-amdgcn-amd-amdhsa--gfx908,hipv4-amdgcn-amd-amdhsa--gfx90a
// RUN: clang-offload-bundler -type=ii -input=%t.bundle.hip.ii -output=%t.res -unbundle \
// RUN: -targets=hipv4-amdgcn-amd-amdhsa--gfx90a
// RUN: diff %t.tgt2 %t.res

int A = 0;
Loading