Skip to content

Commit 431a278

Browse files
authored
[SYCL] Fix handling of comma separated arch value when calling llvm-offload-binary (#20130)
Because `llvm-offload-binary` uses commas to separate the key-values pairs when specifying an image, we cannot specify a value that contains a comma without some special handling. However, if you specify the same key multiple times when calling `llvm-offload-binary`, the keys will be concatenated together with commas in between. So if we want, for example, the image to have an `arch` of `pvc,bdw`, we can call `llvm-offload-binary` with `arch=pvc,arch=bdw` to achieve this.
1 parent 61cbf89 commit 431a278

File tree

4 files changed

+86
-18
lines changed

4 files changed

+86
-18
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10260,6 +10260,18 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
1026010260
"kind=" + Kind.str(),
1026110261
};
1026210262

10263+
// When compiling like -fsycl-targets=spir64_gen -Xsycl-target-backend
10264+
// "-device pvc,bdw", the offloading arch will be "pvc,bdw", which
10265+
// contains a comma. Because the comma is used to separate fields
10266+
// within the --image option, we cannot pass arch=pvc,bdw directly.
10267+
// Instead, we pass it like arch=pvc,arch=bdw, then
10268+
// llvm-offload-binary joins them back to arch=pvc,bdw.
10269+
SmallVector<StringRef> Archs;
10270+
Arch.split(Archs, ',');
10271+
if (Archs.size() > 1) {
10272+
Parts[2] = "arch=" + llvm::join(Archs, ",arch=");
10273+
}
10274+
1026310275
if (TC->getDriver().isUsingOffloadLTO())
1026410276
for (StringRef Feature : FeatureArgs)
1026510277
Parts.emplace_back("feature=" + Feature.str());
@@ -10283,7 +10295,13 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
1028310295
AL += " ";
1028410296
AL += A;
1028510297
}
10286-
Parts.emplace_back(C.getArgs().MakeArgString(Twine(Opt) + AL));
10298+
// As mentioned earlier, we cannot pass a value with commas directly,
10299+
// but llvm-offload-binary joins multiple occurrences of the same
10300+
// option separated by commas, so we split the value on
10301+
// all commas and pass them as separate arguments.
10302+
for (StringRef Split : llvm::split(AL, ',')) {
10303+
Parts.emplace_back(C.getArgs().MakeArgString(Twine(Opt) + Split));
10304+
}
1028710305
};
1028810306
const ArgList &Args =
1028910307
C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_SYCL);
@@ -10292,10 +10310,10 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
1029210310
static_cast<const toolchains::SYCLToolChain &>(*TC);
1029310311
SYCLTC.AddImpliedTargetArgs(TC->getTriple(), Args, BuildArgs, JA, *HostTC,
1029410312
Arch);
10295-
SYCLTC.TranslateBackendTargetArgs(TC->getTriple(), Args, BuildArgs, Arch);
10313+
SYCLTC.TranslateBackendTargetArgs(TC->getTriple(), Args, BuildArgs);
1029610314
createArgString("compile-opts=");
1029710315
BuildArgs.clear();
10298-
SYCLTC.TranslateLinkerTargetArgs(TC->getTriple(), Args, BuildArgs, Arch);
10316+
SYCLTC.TranslateLinkerTargetArgs(TC->getTriple(), Args, BuildArgs);
1029910317
createArgString("link-opts=");
1030010318
}
1030110319

clang/test/Driver/sycl-ftarget-compile-fast.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// RUN: | FileCheck -check-prefix=TARGET_COMPILE_FAST_GEN %s
99

1010
// TARGET_COMPILE_FAST_GEN: llvm-offload-binary
11-
// TARGET_COMPILE_FAST_GEN: compile-opts={{.*}}-options -igc_opts 'PartitionUnit=1,SubroutineThreshold=50000'
11+
// TARGET_COMPILE_FAST_GEN: compile-opts={{.*}}-options -igc_opts 'PartitionUnit=1,compile-opts=SubroutineThreshold=50000'
1212

1313
// RUN: %clang -### -target x86_64-unknown-linux-gnu -fsycl --offload-new-driver \
1414
// RUN: -ftarget-compile-fast %s 2>&1 \

clang/test/Driver/sycl-offload-new-driver.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
// RUN: %clangxx -fsycl -### -fsycl-targets=spir64_gen --offload-new-driver \
189189
// RUN: -Xsycl-target-backend=spir64_gen "-device pvc,bdw" %s 2>&1 \
190190
// RUN: | FileCheck -check-prefix COMMA_FILE %s
191-
// COMMA_FILE: llvm-offload-binary{{.*}} "--image=file={{.*}}pvc@bdw{{.*}},triple=spir64_gen-unknown-unknown,arch=pvc,bdw,kind=sycl,compile-opts=-device_options pvc -ze-intel-enable-auto-large-GRF-mode"
191+
// COMMA_FILE: llvm-offload-binary{{.*}} "--image=file={{.*}}pvc@bdw{{.*}},triple=spir64_gen-unknown-unknown,arch=pvc,arch=bdw,kind=sycl,compile-opts=-device_options pvc -ze-intel-enable-auto-large-GRF-mode -device pvc,compile-opts=bdw"
192192

193193
/// Verify the arch value for the packager is populated with different
194194
/// scenarios for spir64_gen
@@ -212,6 +212,52 @@
212212
// RUN: | FileCheck -check-prefix ARCH_CHECK %s
213213
// ARCH_CHECK: llvm-offload-binary{{.*}} "--image=file={{.*}}triple=spir64_gen-unknown-unknown,arch=bdw,kind=sycl{{.*}}"
214214

215+
// Verify when a comma-separated list of architectures is provided in -device, they are
216+
// passed to llvm-offload-binary correctly.
217+
// RUN: %clangxx -fsycl -### -fsycl-targets=spir64_gen --offload-new-driver \
218+
// RUN: -Xsycl-target-backend "-device pvc,bdw" %s 2>&1 \
219+
// RUN: | FileCheck -check-prefix MULTI_ARCH %s
220+
// RUN: %clangxx -fsycl -### -fsycl-targets=spir64_gen --offload-new-driver \
221+
// RUN: -Xsycl-target-backend=spir64_gen "-device pvc,bdw" %s 2>&1 \
222+
// RUN: | FileCheck -check-prefix MULTI_ARCH %s
223+
// RUN: %clangxx -fsycl -### -fsycl-targets=spir64_gen --offload-new-driver \
224+
// RUN: -Xs "-device pvc,bdw" %s 2>&1 \
225+
// RUN: | FileCheck -check-prefix MULTI_ARCH %s
226+
// MULTI_ARCH: llvm-offload-binary{{.*}} "--image=file={{.*}}triple=spir64_gen-unknown-unknown,arch=pvc,arch=bdw,kind=sycl
227+
// MULTI_ARCH-SAME: compile-opts=-device_options pvc -ze-intel-enable-auto-large-GRF-mode -device pvc,compile-opts=bdw"
228+
229+
// Verify that when an object produced by llvm-offload-binary with multiple Intel GPU architectures
230+
// clang-linker-wrapper will call ocloc with -device listing all architectures.
231+
// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen --offload-new-driver \
232+
// RUN: -Xsycl-target-backend=spir64_gen "-device pvc,bdw" -c %s -o %t_multiarch_test.o
233+
// RUN: clang-linker-wrapper --dry-run --linker-path=/usr/bin/ld \
234+
// RUN: --host-triple=x86_64-unknown-linux-gnu %t_multiarch_test.o 2>&1 \
235+
// RUN: | FileCheck -check-prefix=OCLOC_MULTI_ARCH %s
236+
// OCLOC_MULTI_ARCH: ocloc{{.*}}-device pvc,bdw
237+
238+
// Verify for multiple targets with -Xsycl-target-backend= with commas in the values
239+
// are passed correctly to llvm-offload-binary.
240+
// RUN: %clangxx -fsycl -### --offload-new-driver \
241+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda,amdgcn-amd-amdhsa,spir64_gen \
242+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx908,gfx1010 \
243+
// RUN: -Xsycl-target-backend=nvptx64-nvidia-cuda --offload-arch=sm_86,sm_87,sm_89 \
244+
// RUN: -Xsycl-target-backend=spir64_gen "-device pvc,bdw" \
245+
// RUN: -Xsycl-target-linker=spir64_gen "-DFOO,BAR" \
246+
// RUN: -nogpulib %s 2>&1 | FileCheck -check-prefix=MULTI_ARCH2 %s
247+
// MULTI_ARCH2: llvm-offload-binary{{.*}} "--image=file={{.*}}triple=amdgcn-amd-amdhsa,arch=gfx1010,kind=sycl,compile-opts=--offload-arch=gfx908,compile-opts=gfx1010"
248+
// MULTI_ARCH2-SAME: "--image=file={{.*}}triple=amdgcn-amd-amdhsa,arch=gfx908,kind=sycl,compile-opts=--offload-arch=gfx908,compile-opts=gfx1010"
249+
// MULTI_ARCH2-SAME: "--image=file={{.*}}triple=nvptx64-nvidia-cuda,arch=sm_86,kind=sycl,compile-opts=--offload-arch=sm_86,compile-opts=sm_87,compile-opts=sm_89"
250+
// MULTI_ARCH2-SAME: "--image=file={{.*}}triple=nvptx64-nvidia-cuda,arch=sm_87,kind=sycl,compile-opts=--offload-arch=sm_86,compile-opts=sm_87,compile-opts=sm_89"
251+
// MULTI_ARCH2-SAME: "--image=file={{.*}}triple=nvptx64-nvidia-cuda,arch=sm_89,kind=sycl,compile-opts=--offload-arch=sm_86,compile-opts=sm_87,compile-opts=sm_89"
252+
// MULTI_ARCH2-SAME: "--image=file={{.*}}triple=spir64_gen-unknown-unknown,arch=pvc,arch=bdw,kind=sycl,compile-opts=-device_options pvc -ze-intel-enable-auto-large-GRF-mode -device pvc,compile-opts=bdw,link-opts=-DFOO,link-opts=BAR"
253+
254+
// Verify that the driver correctly handles link-opt and compile-opt values with commas
255+
// RUN: %clangxx -fsycl -### -fsycl-targets=spir64_gen --offload-new-driver \
256+
// RUN: -Xsycl-target-backend "-device bdw -FOO a,b" \
257+
// RUN: -Xsycl-target-linker "-BAR x,y" %s 2>&1 \
258+
// RUN: | FileCheck -check-prefix COMMA_OPTS %s
259+
// COMMA_OPTS: llvm-offload-binary{{.*}} "--image=file={{.*}}triple=spir64_gen-unknown-unknown,arch=bdw,kind=sycl,compile-opts=-device bdw -FOO a,compile-opts=b,link-opts=-BAR x,link-opts=y"
260+
215261
/// Verify that --cuda-path is passed to clang-linker-wrapper for SYCL offload
216262
// RUN: %clangxx -fsycl -### -fsycl-targets=nvptx64-nvidia-cuda -fno-sycl-libspirv \
217263
// RUN: --cuda-gpu-arch=sm_20 --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda %s \

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -943,24 +943,29 @@ static void addSYCLBackendOptions(const ArgList &Args,
943943
if (IsCPU) {
944944
BackendOptions.split(CmdArgs, " ", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
945945
} else {
946-
// ocloc -options args need to be comma separated, e.g. `-options
947-
// "-g,-cl-opt-disable"`. Otherwise, only the first arg is processed by
948-
// ocloc as an arg for -options, and the rest are processed as standalone
949-
// flags, possibly leading to errors.
946+
// ocloc -options takes arguments in the form of '-options "-g
947+
// -cl-opt-disable"' where each argument is separated with spaces.
950948
// split function here returns a pair with everything before the separator
951949
// ("-options") in the first member of the pair, and everything after the
952950
// separator in the second part of the pair. The separator is not included
953951
// in any of them.
954952
auto [BeforeOptions, AfterOptions] = BackendOptions.split("-options ");
955953
// Only add if not empty, an empty arg can lead to ocloc errors.
956-
if (!BeforeOptions.empty())
957-
CmdArgs.push_back(BeforeOptions);
954+
if (!BeforeOptions.empty()) {
955+
SmallVector<StringRef, 8> BeforeArgs;
956+
BeforeOptions.split(BeforeArgs, " ", /*MaxSplit=*/-1,
957+
/*KeepEmpty=*/false);
958+
for (const auto &string : BeforeArgs) {
959+
CmdArgs.push_back(string);
960+
}
961+
}
958962
if (!AfterOptions.empty()) {
959-
// Separator not included by the split function, so explicitly added here.
960963
CmdArgs.push_back("-options");
961-
std::string Replace = AfterOptions.str();
962-
std::replace(Replace.begin(), Replace.end(), ' ', ',');
963-
CmdArgs.push_back(Args.MakeArgString(Replace));
964+
// Split the options string by spaces and rejoin to normalize whitespace
965+
SmallVector<StringRef, 8> AfterArgs;
966+
AfterOptions.split(AfterArgs, " ", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
967+
std::string JoinedOptions = llvm::join(AfterArgs, " ");
968+
CmdArgs.push_back(Args.MakeArgString(JoinedOptions));
964969
}
965970
}
966971

@@ -1441,9 +1446,8 @@ static Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
14411446
if (ExtractedDeviceLibFiles.empty()) {
14421447
// TODO: Add NVPTX when ready
14431448
if (Triple.isSPIROrSPIRV())
1444-
return createStringError(
1445-
inconvertibleErrorCode(),
1446-
" SYCL device library file list cannot be empty.");
1449+
WithColor::warning(errs(), LinkerExecutable)
1450+
<< "SYCL device library file list is empty\n";
14471451
return *LinkedFile;
14481452
}
14491453

0 commit comments

Comments
 (0)