diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index 0e63a7fcf45e..018b0b1e6739 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -72,9 +72,10 @@ class Action { VerifyPCHJobClass, OffloadBundlingJobClass, OffloadUnbundlingJobClass, + OffloadWrappingJobClass, JobClassFirst = PreprocessJobClass, - JobClassLast = OffloadUnbundlingJobClass + JobClassLast = OffloadWrappingJobClass }; // The offloading kind determines if this action is binded to a particular @@ -615,6 +616,17 @@ class OffloadUnbundlingJobAction final : public JobAction { } }; +class OffloadWrappingJobAction : public JobAction { + void anchor() override; + +public: + OffloadWrappingJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == OffloadWrappingJobClass; + } +}; + } // namespace driver } // namespace clang diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 46edca161f6e..df01d06bd2be 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -130,12 +130,14 @@ class ToolChain { mutable std::unique_ptr Assemble; mutable std::unique_ptr Link; mutable std::unique_ptr OffloadBundler; + mutable std::unique_ptr OffloadWrapper; Tool *getClang() const; Tool *getAssemble() const; Tool *getLink() const; Tool *getClangAs() const; Tool *getOffloadBundler() const; + Tool *getOffloadWrapper() const; mutable std::unique_ptr SanitizerArguments; mutable std::unique_ptr XRayArguments; diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index 7130be04222b..adf5a4ddaf66 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -41,6 +41,8 @@ const char *Action::getClassName(ActionClass AC) { return "clang-offload-bundler"; case OffloadUnbundlingJobClass: return "clang-offload-unbundler"; + case OffloadWrappingJobClass: + return "clang-offload-wrapper"; } llvm_unreachable("invalid class"); @@ -408,3 +410,9 @@ void OffloadUnbundlingJobAction::anchor() {} OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input) : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {} + +void OffloadWrappingJobAction::anchor() {} + +OffloadWrappingJobAction::OffloadWrappingJobAction(Action *Input, + types::ID Type) + : JobAction(OffloadWrappingJobClass, Input, Type) {} diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index d09252a2526b..5bb700b78ac5 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -68,27 +68,27 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}]; if (!Entry) { SmallVector AllocatedArgs; - DerivedArgList *OpenMPArgs = nullptr; - // Translate OpenMP toolchain arguments provided via the -Xopenmp-target + DerivedArgList *OffloadArgs = nullptr; + // Translate offload toolchain arguments provided via the -Xopenmp-target // or -Xsycl-target flags. if (DeviceOffloadKind == Action::OFK_OpenMP || DeviceOffloadKind == Action::OFK_SYCL) { const ToolChain *HostTC = getSingleOffloadToolChain(); bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple()); - OpenMPArgs = TC->TranslateOffloadTargetArgs( + OffloadArgs = TC->TranslateOffloadTargetArgs( *TranslatedArgs, SameTripleAsHost, AllocatedArgs, DeviceOffloadKind); } - if (!OpenMPArgs) { + if (!OffloadArgs) { Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); if (!Entry) Entry = TranslatedArgs; } else { - Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind); + Entry = TC->TranslateArgs(*OffloadArgs, BoundArch, DeviceOffloadKind); if (!Entry) - Entry = OpenMPArgs; + Entry = OffloadArgs; else - delete OpenMPArgs; + delete OffloadArgs; } // Add allocated arguments to the final DAL. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 1a4f843c3143..ac5e51c01d0a 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -698,15 +698,15 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // SYCL // // We need to generate a SYCL toolchain if the user specified targets with - // the -fsycl-targets option. + // the -fsycl-targets option. If -fsycl is supplied without -fsycl-targets + // we will assume SPIR-V + bool HasValidSYCLRuntime = C.getInputArgs().hasFlag(options::OPT_fsycl, + options::OPT_fno_sycl, false); if (Arg *SYCLTargets = C.getInputArgs().getLastArg(options::OPT_fsycl_targets_EQ)) { if (SYCLTargets->getNumValues()) { // We expect that -fsycl-targets is always used in conjunction with the // -fsycl option - bool HasValidSYCLRuntime = C.getInputArgs().hasFlag( - options::OPT_fsycl, options::OPT_fno_sycl, false); - if (HasValidSYCLRuntime) { llvm::StringMap FoundNormalizedTriples; for (const char *Val : SYCLTargets->getValues()) { @@ -747,6 +747,27 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, } else Diag(clang::diag::warn_drv_empty_joined_argument) << SYCLTargets->getAsString(C.getInputArgs()); + } else { + // If -fsycl is supplied without -fsycl-targets we will assume SPIR-V + if (HasValidSYCLRuntime) { + const ToolChain *HostTC = + C.getSingleOffloadToolChain(); + const llvm::Triple &HostTriple = HostTC->getTriple(); + llvm::Triple TT(TargetTriple); + TT.setArch(llvm::Triple::spir64); + TT.setVendor(llvm::Triple::UnknownVendor); + TT.setOS(llvm::Triple(llvm::sys::getProcessTriple()).getOS()); + TT.setEnvironment(llvm::Triple::SYCLDevice); + // Use the SYCL and host triples as the key into the ToolChains map, + // because the device toolchain we create depends on both. + auto &SYCLTC = ToolChains[(TT.normalize() + Twine("/") + + HostTriple.normalize()).str()]; + if (!SYCLTC) { + SYCLTC = llvm::make_unique( + *this, TT, *HostTC, C.getInputArgs()); + } + C.addOffloadDeviceToolChain(SYCLTC.get(), Action::OFK_SYCL); + } } // @@ -2942,7 +2963,7 @@ class OffloadingActionBuilder final { // The host depends on the generated integrated header from the device // compilation. if (CurPhase == phases::Compile) { - for (Action *&A : SYCLDeviceActions) { + for (Action *&A : SYCLDeviceActions) { DeviceCompilerInput = C.MakeAction(A, types::TY_SYCL_Header); } @@ -3032,7 +3053,12 @@ class OffloadingActionBuilder final { for (auto &LI : DeviceLinkerInputs) { auto *DeviceLinkAction = C.MakeAction(LI, types::TY_Image); - DA.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, + + // After the Link, wrap the files before the final host link + auto *DeviceWrappingAction = + C.MakeAction(DeviceLinkAction, + types::TY_Object); + DA.add(*DeviceWrappingAction, **TC, /*BoundArch=*/nullptr, Action::OFK_SYCL); ++TC; } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index e20361f91dc5..73cc46c47c10 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -286,6 +286,12 @@ Tool *ToolChain::getOffloadBundler() const { return OffloadBundler.get(); } +Tool *ToolChain::getOffloadWrapper() const { + if (!OffloadWrapper) + OffloadWrapper.reset(new tools::OffloadWrapper(*this)); + return OffloadWrapper.get(); +} + Tool *ToolChain::getTool(Action::ActionClass AC) const { switch (AC) { case Action::AssembleJobClass: @@ -315,6 +321,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::OffloadBundlingJobClass: case Action::OffloadUnbundlingJobClass: return getOffloadBundler(); + + case Action::OffloadWrappingJobClass: + return getOffloadWrapper(); } llvm_unreachable("Invalid tool kind."); @@ -931,7 +940,9 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOffloadTargetArgs( unsigned Index; unsigned Prev; bool XOffloadTargetNoTriple; - + + // TODO: functionality between OpenMP offloading and SYCL offloading + // is similar, can be improved if (DeviceOffloadKind == Action::OFK_OpenMP) { XOffloadTargetNoTriple = A->getOption().matches(options::OPT_Xopenmp_target); @@ -966,7 +977,6 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOffloadTargetArgs( } } - // Parse the argument to -Xopenmp-target. Prev = Index; std::unique_ptr XOffloadTargetArg(Opts.ParseOneArg(Args, Index)); @@ -981,6 +991,8 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOffloadTargetArgs( continue; } if (XOffloadTargetNoTriple && XOffloadTargetArg) { + // TODO: similar behaviors with OpenMP and SYCL offloading, can be + // improved upon if (DeviceOffloadKind == Action::OFK_OpenMP && Args.getAllArgValues(options::OPT_fopenmp_targets_EQ).size() != 1) { getDriver().Diag(diag::err_drv_Xopenmp_target_missing_triple); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c332c10de764..939d1ed56be7 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3412,6 +3412,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, InputInfoList ModuleHeaderInputs; const InputInfo *CudaDeviceInput = nullptr; const InputInfo *OpenMPDeviceInput = nullptr; + const InputInfo *SYCLDeviceInput = nullptr; for (const InputInfo &I : Inputs) { if (&I == &Input) { // This is the primary input. @@ -3428,6 +3429,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CudaDeviceInput = &I; } else if (IsOpenMPDevice && !OpenMPDeviceInput) { OpenMPDeviceInput = &I; + } else if (IsSYCL && !SYCLDeviceInput) { + SYCLDeviceInput = &I; } else { llvm_unreachable("unexpectedly given multiple inputs"); } @@ -3544,8 +3547,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (isa(JA)) { if (IsSYCLOffloadDevice && IsSYCLDevice) { CmdArgs.push_back("-emit-spirv"); - } - else { + } else { CmdArgs.push_back("-emit-obj"); CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); } @@ -5221,11 +5223,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (IsSYCL) { - // Host-side SYCL compilation receives the integrated header file as + // Host-side SYCL compilation receives the integration header file as // Inputs[1]. Include the header with -include - if (!IsSYCLOffloadDevice && Inputs.size() > 1) { + if (!IsSYCLOffloadDevice && SYCLDeviceInput) { CmdArgs.push_back("-include"); - CmdArgs.push_back(Inputs[1].getFilename()); + CmdArgs.push_back(SYCLDeviceInput->getFilename()); } if (IsSYCLOffloadDevice && JA.getType() == types::TY_SYCL_Header) { // Generating a SYCL Header @@ -6254,3 +6256,66 @@ void OffloadBundler::ConstructJobMultipleOutputs( TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), CmdArgs, None)); } + +// Begin OffloadWrapper + +void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // Construct offload-wrapper command. Also calls llc to generate the + // object that is fed to the linker from the wrapper generated bc file + assert(isa(JA) && "Expecting wrapping job!"); + + // The wrapper command looks like this: + // clang-offload-wrapper + // -o=.bc + // -target=sycl-x86_64-pc-linux-gnu .spv + ArgStringList WrapperArgs; + + std::string OutTmpName = C.getDriver().GetTemporaryPath("wrapper", "bc"); + const char * WrapperFileName = + C.addTempFile(C.getArgs().MakeArgString(OutTmpName)); + SmallString<128> OutOpt("-o="); + OutOpt += WrapperFileName; + WrapperArgs.push_back(C.getArgs().MakeArgString(OutOpt)); + for (auto I : Inputs) { + WrapperArgs.push_back(I.getFilename()); + } + + SmallString<128> TargetOpt("-target="); + TargetOpt += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + TargetOpt += '-'; + TargetOpt += getToolChain().getAuxTriple()->str(); + WrapperArgs.push_back(C.getArgs().MakeArgString(TargetOpt)); + + // For SYCL, do not emit entry tables + if (JA.isOffloading(Action::OFK_SYCL)) + WrapperArgs.push_back("-emit-entry-table=0"); + + C.addCommand(llvm::make_unique(JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + WrapperArgs, None)); + + // Construct llc command. + // The output is an object file + ArgStringList LlcArgs{"-filetype=obj", "-o", Output.getFilename(), + WrapperFileName}; + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), TCArgs); + if (PICLevel > 0) { + LlcArgs.push_back("-relocation-model=pic"); + } + if (IsPIE) { + LlcArgs.push_back("-enable-pie"); + } + SmallString<128> LlcPath(C.getDriver().Dir); + llvm::sys::path::append(LlcPath, "llc"); + const char *Llc = C.getArgs().MakeArgString(LlcPath); + C.addCommand(llvm::make_unique(JA, *this, Llc, LlcArgs, None)); +} + diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index df67fb2cb331..1b7ff960f146 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -147,6 +147,19 @@ class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool { const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +/// Offload wrapper tool. +class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool { +public: + OffloadWrapper(const ToolChain &TC) + : Tool("offload wrapper", "clang-offload-wrapper", TC) {} + + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace tools } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 91888ed745e9..d0b0ca40bfb8 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -24,24 +24,27 @@ using namespace clang; using namespace llvm::opt; const char *SYCL::Linker::constructLLVMSpirvCommand(Compilation &C, - const JobAction &JA, StringRef OutputFilePrefix, bool toBc, - const char *InputFileName) const { + const JobAction &JA, const InputInfo &Output, StringRef OutputFilePrefix, + bool ToBc, const char *InputFileName) const { // Construct llvm-spirv command. // The output is a bc file or vice versa depending on the -r option usage // llvm-spirv -r -o a_kernel.bc a_kernel.spv // llvm-spirv -o a_kernel.spv a_kernel.bc ArgStringList CmdArgs; - if (toBc) + const char *OutputFileName = nullptr; + if (ToBc) { + std::string TmpName = + C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-spirv", "bc"); + OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); CmdArgs.push_back("-r"); - std::string TmpName = - C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-spirv", - toBc ? "bc" : "spv"); - const char *OutputFileName = - C.addTempFile(C.getArgs().MakeArgString(TmpName)); - //return OutputFileName; - CmdArgs.push_back("-o"); - CmdArgs.push_back(OutputFileName); + CmdArgs.push_back("-o"); + CmdArgs.push_back(OutputFileName); + } else { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } CmdArgs.push_back(InputFileName); + SmallString<128> LLVMSpirvPath(C.getDriver().Dir); llvm::sys::path::append(LLVMSpirvPath, "llvm-spirv"); const char *LLVMSpirv = C.getArgs().MakeArgString(LLVMSpirvPath); @@ -71,39 +74,6 @@ const char *SYCL::Linker::constructLLVMLinkCommand( return OutputFileName; } -const char *SYCL::Linker::constructOffloadWrapperCommand( - Compilation &C, const JobAction &JA, StringRef OutputFilePrefix, - const char *InputFileName) const { - // Construct offload-wrapper command. - // The output is bc wrapped spirv file - std::string TmpName = - C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-wrapped", "bc"); - const char *OutputFileName = - C.addTempFile(C.getArgs().MakeArgString(TmpName)); - ArgStringList WrapperArgs; - - SmallString<128> TmpOutOpt("-o="); - TmpOutOpt += OutputFileName; - WrapperArgs.push_back(C.getArgs().MakeArgString(TmpOutOpt)); - WrapperArgs.push_back(InputFileName); - - SmallString<128> TmpTargetOpt("-target="); - TmpTargetOpt += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); - TmpTargetOpt += '-'; - TmpTargetOpt += getToolChain().getAuxTriple()->str(); - WrapperArgs.push_back(C.getArgs().MakeArgString(TmpTargetOpt)); - - // For SYCL, do not emit entry tables - WrapperArgs.push_back("-emit-entry-table=0"); - - SmallString<128> WrapperPath(C.getDriver().Dir); - llvm::sys::path::append(WrapperPath, "clang-offload-wrapper"); - const char *Wrapper = C.getArgs().MakeArgString(WrapperPath); - C.addCommand(llvm::make_unique(JA, *this, Wrapper, WrapperArgs, - None)); - return OutputFileName; -} - void SYCL::Linker::constructLlcCommand(Compilation &C, const JobAction &JA, const InputInfo &Output, const char *InputFileName) const { // Construct llc command. @@ -117,8 +87,7 @@ void SYCL::Linker::constructLlcCommand(Compilation &C, const JobAction &JA, } // For SYCL the inputs of the linker job are SPIR-V binaries and output is -// object file. It calls llvm-spirv, llvm-link, llvm-spirv, offload-wrapper -// and llc +// a single SPIR-V binary. void SYCL::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -142,16 +111,12 @@ void SYCL::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!II.isFilename()) continue; const char *LLVMSpirvOutputFile = - constructLLVMSpirvCommand(C, JA, Prefix, true, II.getFilename()); + constructLLVMSpirvCommand(C, JA, Output, Prefix, true, II.getFilename()); SpirvInputs.push_back(LLVMSpirvOutputFile); } const char *LLVMLinkOutputFile = constructLLVMLinkCommand(C, JA, SubArchName, Prefix, SpirvInputs); - const char *LLVMSpirvOutputFile = - constructLLVMSpirvCommand(C, JA, Prefix, false, LLVMLinkOutputFile); - const char *OffloadWrapperOutputFile = - constructOffloadWrapperCommand(C, JA, Prefix, LLVMSpirvOutputFile); - constructLlcCommand(C, JA, Output, OffloadWrapperOutputFile); + constructLLVMSpirvCommand(C, JA, Output, Prefix, false, LLVMLinkOutputFile); } SYCLToolChain::SYCLToolChain(const Driver &D, const llvm::Triple &Triple, diff --git a/clang/lib/Driver/ToolChains/SYCL.h b/clang/lib/Driver/ToolChains/SYCL.h index b4f6fca94b72..c18d3eaad0de 100644 --- a/clang/lib/Driver/ToolChains/SYCL.h +++ b/clang/lib/Driver/ToolChains/SYCL.h @@ -35,6 +35,7 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { private: /// \return llvm-spirv output file name. const char *constructLLVMSpirvCommand(Compilation &C, const JobAction &JA, + const InputInfo &Output, llvm::StringRef OutputFilePrefix, bool isBc, const char *InputFile) const; /// \return llvm-link output file name. @@ -42,11 +43,6 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { llvm::StringRef SubArchName, llvm::StringRef OutputFilePrefix, const llvm::opt::ArgStringList &InputFiles) const; - /// \return clang-offload-wrapper output file name. - const char *constructOffloadWrapperCommand(Compilation &C, - const JobAction &JA, - llvm::StringRef OutputFilePrefix, - const char *InputFile) const; void constructLlcCommand(Compilation &C, const JobAction &JA, const InputInfo &Output, const char *InputFile) const; diff --git a/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func.cpp b/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func.cpp new file mode 100644 index 000000000000..d5632876c8ef --- /dev/null +++ b/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func.cpp @@ -0,0 +1,32 @@ +// RUN: %clang -cc1 -triple spir64-unknown-linux-sycldevice -std=c++11 -fsycl-is-device -emit-llvm -x c++ %s -o - | FileCheck %s + +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + kernelFunc(); +} + +class BASE { +public: + virtual void initialize() {} + virtual ~BASE(); +}; + +template +class DERIVED : public BASE { +public: + void initialize() { + kernel_single_task([]() { }); + } +}; + +int main() { + BASE *Base = new DERIVED; + Base->initialize(); + delete Base; +} + +// Ensure that the SPIR-Kernel function is actually emitted. +// CHECK: define spir_kernel void @FF +// CHECK: call spir_func void @_ZZN7DERIVEDIiE10initializeEvENKUlvE_clEv +// CHECK: define linkonce_odr spir_func void @_ZZN7DERIVEDIiE10initializeEvENKUlvE_clEv + diff --git a/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func2.cpp b/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func2.cpp new file mode 100644 index 000000000000..dff28c3f5438 --- /dev/null +++ b/clang/test/CodeGenSYCL/emit-kernel-in-virtual-func2.cpp @@ -0,0 +1,37 @@ +// RUN: %clang -cc1 -triple spir64-unknown-linux-sycldevice -std=c++11 -fsycl-is-device -emit-llvm -x c++ %s -o - | FileCheck %s + +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + kernelFunc(); +} + +template +void TT() { + kernel_single_task([]() {}); +} + +class BASE { + public: + virtual void initialize() {} + virtual ~BASE(); +}; + +template +class DERIVED : public BASE { + public: + void initialize() { + TT(); + } +}; + +int main() { + BASE *Base = new DERIVED; + Base->initialize(); + delete Base; +} + +// Ensure that the SPIR-Kernel function is actually emitted. +// CHECK: define spir_kernel void @PP +// CHECK: call spir_func void @_ZZ2TTIiEvvENKUlvE_clEv +// CHECK: define linkonce_odr spir_func void @_ZZ2TTIiEvvENKUlvE_clEv + diff --git a/clang/test/CodeGenSYCL/skip-host-classes.cpp b/clang/test/CodeGenSYCL/skip-host-classes.cpp new file mode 100644 index 000000000000..fd85c95ee09e --- /dev/null +++ b/clang/test/CodeGenSYCL/skip-host-classes.cpp @@ -0,0 +1,10 @@ +// RUN: %clang --sycl -c %s -o %t.ll -Xclang -fsycl-int-header=%t.hpp -emit-llvm -S +// RUN: FileCheck < %t.ll %s --check-prefix=CHECK + +// CHECK-NOT: declare dso_local spir_func void {{.+}}test{{.+}}printer{{.+}} +class test { +public: + virtual void printer(); +}; + +void test::printer() {} diff --git a/clang/test/Driver/sycl-offload.c b/clang/test/Driver/sycl-offload.c index 97b124bf06a3..0864f9b3970a 100644 --- a/clang/test/Driver/sycl-offload.c +++ b/clang/test/Driver/sycl-offload.c @@ -54,15 +54,17 @@ /// Check the phases graph when using a single target, different from the host. /// We should have an offload action joining the host compile and device /// preprocessor and another one joining the device linking outputs to the host -/// action. +/// action. The same graph should be generated when no -fsycl-targets is used // RUN: %clang -ccc-print-phases -target x86_64-unknown-linux-gnu -fsycl -fsycl-targets=spir64-unknown-linux-sycldevice %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-PHASES %s +// RUN: %clang -ccc-print-phases -target x86_64-unknown-linux-gnu -fsycl %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-PHASES %s // CHK-PHASES: 0: input, "[[INPUT:.+\.c]]", c, (host-sycl) // CHK-PHASES: 1: preprocessor, {0}, cpp-output, (host-sycl) // CHK-PHASES: 2: input, "[[INPUT]]", c, (device-sycl) // CHK-PHASES: 3: preprocessor, {2}, cpp-output, (device-sycl) // CHK-PHASES: 4: compiler, {3}, sycl-header, (device-sycl) -// CHK-PHASES: 5: offload, "host-sycl (x86_64-unknown-linux-gnu)" {1}, "device-sycl (spir64-unknown-linux-sycldevice)" {4}, cpp-output +// CHK-PHASES: 5: offload, "host-sycl (x86_64-unknown-linux-gnu)" {1}, "device-sycl (spir64-unknown-{{.*}}-sycldevice)" {4}, cpp-output // CHK-PHASES: 6: compiler, {5}, ir, (host-sycl) // CHK-PHASES: 7: backend, {6}, assembler, (host-sycl) // CHK-PHASES: 8: assembler, {7}, object, (host-sycl) @@ -71,7 +73,8 @@ // CHK-PHASES: 11: backend, {10}, assembler, (device-sycl) // CHK-PHASES: 12: assembler, {11}, object, (device-sycl) // CHK-PHASES: 13: linker, {12}, image, (device-sycl) -// CHK-PHASES: 14: offload, "host-sycl (x86_64-unknown-linux-gnu)" {9}, "device-sycl (spir64-unknown-linux-sycldevice)" {13}, image +// CHK-PHASES: 14: clang-offload-wrapper, {13}, object, (device-sycl) +// CHK-PHASES: 15: offload, "host-sycl (x86_64-unknown-linux-gnu)" {9}, "device-sycl (spir64-unknown-linux-sycldevice)" {14}, image /// ########################################################################### @@ -95,7 +98,8 @@ // CHK-PHASES-LIB: 13: backend, {12}, assembler, (device-sycl) // CHK-PHASES-LIB: 14: assembler, {13}, object, (device-sycl) // CHK-PHASES-LIB: 15: linker, {11, 14}, image, (device-sycl) -// CHK-PHASES-LIB: 16: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64-unknown-linux-sycldevice)" {15}, image +// CHK-PHASES-LIB: 16: clang-offload-wrapper, {15}, object, (device-sycl) +// CHK-PHASES-LIB: 17: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64-unknown-linux-sycldevice)" {16}, image /// ########################################################################### @@ -132,7 +136,8 @@ // CHK-PHASES-FILES: 25: backend, {24}, assembler, (device-sycl) // CHK-PHASES-FILES: 26: assembler, {25}, object, (device-sycl) // CHK-PHASES-FILES: 27: linker, {20, 23, 26}, image, (device-sycl) -// CHK-PHASES-FILES: 28: offload, "host-sycl (x86_64-unknown-linux-gnu)" {19}, "device-sycl (spir64-unknown-linux-sycldevice)" {27}, image +// CHK-PHASES-FILES: 28: clang-offload-wrapper, {27}, object, (device-sycl) +// CHK-PHASES-FILES: 29: offload, "host-sycl (x86_64-unknown-linux-gnu)" {19}, "device-sycl (spir64-unknown-linux-sycldevice)" {28}, image /// ########################################################################### @@ -166,7 +171,8 @@ // CHK-UBACTIONS: 3: linker, {0, 2}, image, (host-sycl) // CHK-UBACTIONS: 4: input, "somelib", object, (device-sycl) // CHK-UBACTIONS: 5: linker, {4, 2}, image, (device-sycl) -// CHK-UBACTIONS: 6: offload, "host-sycl (x86_64-unknown-linux-gnu)" {3}, "device-sycl (spir64-unknown-linux-sycldevice)" {5}, image +// CHK-UBACTIONS: 6: clang-offload-wrapper, {5}, object, (device-sycl) +// CHK-UBACTIONS: 7: offload, "host-sycl (x86_64-unknown-linux-gnu)" {3}, "device-sycl (spir64-unknown-linux-sycldevice)" {6}, image /// ########################################################################### @@ -192,7 +198,8 @@ // CHK-UBUACTIONS: 15: backend, {14}, assembler, (device-sycl) // CHK-UBUACTIONS: 16: assembler, {15}, object, (device-sycl) // CHK-UBUACTIONS: 17: linker, {13, 2, 16}, image, (device-sycl) -// CHK-UBUACTIONS: 18: offload, "host-sycl (x86_64-unknown-linux-gnu)" {12}, "device-sycl (spir64-unknown-linux-sycldevice)" {17}, image +// CHK-UBUACTIONS: 18: clang-offload-wrapper, {17}, object, (device-sycl) +// CHK-UBUACTIONS: 19: offload, "host-sycl (x86_64-unknown-linux-gnu)" {12}, "device-sycl (spir64-unknown-linux-sycldevice)" {18}, image /// ###########################################################################