diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 2e40237d136e9..d638831ef9ce3 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -7273,6 +7273,8 @@ defm sycl_allow_device_image_dependencies: BoolOptionWithoutMarshalling<"f", "sy def fsycl_dump_device_code_EQ : Joined<["-"], "fsycl-dump-device-code=">, Flags<[NoXarchOption]>, HelpText<"Dump device code into the user provided directory.">; +def fsyclbin : Flag<["-"], "fsyclbin">, + HelpText<"Create a SYCLBIN file">; } // let Group = sycl_Group // FIXME: -fsycl-explicit-simd is deprecated. remove it when support is dropped. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 16afee088073a..87bffb83d6fb1 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1221,9 +1221,11 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // We need to generate a SYCL toolchain if the user specified -fsycl. // If -fsycl is supplied without any of these we will assume SPIR-V. // Use of -fsycl-device-only overrides -fsycl. + // Use of -fsyclbin enables SYCL device compilation. bool IsSYCL = C.getInputArgs().hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) || - C.getInputArgs().hasArg(options::OPT_fsycl_device_only); + C.getInputArgs().hasArgNoClaim(options::OPT_fsycl_device_only, + options::OPT_fsyclbin); auto argSYCLIncompatible = [&](OptSpecifier OptId) { if (!IsSYCL) @@ -3464,7 +3466,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Arg *InputTypeArg = nullptr; bool IsSYCL = Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) || - Args.hasArg(options::OPT_fsycl_device_only); + Args.hasArgNoClaim(options::OPT_fsycl_device_only, options::OPT_fsyclbin); // The last /TC or /TP option sets the input type to C or C++ globally. if (Arg *TCTP = Args.getLastArgNoClaim(options::OPT__SLASH_TC, @@ -7929,6 +7931,19 @@ Action *Driver::BuildOffloadingActions(Compilation &C, C.MakeAction(OffloadActions, types::TY_HIP_FATBIN); DDep.add(*FatbinAction, *C.getSingleOffloadToolChain(), nullptr, Action::OFK_HIP); + } else if (C.isOffloadingHostKind(Action::OFK_SYCL) && + Args.hasArg(options::OPT_fsyclbin)) { + // With '-fsyclbin', package all the offloading actions into a single output + // that is sent to the clang-linker-wrapper. + Action *PackagerAction = + C.MakeAction(OffloadActions, types::TY_Image); + ActionList PackagerActions; + PackagerActions.push_back(PackagerAction); + Action *LinkAction = + C.MakeAction(PackagerActions, types::TY_Image); + DDep.add(*LinkAction, *C.getSingleOffloadToolChain(), + nullptr, C.getActiveOffloadKinds()); + return C.MakeAction(DDep, types::TY_Nothing); } else { // Package all the offloading actions into a single output that can be // embedded in the host and linked. @@ -9336,8 +9351,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, if (AtTopLevel && !isa(JA) && !isa(JA)) { if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) return C.addResultFile(FinalOutput->getValue(), &JA); - // Output to destination for -fsycl-device-only and Windows -o - if (offloadDeviceOnly() && JA.getOffloadingDeviceKind() == Action::OFK_SYCL) + // Output to destination for -fsycl-device-only/-fsyclbin and Windows -o + if ((offloadDeviceOnly() || + C.getArgs().hasArgNoClaim(options::OPT_fsyclbin)) && + JA.getOffloadingDeviceKind() == Action::OFK_SYCL) if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_o)) return C.addResultFile(FinalOutput->getValue(), &JA); } @@ -9506,6 +9523,20 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, else BaseName = llvm::sys::path::filename(BasePath); + // When compiling with -fsyclbin, maintain a simple output file name for the + // resulting image. A '.syclbin' extension is used to represent the resulting + // output file. + if (JA.getOffloadingDeviceKind() == Action::OFK_SYCL && + C.getArgs().hasArgNoClaim(options::OPT_fsyclbin) && + JA.getType() == types::TY_Image) { + SmallString<128> SYCLBinOutput(getDefaultImageName()); + if (IsCLMode()) + // Use BaseName for the syclbin output name. + SYCLBinOutput = BaseName; + llvm::sys::path::replace_extension(SYCLBinOutput, ".syclbin"); + return C.addResultFile(C.getArgs().MakeArgString(SYCLBinOutput), &JA); + } + // Determine what the derived output name should be. const char *NamedOutput; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ba18e33ece294..a0a70d8fe2c5a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -11465,6 +11465,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString("--sycl-target-link-options=" + LinkOptString)); } + // Add option to enable creating of the .syclbin file. + if (Args.hasArg(options::OPT_fsyclbin)) + CmdArgs.push_back(Args.MakeArgString("--syclbin")); } // Construct the link job so we can wrap around it. diff --git a/clang/test/Driver/fsyclbin.cpp b/clang/test/Driver/fsyclbin.cpp new file mode 100644 index 0000000000000..43c9e5ec8469b --- /dev/null +++ b/clang/test/Driver/fsyclbin.cpp @@ -0,0 +1,69 @@ +/// Tests behaviors of -fsyclbin + +/// -fsyclbin is only used with the new offloading model. +// RUN: %clangxx -fsycl -fsyclbin --no-offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=UNUSED +// UNUSED: warning: argument unused during compilation: '-fsyclbin' + +/// -fsyclbin -fsycl-device-only usage. -fsycl-device-only will 'win' and +/// -fsyclbin is effectively ignored. +// RUN: %clangxx -fsycl-device-only -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=SYCLBIN_UNUSED +// RUN: %clang_cl -fsycl-device-only -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=SYCLBIN_UNUSED +// SYCLBIN_UNUSED: warning: argument unused during compilation: '-fsyclbin' + +/// Check tool invocation contents. +// RUN: %clangxx -fsycl -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_TOOLS +// RUN: %clangxx -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_TOOLS +// RUN: %clang_cl -fsycl -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_TOOLS +// CHECK_TOOLS: clang-offload-packager +// CHECK_TOOLS-SAME: --image=file={{.*}}.bc,triple=spir64-unknown-unknown +// CHECK_TOOLS-SAME: kind=sycl +// CHECK_TOOLS: clang-linker-wrapper +// CHECK_TOOLS-SAME: --syclbin + +/// Check compilation phases, only device compile should be performed +// RUN: %clangxx --target=x86_64-unknown-linux-gnu -fsycl -fsyclbin \ +// RUN: --offload-new-driver %s -ccc-print-phases 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_PHASES +// RUN: %clangxx --target=x86_64-unknown-linux-gnu -fsyclbin \ +// RUN: --offload-new-driver %s -ccc-print-phases 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_PHASES +// CHECK_PHASES: 0: input, "{{.*}}", c++, (device-sycl) +// CHECK_PHASES: 1: preprocessor, {0}, c++-cpp-output, (device-sycl) +// CHECK_PHASES: 2: compiler, {1}, ir, (device-sycl) +// CHECK_PHASES: 3: backend, {2}, ir, (device-sycl) +// CHECK_PHASES: 4: offload, "device-sycl (spir64-unknown-unknown)" {3}, ir +// CHECK_PHASES: 5: clang-offload-packager, {4}, image, (device-sycl) +// CHECK_PHASES: 6: clang-linker-wrapper, {5}, image, (device-sycl) +// CHECK_PHASES: 7: offload, "device-sycl (x86_64-unknown-linux-gnu)" {6}, none + +/// Check the output file names (file.syclbin, or -o ) +// RUN: %clangxx --target=x86_64-unknown-linux-gnu -fsyclbin \ +// RUN: --offload-new-driver -o file.syclbin %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_NAMED_OUTPUT +// CHECK_NAMED_OUTPUT: clang-linker-wrapper +// CHECK_NAMED_OUTPUT-SAME: "-o" "file.syclbin" + +// RUN: %clang_cl -fsyclbin --offload-new-driver -o file.syclbin %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_NAMED_OUTPUT_WIN +// CHECK_NAMED_OUTPUT_WIN: clang-linker-wrapper +// CHECK_NAMED_OUTPUT_WIN-SAME: "-out:file.syclbin" + +/// For Linux - the default is 'a.out' so the syclbin file is 'a.syclbin' +// RUN: %clangxx --target=x86_64-unknown-linux-gnu -fsyclbin \ +// RUN: --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_LINUX_DEFAULT_OUTPUT +// CHECK_LINUX_DEFAULT_OUTPUT: clang-linker-wrapper +// CHECK_LINUX_DEFAULT_OUTPUT-SAME: "-o" "a.syclbin" + +/// For Windows - the default is based on the source file so the syclbin file +/// is 'fsyclbin.syclbin' +// RUN: %clang_cl -fsyclbin --offload-new-driver %s -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK_WIN_DEFAULT_OUTPUT +// CHECK_WIN_DEFAULT_OUTPUT: clang-linker-wrapper +// CHECK_WIN_DEFAULT_OUTPUT-SAME: "-out:{{.*}}fsyclbin.syclbin" diff --git a/sycl/test/syclbin/simple_kernel.cpp b/sycl/test/syclbin/simple_kernel.cpp index c50af68c1c27b..844b20da3ec5a 100644 --- a/sycl/test/syclbin/simple_kernel.cpp +++ b/sycl/test/syclbin/simple_kernel.cpp @@ -1,16 +1,8 @@ -// RUN: %clangxx -fsycl-device-only -Xclang -emit-llvm-bc -o %t.bc %s -// RUN: clang-offload-packager -o %t.out "--image=file=%t.bc,triple=spir64-unknown-unknown,arch=,kind=sycl,compile-opts=" -// RUN: clang-linker-wrapper --syclbin --host-triple=x86_64-unknown-linux-gnu -sycl-device-libraries="libsycl-crt.new.o" -sycl-device-library-location=%sycl_libs_dir --sycl-post-link-options="-device-globals" --llvm-spirv-options=-spirv-max-version=1.4 -o %t.syclbin %t.out +// RUN: %clangxx --offload-new-driver -fsyclbin -o %t.syclbin %s // RUN: syclbin-dump %t.syclbin | FileCheck %s // Checks the generated SYCLBIN contents of a simple SYCL free function kernel. -// TODO: Replace clang tooling invocation with -fsyclbin clang driver command -// when available. Once this is in place, Windows should also be -// supported. -// UNSUPPORTED: windows -// UNSUPPORTED-TRACKER: CMPLRLLVM-65259 - #include extern "C" {