diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index c5a96958cdcfc..57de189a42dcf 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -345,6 +345,8 @@ def warn_drv_sycl_offload_target_duplicate : Warning< def warn_drv_sycl_target_missing : Warning< "linked binaries do not contain expected '%0' target; found targets: '%1'">, InGroup; +def err_drv_multiple_target_with_forced_target : Error< + "multiple target usage with '%0' is not supported with '%1'">; def err_drv_failed_to_deduce_target_from_arch : Error< "failed to deduce triple for target architecture '%0'; specify the triple " "using '-fopenmp-targets' and '-Xopenmp-target' instead.">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index aa96b0e8b31d5..09d2ccf35727a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2848,6 +2848,10 @@ def fsycl_link_targets_EQ : CommaJoined<["-"], "fsycl-link-targets=">, Flags<[NoXarchOption, CC1Option, CoreOption, Deprecated]>, HelpText<"Specify comma-separated list of triples SYCL offloading targets " "to produce linked device images (deprecated)">; +def fsycl_force_target_EQ : Joined<["-"], "fsycl-force-target=">, + Flags<[NoXarchOption, CoreOption]>, + HelpText<"Force the usage of the given triple when extracting device code " + "from any given objects on the command line">; def fsycl_device_code_split_EQ : Joined<["-"], "fsycl-device-code-split=">, Flags<[CC1Option, CoreOption]>, HelpText<"Perform SYCL device code split: per_kernel (device code module is " "created for each SYCL kernel) | per_source (device code module is created for each source (translation unit)) | off (no device code split). | auto (use heuristic to select the best way of splitting device code). " diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index a3c554be5ab84..c570a1b4e0e98 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -785,6 +785,8 @@ static bool addSYCLDefaultTriple(Compilation &C, /// Returns true if a triple is added to SYCLTriples, false otherwise if (!C.getDriver().isSYCLDefaultTripleImplied()) return false; + if (C.getInputArgs().hasArg(options::OPT_fsycl_force_target_EQ)) + return false; for (const auto &SYCLTriple : SYCLTriples) { if (SYCLTriple.getSubArch() == llvm::Triple::NoSubArch && SYCLTriple.isSPIR()) @@ -1057,6 +1059,14 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, C.getInputArgs().getLastArg(options::OPT_fsycl_device_code_split_EQ), {"per_kernel", "per_source", "auto", "off"}); + Arg *SYCLForceTarget = + getArgRequiringSYCLRuntime(options::OPT_fsycl_force_target_EQ); + if (SYCLForceTarget) { + StringRef Val(SYCLForceTarget->getValue()); + llvm::Triple TT(MakeSYCLDeviceTriple(Val)); + if (!isValidSYCLTriple(TT)) + Diag(clang::diag::err_drv_invalid_sycl_target) << Val; + } bool HasSYCLTargetsOption = SYCLTargets || SYCLLinkTargets || SYCLAddTargets; llvm::StringMap FoundNormalizedTriples; llvm::SmallVector UniqueSYCLTriplesVec; @@ -1066,6 +1076,15 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, Arg *SYCLTargetsValues = SYCLTargets ? SYCLTargets : SYCLLinkTargets; if (SYCLTargetsValues) { if (SYCLTargetsValues->getNumValues()) { + + // Multiple targets are currently not supported when using + // -fsycl-force-target as the bundler does not allow for multiple + // outputs of the same target. + if (SYCLForceTarget && SYCLTargetsValues->getNumValues() > 1) + Diag(clang::diag::err_drv_multiple_target_with_forced_target) + << SYCLTargetsValues->getAsString(C.getInputArgs()) + << SYCLForceTarget->getAsString(C.getInputArgs()); + for (StringRef Val : SYCLTargetsValues->getValues()) { llvm::Triple TT(MakeSYCLDeviceTriple(Val)); if (!isValidSYCLTriple(TT)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index bf02a95694d17..7b8306228a57b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -8916,7 +8916,16 @@ void OffloadBundler::ConstructJobMultipleOutputs( Triples += ','; Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); Triples += '-'; - Triples += Dep.DependentToolChain->getTriple().normalize(); + // When -fsycl-force-target is used, this value overrides the expected + // output type we are unbundling. + if (Dep.DependentOffloadKind == Action::OFK_SYCL && + TCArgs.hasArg(options::OPT_fsycl_force_target_EQ)) { + StringRef Val( + TCArgs.getLastArg(options::OPT_fsycl_force_target_EQ)->getValue()); + llvm::Triple TT(C.getDriver().MakeSYCLDeviceTriple(Val)); + Triples += TT.normalize(); + } else + Triples += Dep.DependentToolChain->getTriple().normalize(); if ((Dep.DependentOffloadKind == Action::OFK_HIP || Dep.DependentOffloadKind == Action::OFK_OpenMP || Dep.DependentOffloadKind == Action::OFK_Cuda || diff --git a/clang/test/Driver/sycl-force-target.cpp b/clang/test/Driver/sycl-force-target.cpp new file mode 100644 index 0000000000000..5de5d2d07cf22 --- /dev/null +++ b/clang/test/Driver/sycl-force-target.cpp @@ -0,0 +1,26 @@ +/// Verify the usage of -fsycl-force-target applies to all expected unbundlings +// RUN: touch %t.o +// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen -fsycl-force-target=spir64 \ +// RUN: %s --sysroot=%S/Inputs/SYCL %t.o -### 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK_FORCE_TARGET +// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen \ +// RUN: -fsycl-force-target=spir64-unknown-unknown \ +// RUN: %s --sysroot=%S/Inputs/SYCL %t.o -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=CHECK_FORCE_TARGET,CHECK_FORCE_TARGET_GEN +// RUN: %clangxx -fsycl -fsycl-targets=spir64_x86_64 \ +// RUN: -fsycl-force-target=spir64 %s \ +// RUN: --sysroot=%S/Inputs/SYCL %t.o -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=CHECK_FORCE_TARGET,CHECK_FORCE_TARGET_CPU +// CHECK_FORCE_TARGET: clang-offload-bundler{{.*}} "-type=o" "-targets=host-{{.*}},sycl-spir64-unknown-unknown" "-input={{.*}}" "-output={{.*}}" "-output=[[DEVICEOBJECTOUT:.+]]" "-unbundle" "-allow-missing-bundles" +// CHECK_FORCE_TARGET: spirv-to-ir-wrapper{{.*}} "[[DEVICEOBJECTOUT]]" "-o" "[[DEVICEOBJECTBC:.+\.bc]]" +// CHECK_FORCE_TARGET: llvm-link{{.*}} "[[DEVICEOBJECTBC]]"{{.*}} "-o" "[[DEVICEOBJLINKED:.+\.bc]]" "--suppress-warnings" +// CHECK_FORCE_TARGET: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown" "-input={{.*}}libsycl-complex{{.*}}" "-output={{.*}}libsycl-complex-{{.*}}" "-unbundle" +// CHECK_FORCE_TARGET_GEN: llvm-foreach{{.*}} {{.*}}ocloc{{.*}} +// CHECK_FORCE_TARGET_CPU: llvm-foreach{{.*}} {{.*}}opencl-aot{{.*}} + +/// -fsycl-force-target is only valid with -fsycl-target with single targets +// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen,spir64_x86_64 \ +// RUN: -fsycl-force-target=spir64 %s -### 2>&1 \ +// RUN: | FileCheck %s -check-prefix=MULTIPLE_TARGET +// MULTIPLE_TARGET: error: multiple target usage with '-fsycl-targets=spir64_gen,spir64_x86_64' is not supported with '-fsycl-force-target=spir64' + diff --git a/sycl/doc/UsersManual.md b/sycl/doc/UsersManual.md index 60c295d503dc2..5b9a38671fdf6 100644 --- a/sycl/doc/UsersManual.md +++ b/sycl/doc/UsersManual.md @@ -225,6 +225,14 @@ and not recommended to use in production environment. NOTE: This option is currently only supported on Linux. +**`-fsycl-force-target=`** + + When used along with '-fsycl-targets', force the device object being + unbundled to match the target given. This allows the user to override + the expected unbundling type even though the target given does not match. + The forced target applies to all objects, archives and default device + libraries. + ## Intel FPGA specific options **`-fintelfpga`**