[SYCL] Add support for passing multiple archs in command line - #22945
[SYCL] Add support for passing multiple archs in command line#22945bviyer wants to merge 5 commits into
Conversation
I think we need to fix this design issue to enable support for "multiple archs" i.e. we must use a dedicated key for each
Joining all options into a single value to reparse them again in clang-link-wrapper tool requires implementing non-trivial logic which is a source of bugs. As Mike noted in his comment, dd9abc1 replaces this approach with simplified logic to fix one of such bugs. I suggest we don't bring it back. |
I have put it back. I also added a e2e test. |
| // WRAPPER_OPTIONS_MULTI_GEN-SAME: "--device-compiler=sycl:spir64_gen-unknown-unknown/pvc=-extraopt_pvc" | ||
| // WRAPPER_OPTIONS_MULTI_GEN-SAME: "--device-compiler=sycl:spir64_gen-unknown-unknown/skl=-extraopt_skl" | ||
| // WRAPPER_OPTIONS_MULTI_GEN-NOT: "--device-compiler=sycl:spir64_gen-unknown-unknown/pvc=-extraopt_skl" | ||
| // WRAPPER_OPTIONS_MULTI_GEN-NOT: "--device-compiler=sycl:spir64_gen-unknown-unknown/skl=-extraopt_pvc" |
There was a problem hiding this comment.
Can a test be added that verifies the mixing of intel_gpu* and spir64_gen with -device usage where the target is the same? e.g.: -fsycl --offload-new-driver -fsycl-targets=spir64_gen,intel_gpu_skl -Xsycl-target-backend=spir64_gen "-device skl -options extraopt_skl1" -Xsycl-target-backend=intel_gpu_skl "-options -extraopt_skl2"?
There was a problem hiding this comment.
The test was added, but it only asserts the driver's argv, not the ocloc argv. Could you please add ocloc checks as well to make sure merging of options works as expected?
196d3a8 to
d5cc96a
Compare
|
@intel/llvm-gatekeepers please consider merging |
Co-authored-by: Yury Plyakhin <yury.plyakhin@intel.com>
YuriPlyakhin
left a comment
There was a problem hiding this comment.
Please, update sycl/doc/design/OffloadDesign.md in this PR as well.
It documents --device-compiler=[<kind>:][<triple>=]<value>
I think we should document:
[<kind>:][<triple>[/<arch>]=]<value>format- the multi-arch example needs update
- one token per occurrence
- what happens with no
/<arch>provided
| Triple.getSubArch() == llvm::Triple::SPIRSubArch_gen; | ||
| if (IsGenTriple) { | ||
| if (Device != GenDevice && !Device.empty()) | ||
| if (!GenDevice.empty() && Device != GenDevice && !Device.empty()) |
There was a problem hiding this comment.
It seems to change old offload model ocloc invocations.
Could you please check these examples, before and after your change - what does each call to ocloc receives?
clang++ -fsycl -fsycl-targets=intel_gpu_dg1 -Xsycl-target-backend=spir64_gen "-DFOO"
clang++ -fsycl -fsycl-targets=intel_gpu_dg1,spir64_gen,intel_gpu_skl -Xsycl-target-backend=spir64_gen "-device skl -DSKL" -Xsycl-target-backend=intel_gpu_skl "-DSKL2"
Please, look at CHECK_TOOLS_BEOPTS test case in clang/test/Driver/sycl-oneapi-gpu-intelgpu.cpp, I think it can be used to verify the change before/after. The checks there are loose, so they might not catch the change.
If old offloading model behavior changes, I think we need to decide, if it is what we want...
| // RUN: -fsycl-targets=spir64_gen,intel_gpu_skl \ | ||
| // RUN: -Xsycl-target-backend=spir64_gen "-device skl -options extraopt_skl1" \ | ||
| // RUN: -Xsycl-target-backend=intel_gpu_skl "-options -extraopt_skl2" \ |
There was a problem hiding this comment.
In the new model these two -fsycl-targets entries collapse to a single arch (skl), so both option groups reach one ocloc invocation, right?
In the old offload model, it seems we wanted different behavior, check clang/test/Driver/sycl-oneapi-gpu-intelgpu.cpp, specifically:
/// Check that ocloc backend option settings only occur for the expected
/// toolchains when mixing spir64_gen and intel_gpu
// RUN: %clangxx -fsycl -fsycl-targets=intel_gpu_dg1,spir64_gen,intel_gpu_skl \
// RUN: -Xsycl-target-backend=spir64_gen "-device skl -DSKL" \
// RUN: -Xsycl-target-backend=intel_gpu_dg1 "-DDG1" \
// RUN: -Xsycl-target-backend=intel_gpu_skl "-DSKL2" \
// RUN: --no-offloadlib -fno-sycl-instrument-device-code \
// RUN: -target x86_64-unknown-linux-gnu -### %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK_TOOLS_BEOPTS
// CHECK_TOOLS_BEOPTS: ocloc{{.*}} "-device" "dg1"{{.*}}"-DDG1"
// CHECK_TOOLS_BEOPTS: ocloc{{.*}} "-device" "skl"{{.*}}"-DSKL"
// CHECK_TOOLS_BEOPTS: ocloc{{.*}} "-device" "skl"{{.*}}"-DSKL2"
| llvm::cl::TokenizeGNUCommandLine(Value, S, Tokens); | ||
| bool EmbDeviceNoMatch = false; | ||
| for (size_t I = 0; I + 1 < Tokens.size(); ++I) { | ||
| if (StringRef(Tokens[I]) == "-device") { |
There was a problem hiding this comment.
There are two -device scanners now, with semantics that disagree.
Please, check: Driver::getOffloadArchs (Driver.cpp:7925) — scans right-to-left, grabs the right most entry
This one — scans left-to-right, takes the left most entry.
So -Xsycl-target-backend=spir64_gen "-device pvc -device skl" gives Arch=skl from getOffloadArchs
but routes options against pvc here.
Is it possible to make a single helper?
What happens with the cases like -device pvc,bdw?
| SmallVector<const char *, 8> Tokens; | ||
| llvm::BumpPtrAllocator Alloc; | ||
| llvm::StringSaver S(Alloc); | ||
| llvm::cl::TokenizeGNUCommandLine(Value, S, Tokens); |
There was a problem hiding this comment.
nit
This tokenizes A->getValue(1), and parseTargetOpts tokenizes the same string again a few lines below.
Consider refactoring, if practical.
| // WRAPPER_OPTIONS_MULTI_GEN-NOT: "--device-compiler=sycl:spir64_gen-unknown-unknown/pvc=-extraopt_skl" | ||
| // WRAPPER_OPTIONS_MULTI_GEN-NOT: "--device-compiler=sycl:spir64_gen-unknown-unknown/skl=-extraopt_pvc" |
There was a problem hiding this comment.
Everything is on one clang-linker-wrapper line, so a cross-contaminated entry appearing earlier on that line would not be caught. Use --implicit-check-not=....
| // (runtime check). | ||
|
|
||
| // REQUIRES: ocloc, target-spir | ||
| // REQUIRES: arch-intel_gpu_pvc |
There was a problem hiding this comment.
I think compile-time test should be enough for this PR. I don't see why we need to run it.
Could you please consider dropping %{run} and the PVC requirement REQUIRES: arch-intel_gpu_pvc (but keep REQUIRES: ocloc)?
I think we may also have some other lit parameter that specifies "build only" tests, maybe we can apply it as well.
We want this test to run each time, when the build of E2E tests is happening.
Also please, check if we have ocloc on the systems, which are used to build E2E tests.
Thanks!
| // For spir64_gen the value is qualified with "/<arch>" and emitted per | ||
| // (triple, arch) to keep per-arch tokens from crossing across archs. |
There was a problem hiding this comment.
| // For spir64_gen the value is qualified with "/<arch>" and emitted per | |
| // (triple, arch) to keep per-arch tokens from crossing across archs. | |
| // For spir64_gen the key is qualified with "/<arch>" and emitted per | |
| // (triple, arch) to keep per-arch tokens from leaking between archs. |
| /// /skl bucket rather than land under different keys or drop each other. | ||
| // RUN: %clangxx --target=x86_64-unknown-linux-gnu -fsycl --offload-new-driver --sysroot=%S/Inputs/SYCL \ | ||
| // RUN: -fsycl-targets=spir64_gen,intel_gpu_skl \ | ||
| // RUN: -Xsycl-target-backend=spir64_gen "-device skl -options extraopt_skl1" \ |
There was a problem hiding this comment.
nit, for consistency with the next line
| // RUN: -Xsycl-target-backend=spir64_gen "-device skl -options extraopt_skl1" \ | |
| // RUN: -Xsycl-target-backend=spir64_gen "-device skl -options -extraopt_skl1" \ |
YuriPlyakhin
left a comment
There was a problem hiding this comment.
From description: The driver now emits one --device-compiler/--device-linker per (triple, arch) with tokens joined into a single value;
Is it still up-to-date statement?
There was a problem hiding this comment.
Please, consider the following case (pseudo-code):
fsycltargets=spir64_gen,pvc,skl
backendoption=spir64_gen "-device skl -DFOO1"
backendoption=spir64_gen "=-DFOO4"
backendoption=pvc "=-device pvc -DFOO2"
backendoption=skl "=-DFOO3"
I believe, the old model would call oclocs the following way (please, check that):
ocloc -device skl -DFOO1 -DFOO4
ocloc -device pvc -device pvc -DFOO2
ocloc -device skl -DFOO3
With the current patch, I think we will get (please check that):
ocloc "-device skl -DFOO1 -DFOO4 -DFOO3
ocloc "-device pvc -device pvc -DFOO2 -DFOO4
It doesn't make sense to keep spir64_gen in the new offloading model, but change the semantics. If we keep it in new offloading model, it should work the same way as in old offloading model.
Thinking aloud:
What if we introduce our internal arch, something like "aot_generic", and use it for spir64_gen, without trying to parse -device option? So all options, passed to `spir64_gen" would just end up as is in the single ocloc call? Would that work and match what the old offloading model does?
| // Raw spir64_gen entry: if the value embeds "-device X", route | ||
| // only to arch X. Absent -> shared, applies to every arch. |
There was a problem hiding this comment.
is this reproducing semantics of old offloading model?
| // CHECK-RAW-PVC: ocloc{{.*}} -device pvc {{.*}}-cl-mad-enable | ||
| // CHECK-RAW-PVC-NOT: ocloc{{.*}} -device pvc {{.*}}-cl-unsafe-math-optimizations | ||
| // CHECK-RAW-ACM: ocloc{{.*}} -device acm_g10 {{.*}}-cl-unsafe-math-optimizations | ||
| // CHECK-RAW-ACM-NOT: ocloc{{.*}} -device acm_g10 {{.*}}-cl-mad-enable |
There was a problem hiding this comment.
consider implicit-check-not in this and other cases to avoid test false-passing, because of order of parameters in the same line.
| // CHECK-RAW-ACM: ocloc{{.*}} -device acm_g10 {{.*}}-cl-unsafe-math-optimizations | ||
| // CHECK-RAW-ACM-NOT: ocloc{{.*}} -device acm_g10 {{.*}}-cl-mad-enable | ||
|
|
||
| #include <sycl/detail/core.hpp> |
There was a problem hiding this comment.
if we end up in build-only test, I think, the source code can be simplified.
|
@intel/llvm-gatekeepers please consider merging |
1 similar comment
|
@intel/llvm-gatekeepers please consider merging |
I am getting hte following output: Without my change (or the sycl branch): |
The clang-linker-wrapper --device-compiler=/--device-linker= channel did not distinguish between architectures sharing the same triple, so with
-fsycl-targets=spir64_gen,intel_gpu_sklplus per-target-Xsycl-target-backend, all options were emitted under a singlespir64_gen-unknown-unknownentry and per-arch tokens leaked across ocloc invocations (e.g. skl's options ended up on the pvc call and vice versa). The driver now emits one --device-compiler/--device-linker per (triple, arch) with tokens joined into a single value; gen entries carry a leading "-device " that the wrapper uses to route each value to the matching ocloc call, while values without "-device" (or from non-gen triples) still apply to every arch of the triple. This feature affects the new-offload-model only.