diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 6ac9e94f7c330..58f7c07fb18ad 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -340,6 +340,8 @@ def warn_drv_object_size_disabled_O0 : Warning< InGroup, DefaultWarnNoWerror; def err_invalid_branch_protection: Error < "invalid branch protection option '%0' in '%1'">; +def warn_drv_deprecated_option : Warning< + "option '%0' is deprecated, use '%1' directly instead">, InGroup; def note_drv_command_failed_diag_msg : Note< "diagnostic msg: %0">; diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index fe991b971b73f..88e20a965c690 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -76,6 +76,7 @@ class Action { SPIRVTranslatorJobClass, SPIRCheckJobClass, SYCLPostLinkJobClass, + PartialLinkJobClass, BackendCompileJobClass, JobClassFirst = PreprocessJobClass, @@ -680,6 +681,18 @@ class SYCLPostLinkJobAction : public JobAction { } }; +class PartialLinkJobAction : public JobAction { + void anchor() override; + +public: + PartialLinkJobAction(Action *Input, types::ID OutputType); + PartialLinkJobAction(ActionList &Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PartialLinkJobClass; + } +}; + class BackendCompileJobAction : public JobAction { void anchor() override; diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 4867f48b53005..6679fae41f436 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -621,6 +621,15 @@ class Driver { &CachedResults, Action::OffloadKind TargetDeviceOffloadKind) const; + /// Static offload library seen. + bool OffloadStaticLibSeen = false; + + void setOffloadStaticLibSeen() { OffloadStaticLibSeen = true; } + + /// Returns true if an offload static library is found. + bool checkForOffloadStaticLib(Compilation &C, + llvm::opt::DerivedArgList &Args) const; + public: /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and /// return the grouped values as integers. Numbers which are not @@ -642,6 +651,8 @@ class Driver { MutableArrayRef Digits); /// Compute the default -fmodule-cache-path. static void getDefaultModuleCachePath(SmallVectorImpl &Result); + + bool getOffloadStaticLibSeen() const { return OffloadStaticLibSeen; }; }; /// \return True if the last defined optimization level is -Ofast. @@ -651,6 +662,9 @@ bool isOptimizationLevelFast(const llvm::opt::ArgList &Args); /// \return True if the filename has a valid object file extension. bool isObjectFile(std::string FileName); +/// \return True if the filename has a static archive/lib extension. +bool isStaticArchiveFile(const StringRef &FileName); + /// \return True if the argument combination will end up generating remarks. bool willEmitRemarks(const llvm::opt::ArgList &Args); diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 8436bdef71541..7c05cb219639a 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -145,6 +145,7 @@ class ToolChain { mutable std::unique_ptr SPIRVTranslator; mutable std::unique_ptr SPIRCheck; mutable std::unique_ptr SYCLPostLink; + mutable std::unique_ptr PartialLink; mutable std::unique_ptr BackendCompiler; Tool *getClang() const; @@ -158,6 +159,7 @@ class ToolChain { Tool *getSPIRVTranslator() const; Tool *getSPIRCheck() const; Tool *getSYCLPostLink() const; + Tool *getPartialLink() const; Tool *getBackendCompiler() const; mutable std::unique_ptr SanitizerArguments; diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index e83094374a04c..f2973da2322e1 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -49,6 +49,8 @@ const char *Action::getClassName(ActionClass AC) { return "llvm-no-spir-kernel"; case SYCLPostLinkJobClass: return "sycl-post-link"; + case PartialLinkJobClass: + return "partial-link"; case BackendCompileJobClass: return "backend-compiler"; } @@ -454,6 +456,14 @@ void SYCLPostLinkJobAction::anchor() {} SYCLPostLinkJobAction::SYCLPostLinkJobAction(Action *Input, types::ID Type) : JobAction(SYCLPostLinkJobClass, Input, Type) {} +void PartialLinkJobAction::anchor() {} + +PartialLinkJobAction::PartialLinkJobAction(Action *Input, types::ID Type) + : JobAction(PartialLinkJobClass, Input, Type) {} + +PartialLinkJobAction::PartialLinkJobAction(ActionList &Inputs, types::ID Type) + : JobAction(PartialLinkJobClass, Inputs, Type) {} + void BackendCompileJobAction::anchor() {} BackendCompileJobAction::BackendCompileJobAction(ActionList &Inputs, diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 512b92010f1d3..95a733994c6d5 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1301,6 +1301,10 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { InputList Inputs; BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); + // Determine if there are any offload static libraries. + if (checkForOffloadStaticLib(*C, *TranslatedArgs)) + setOffloadStaticLibSeen(); + // Populate the tool chains for the offloading devices, if any. CreateOffloadingDeviceToolChains(*C, Inputs); @@ -2472,6 +2476,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Diag(diag::note_use_dashdash); } } + // TODO: remove when -foffload-static-lib support is dropped. else if (A->getOption().matches(options::OPT_offload_lib_Group)) { // Add the foffload-static-lib library to the command line to allow // processing when no source or object is supplied as well as proper @@ -2479,6 +2484,10 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_Object, InputArg)); A->claim(); + // Use of -foffload-static-lib and -foffload-whole-static-lib are + // deprecated with the updated functionality to scan the static libs. + Diag(clang::diag::warn_drv_deprecated_option) + << A->getAsString(Args) << A->getValue(); } } if (CCCIsCPP() && Inputs.empty()) { @@ -2489,6 +2498,188 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } +static bool runBundler(const SmallVectorImpl &BundlerArgs, + Compilation &C) { + // Find bundler. + StringRef ExecPath(C.getArgs().MakeArgString(C.getDriver().Dir)); + llvm::ErrorOr BundlerBinary = + llvm::sys::findProgramByName("clang-offload-bundler", ExecPath); + // Since this is run in real time and not in the toolchain, output the + // command line if requested. + bool OutputOnly = C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); + if (C.getArgs().hasArg(options::OPT_v) || OutputOnly) { + for (StringRef A : BundlerArgs) + if (OutputOnly) + llvm::errs() << "\"" << A << "\" "; + else + llvm::errs() << A << " "; + llvm::errs() << '\n'; + } + if (BundlerBinary.getError()) + return false; + + return !llvm::sys::ExecuteAndWait(BundlerBinary.get(), BundlerArgs); +} + +bool hasFPGABinary(Compilation &C, std::string Object, types::ID Type) { + assert(types::isFPGA(Type) && "unexpected Type for FPGA binary check"); + // Temporary names for the output. + llvm::Triple TT; + TT.setArchName(types::getTypeName(Type)); + TT.setVendorName("intel"); + TT.setOS(llvm::Triple::UnknownOS); + TT.setEnvironment(llvm::Triple::SYCLDevice); + + // Checking uses -check-section option with the input file, no output + // file and the target triple being looked for. + const char *Targets = + C.getArgs().MakeArgString(Twine("-targets=sycl-") + TT.str()); + const char *Inputs = C.getArgs().MakeArgString(Twine("-inputs=") + Object); + // Always use -type=ao for aocx/aocr bundle checking. The 'bundles' are + // actually archives. + SmallVector BundlerArgs = {"clang-offload-bundler", "-type=ao", + Targets, Inputs, "-check-section"}; + return runBundler(BundlerArgs, C); +} + +static bool hasOffloadSections(Compilation &C, const StringRef &Archive, + DerivedArgList &Args) { + // Do not do the check if the file doesn't exist + if (!llvm::sys::fs::exists(Archive)) + return false; + + llvm::Triple TT(C.getDefaultToolChain().getTriple()); + // Checking uses -check-section option with the input file, no output + // file and the target triple being looked for. + // TODO - Improve checking to check for explicit offload target instead + // of the generic host availability. + const char *Targets = Args.MakeArgString(Twine("-targets=host-") + TT.str()); + const char *Inputs = Args.MakeArgString(Twine("-inputs=") + Archive.str()); + // Always use -type=ao for bundle checking. The 'bundles' are + // actually archives. + SmallVector BundlerArgs = {"clang-offload-bundler", "-type=ao", + Targets, Inputs, "-check-section"}; + return runBundler(BundlerArgs, C); +} + +// Simple helper function for Linker options, where the option is valid if +// it has '-' or '--' as the designator. +static bool optionMatches(const std::string &Option, + const std::string &OptCheck) { + return (Option == OptCheck || ("-" + Option) == OptCheck); +} + +// Process linker inputs for use with offload static libraries. We are only +// handling options and explicitly named static archives as these need to be +// partially linked. +static SmallVector getLinkerArgs(Compilation &C, + DerivedArgList &Args) { + SmallVector LibArgs; + for (const auto *A : Args) { + std::string FileName = A->getAsString(Args); + if (A->getOption().getKind() == Option::InputClass) { + StringRef Value(A->getValue()); + if (isStaticArchiveFile(Value)) { + LibArgs.push_back(Args.MakeArgString(FileName)); + continue; + } + } + if (A->getOption().hasFlag(options::LinkerInput)) { + // Do not add any libraries that are not fully named static libs + if (A->getOption().matches(options::OPT_l) || + A->getOption().matches(options::OPT_reserved_lib_Group) || + A->getOption().hasFlag(options::NoArgumentUnused)) + continue; + std::string PrevArg; + for (const std::string &Value : A->getValues()) { + auto addKnownValues = [&](const StringRef &V) { + // Only add named static libs objects and --whole-archive options. + if (optionMatches("-whole-archive", V.str()) || + optionMatches("-no-whole-archive", V.str()) || + isStaticArchiveFile(V)) { + LibArgs.push_back(Args.MakeArgString(V)); + return; + } + // Probably not the best way to handle this, but there are options + // that take arguments which we should not add to the known values. + // Handle -z and -rpath for now - can be expanded if/when usage shows + // the need. + if (PrevArg != "-z" && PrevArg != "-rpath" && V[0] != '-' && + isObjectFile(V.str())) { + LibArgs.push_back(Args.MakeArgString(V)); + return; + } + }; + if (Value[0] == '@') { + // Found a response file, we want to expand contents to try and + // discover more libraries and options. + SmallVector ExpandArgs; + ExpandArgs.push_back(Value.c_str()); + + llvm::BumpPtrAllocator A; + llvm::StringSaver S(A); + llvm::cl::ExpandResponseFiles( + S, + C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment() + ? llvm::cl::TokenizeWindowsCommandLine + : llvm::cl::TokenizeGNUCommandLine, + ExpandArgs); + for (StringRef EA : ExpandArgs) + addKnownValues(EA); + } else + addKnownValues(Value); + PrevArg = Value; + } + continue; + } + // Use of -foffload-static-lib and -foffload-whole-static-lib is + // considered deprecated. Usage should move to passing in the static + // library name on the command line, encapsulating with + // -Wl,--whole-archive -Wl,--no-whole-archive as needed. + if (A->getOption().matches(options::OPT_foffload_static_lib_EQ)) { + LibArgs.push_back(Args.MakeArgString(A->getValue())); + continue; + } + if (A->getOption().matches(options::OPT_foffload_whole_static_lib_EQ)) { + // For -foffload-whole-static-lib, we add the --whole-archive wrap + // around the library which will be used during the partial link step. + LibArgs.push_back("--whole-archive"); + LibArgs.push_back(Args.MakeArgString(A->getValue())); + LibArgs.push_back("--no-whole-archive"); + continue; + } + } + return LibArgs; +} + +// Goes through all of the arguments, including inputs expected for the +// linker directly, to determine if we need to perform additional work for +// static offload libraries. +bool Driver::checkForOffloadStaticLib(Compilation &C, + DerivedArgList &Args) const { + // Check only if enabled with -fsycl or -fopenmp-targets + if (!Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + !Args.hasArg(options::OPT_fopenmp_targets_EQ)) + return false; + + // Right off the bat, assume the presense of -foffload-static-lib means + // the need to perform linking steps for fat static archive offloading. + // TODO: remove when -foffload-static-lib support is dropped. + if (Args.hasArg(options::OPT_offload_lib_Group)) + return true; + SmallVector OffloadLibArgs(getLinkerArgs(C, Args)); + for (const StringRef &OLArg : OffloadLibArgs) + if (isStaticArchiveFile(OLArg) && hasOffloadSections(C, OLArg, Args)) { + // FPGA binaries with AOCX or AOCR sections are not considered fat + // static archives. + if (Args.hasArg(options::OPT_fintelfpga)) + return !(hasFPGABinary(C, OLArg.str(), types::TY_FPGA_AOCR) || + hasFPGABinary(C, OLArg.str(), types::TY_FPGA_AOCX)); + return true; + } + return false; +} + namespace { /// Provides a convenient interface for different programming models to generate /// the required device actions. @@ -3392,8 +3583,9 @@ class OffloadingActionBuilder final { return ABRT_Inactive; std::string InputName = IA->getInputArg().getAsString(Args); - // Objects should already be consumed with -foffload-static-lib - if (Args.hasArg(options::OPT_offload_lib_Group) && + // Objects will be consumed as part of the partial link step when + // dealing with offload static libraries + if (C.getDriver().getOffloadStaticLibSeen() && IA->getType() == types::TY_Object && isObjectFile(InputName)) return ABRT_Inactive; @@ -3898,57 +4090,6 @@ class OffloadingActionBuilder final { return C.MakeAction(HDep, DDeps); } - bool hasFPGABinary(Compilation &C, std::string Object, types::ID Type) { - assert(types::isFPGA(Type) && "unexpected Type for FPGA binary check"); - // Temporary names for the output. - const ToolChain *OTC = C.getSingleOffloadToolChain(); - llvm::Triple TT; - TT.setArchName(types::getTypeName(Type)); - TT.setVendorName("intel"); - TT.setOS(llvm::Triple(OTC->getTriple()).getOS()); - TT.setEnvironment(llvm::Triple::SYCLDevice); - - // Checking uses -check-section option with the input file, no output - // file and the target triple being looked for. - const char *Targets = - C.getArgs().MakeArgString(Twine("-targets=sycl-") + TT.str()); - const char *Inputs = C.getArgs().MakeArgString(Twine("-inputs=") + - Object); - // Always use -type=ao for aocx/aocr bundle checking. The 'bundles' are - // actually archives. - std::vector BundlerArgs = { "clang-offload-bundler", - "-type=ao", - Targets, - Inputs, - "-check-section" }; - // Find bundler. - StringRef ExecPath(C.getArgs().MakeArgString(C.getDriver().Dir)); - auto BundlerBinary = llvm::sys::findProgramByName("clang-offload-bundler", - ExecPath); - if (C.getArgs().hasArg(options::OPT_ccc_print_phases, - options::OPT_ccc_print_bindings)) - return false; - // Since this is run in real time and not in the toolchain, output the - // command line if requested. - bool OutputOnly = C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); - if (C.getArgs().hasArg(options::OPT_v) || OutputOnly) { - for (StringRef A : BundlerArgs) - if (OutputOnly) - llvm::errs() << "\"" << A << "\" "; - else - llvm::errs() << A << " "; - llvm::errs() << '\n'; - } - if (BundlerBinary.getError()) - return false; - - // Run the bundler. - bool Failed = llvm::sys::ExecuteAndWait(BundlerBinary.get(), BundlerArgs); - if (!Failed) - return true; - return false; - } - /// Generate an action that adds a host dependence to a device action. The /// results will be kept in this action builder. Return true if an error was /// found. @@ -3985,7 +4126,7 @@ class OffloadingActionBuilder final { if (C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment() || !(HostAction->getType() == types::TY_Object && isObjectFile(InputName) && - Args.hasArg(options::OPT_offload_lib_Group))) { + C.getDriver().getOffloadStaticLibSeen())) { ActionList HostActionList; Action *A(HostAction); // Only check for FPGA device information when using fpga SubArch. @@ -4465,10 +4606,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, OffloadBuilder.appendTopLevelLinkAction(Actions); + // Go through all of the args, and create a Linker specific argument list. + // When dealing with fat static archives, this is fed into the partial link + // step on Linux or each archive is individually addressed on Windows. + SmallVector LinkArgs(getLinkerArgs(C, Args)); // When a static fat archive is provided, create a new unbundling step // for all of the objects. if (!C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment() && - Args.hasArg(options::OPT_offload_lib_Group)) { + C.getDriver().getOffloadStaticLibSeen()) { ActionList UnbundlerInputs; for (const auto &LI : LinkerInputs) { // Unbundler only handles objects. @@ -4482,55 +4627,77 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, UnbundlerInputs.push_back(LI); } const Arg *LastArg; - auto addUnbundlerInput = [&](types::ID T, const Arg *A) { + auto addUnbundlerInput = [&](types::ID T, const StringRef &A) { const llvm::opt::OptTable &Opts = getOpts(); - Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); + Arg *InputArg = MakeInputArg(Args, Opts, C.getArgs().MakeArgString(A)); LastArg = InputArg; Action *Current = C.MakeAction(*InputArg, T); UnbundlerInputs.push_back(Current); }; - for (const auto *A : Args.filtered(options::OPT_foffload_static_lib_EQ)) - addUnbundlerInput(types::TY_Archive, A); - for (const auto *A : - Args.filtered(options::OPT_foffload_whole_static_lib_EQ)) - addUnbundlerInput(types::TY_WholeArchive, A); + bool IsWholeArchive = false; + for (const StringRef &LA : LinkArgs) { + if (isStaticArchiveFile(LA)) { + addUnbundlerInput( + IsWholeArchive ? types::TY_WholeArchive : types::TY_Archive, LA); + continue; + } + if (optionMatches("-no-whole-archive", LA.str())) { + IsWholeArchive = false; + continue; + } + if (optionMatches("-whole-archive", LA.str())) { + IsWholeArchive = true; + continue; + } + if (isObjectFile(LA.str())) { + // Add any objects to the unbundler step. These objects are passed + // directly to the linker, so the driver does not know about them. + // FIXME - Better process objects passed to the linker. We are only + // adding these objects to the unbundler step, but these objects can + // potentially be fat objects that should be processed by the driver. + addUnbundlerInput(types::TY_Object, LA); + continue; + } + } + if (!UnbundlerInputs.empty()) { - Action *Current = C.MakeAction(*LastArg, types::TY_Archive); - OffloadBuilder.addHostDependenceToUnbundlingAction(Current, - UnbundlerInputs, LastArg); + Action *PartialLink = + C.MakeAction(UnbundlerInputs, types::TY_Object); + Action *Current = C.MakeAction(*LastArg, types::TY_Object); + ActionList AL; + AL.push_back(PartialLink); + OffloadBuilder.addHostDependenceToUnbundlingAction(Current, AL, LastArg); Current = OffloadBuilder.addDeviceDependencesToHostAction(Current, LastArg, phases::Link, PL.back(), PL); } } const llvm::opt::OptTable &Opts = getOpts(); - auto unbundleStaticLib = [&](types::ID T, const Arg *A) { - Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); + auto unbundleStaticLib = [&](types::ID T, const StringRef &A) { + Arg *InputArg = MakeInputArg(Args, Opts, Args.MakeArgString(A)); Action *Current = C.MakeAction(*InputArg, T); OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg, Args); OffloadBuilder.addDeviceDependencesToHostAction( Current, InputArg, phases::Link, PL.back(), PL); }; - for (const auto *A : Args.filtered(options::OPT_foffload_static_lib_EQ)) { + for (const StringRef &LA : LinkArgs) { + // At this point, we will process the archives for FPGA AOCO and individual + // archive unbundling for Windows. + if (!isStaticArchiveFile(LA)) + continue; // In MSVC environment offload-static-libs are handled slightly different // because of missing support for partial linking in the linker. We add an // unbundling action for each static archive which produces list files with // extracted objects. Device lists are then added to the appropriate device // link actions and host list is ignored since we are adding // offload-static-libs as normal libraries to the host link command. - if (C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment()) - unbundleStaticLib(types::TY_Archive, A); - // Pass along the -foffload-static-lib values to check if we need to - // add them for unbundling for FPGA AOT static lib usage. Uses FPGA - // aoco type to differentiate if aoco unbundling is needed. - if (Args.hasArg(options::OPT_fintelfpga)) - unbundleStaticLib(types::TY_FPGA_AOCO, A); - } - for (const auto *A : - Args.filtered(options::OPT_foffload_whole_static_lib_EQ)) { - if (C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment()) - unbundleStaticLib(types::TY_WholeArchive, A); + if (C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment() && + hasOffloadSections(C, LA, Args)) + unbundleStaticLib(types::TY_Archive, LA); + // Pass along the static libraries to check if we need to add them for + // unbundling for FPGA AOT static lib usage. Uses FPGA aoco type to + // differentiate if aoco unbundling is needed. if (Args.hasArg(options::OPT_fintelfpga)) - unbundleStaticLib(types::TY_FPGA_AOCO, A); + unbundleStaticLib(types::TY_FPGA_AOCO, LA); } // For an FPGA archive, we add the unbundling step above to take care of @@ -5408,8 +5575,8 @@ InputInfo Driver::BuildJobsForActionNoCache( bool IsFPGAObjLink = (JA->getType() == types::TY_Object && C.getInputArgs().hasArg(options::OPT_fintelfpga) && C.getInputArgs().hasArg(options::OPT_fsycl_link_EQ)); - if (C.getInputArgs().hasArg(options::OPT_offload_lib_Group) && - ((JA->getType() == types::TY_Archive && IsMSVCEnv) || + if (C.getDriver().getOffloadStaticLibSeen() && + (JA->getType() == types::TY_Archive || (JA->getType() == types::TY_Object && !IsMSVCEnv))) { // Host part of the unbundled static archive is not used. if (UI.DependentOffloadKind == Action::OFK_Host) @@ -6311,6 +6478,15 @@ bool clang::driver::isObjectFile(std::string FileName) { types::lookupTypeForExtension(Ext) == types::TY_Object); } +bool clang::driver::isStaticArchiveFile(const StringRef &FileName) { + if (!llvm::sys::path::has_extension(FileName)) + // Any file with no extension should not be considered an Archive. + return false; + StringRef Ext(llvm::sys::path::extension(FileName).drop_front()); + // Only .lib and .a files are to be considered. + return (Ext == "lib" || Ext == "a"); +} + bool clang::driver::willEmitRemarks(const ArgList &Args) { // -fsave-optimization-record enables it. if (Args.hasFlag(options::OPT_fsave_optimization_record, diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 51be68bbe1212..1abb81a8019c2 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -330,6 +330,12 @@ Tool *ToolChain::getSYCLPostLink() const { return SYCLPostLink.get(); } +Tool *ToolChain::getPartialLink() const { + if (!PartialLink) + PartialLink.reset(new tools::PartialLink(*this)); + return PartialLink.get(); +} + Tool *ToolChain::getBackendCompiler() const { if (!BackendCompiler) BackendCompiler.reset(buildBackendCompiler()); @@ -381,6 +387,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::SYCLPostLinkJobClass: return getSYCLPostLink(); + case Action::PartialLinkJobClass: + return getPartialLink(); + case Action::BackendCompileJobClass: return getBackendCompiler(); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c7006cb04229b..bb71afa371f28 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7181,55 +7181,14 @@ void OffloadBundler::ConstructJobMultipleOutputs( C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); types::ID InputType(Input.getType()); bool IsFPGADepUnbundle = (JA.getType() == types::TY_FPGA_Dependencies); + bool IsArchiveUnbundle = + (!IsMSVCEnv && C.getDriver().getOffloadStaticLibSeen() && + (types::isArchive(InputType) || InputType == types::TY_Object)); - // For Linux, we have initial support for fat archives (archives which - // contain bundled objects). We will perform partial linking against the - // specific offload target archives which will be sent to the unbundler to - // produce a list of target objects. - // FIXME: This should be a separate job in the toolchain. - if (!IsMSVCEnv && TCArgs.hasArg(options::OPT_offload_lib_Group) && - (types::isArchive(InputType) || InputType == types::TY_Object)) { + if (IsArchiveUnbundle) TypeArg = "oo"; - ArgStringList LinkArgs; - LinkArgs.push_back("-r"); - LinkArgs.push_back("-o"); - std::string TmpName = - C.getDriver().GetTemporaryPath( - llvm::sys::path::stem(Input.getFilename()).str() + "-prelink", "o"); - InputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - LinkArgs.push_back(InputFileName); - const ToolChain *HTC = C.getSingleOffloadToolChain(); - // Add crt objects - LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crt1.o"))); - LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crti.o"))); - // Add -L search directories. - TCArgs.AddAllArgs(LinkArgs, options::OPT_L); - - // TODO - We can potentially go through the args and add the known linker - // pass through args of --whole-archive and --no-whole-archive. This - // would allow to support user commands like: -Wl,--whole-archive - // -foffload-static-lib= -Wl,--no-whole-archive - // Input files consist of fat libraries and the object(s) to be unbundled. - bool IsWholeArchive = false; - for (const auto &I : Inputs) { - if (I.getType() == types::TY_WholeArchive && !IsWholeArchive) { - LinkArgs.push_back("--whole-archive"); - IsWholeArchive = true; - } else if (I.getType() == types::TY_Archive && IsWholeArchive) { - LinkArgs.push_back("--no-whole-archive"); - IsWholeArchive = false; - } - LinkArgs.push_back(I.getFilename()); - } - // Disable whole archive if it was enabled for the previous inputs. - if (IsWholeArchive) - LinkArgs.push_back("--no-whole-archive"); - // Add crt objects - LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crtn.o"))); - const char *Exec = TCArgs.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique(JA, *this, Exec, LinkArgs, Inputs)); - } else if (InputType == types::TY_FPGA_AOCX || - InputType == types::TY_FPGA_AOCR) { + else if (InputType == types::TY_FPGA_AOCX || + InputType == types::TY_FPGA_AOCR) { // Override type with archive object if (getToolChain().getTriple().getSubArch() == llvm::Triple::SPIRSubArch_fpga) @@ -7274,10 +7233,9 @@ void OffloadBundler::ConstructJobMultipleOutputs( Triples += Dep.DependentToolChain->getTriple().normalize(); } continue; - } else if (types::isArchive(InputType) || (InputType == types::TY_Object && - ((!IsMSVCEnv && TCArgs.hasArg(options::OPT_offload_lib_Group)) || - (TCArgs.hasArg(options::OPT_fintelfpga) && - TCArgs.hasArg(options::OPT_fsycl_link_EQ))))) { + } else if (InputType == types::TY_Archive || IsArchiveUnbundle || + (TCArgs.hasArg(options::OPT_fintelfpga) && + TCArgs.hasArg(options::OPT_fsycl_link_EQ))) { // Do not extract host part if we are unbundling archive on Windows // because it is not needed. Static offload libraries are added to the // host link command just as normal libraries. Do not extract the host @@ -7702,3 +7660,52 @@ void SYCLPostLink::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs, None)); } +// For Linux, we have initial support for fat archives (archives which +// contain bundled objects). We will perform partial linking against the +// specific offload target archives which will be sent to the unbundler to +// produce a list of target objects. +void PartialLink::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // Construct simple partial link command. + assert(isa(JA) && "Expecting Partial Link job!"); + + // The partial linking command resembles this: + // ld -r -o + ArgStringList LinkArgs; + LinkArgs.push_back("-r"); + LinkArgs.push_back("-o"); + LinkArgs.push_back(Output.getFilename()); + + const ToolChain *HTC = C.getSingleOffloadToolChain(); + // Add crt objects + LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crt1.o"))); + LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crti.o"))); + // Add -L search directories. + TCArgs.AddAllArgs(LinkArgs, options::OPT_L); + HTC->AddFilePathLibArgs(TCArgs, LinkArgs); + + // Input files consist of fat libraries and the object(s) to be unbundled. + // We add the needed --whole-archive/--no-whole-archive when appropriate. + bool IsWholeArchive = false; + for (const auto &I : Inputs) { + if (I.getType() == types::TY_WholeArchive && !IsWholeArchive) { + LinkArgs.push_back("--whole-archive"); + IsWholeArchive = true; + } else if (I.getType() == types::TY_Archive && IsWholeArchive) { + LinkArgs.push_back("--no-whole-archive"); + IsWholeArchive = false; + } + LinkArgs.push_back(I.getFilename()); + } + // Disable whole archive if it was enabled for the previous inputs. + if (IsWholeArchive) + LinkArgs.push_back("--no-whole-archive"); + + // Add crt objects + LinkArgs.push_back(TCArgs.MakeArgString(HTC->GetFilePath("crtn.o"))); + const char *Exec = TCArgs.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(std::make_unique(JA, *this, Exec, LinkArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 0cd0e16ad7784..f1467e40746e1 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -205,6 +205,19 @@ class LLVM_LIBRARY_VISIBILITY SYCLPostLink final : public Tool { const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +/// Partially link objects and archives. +class LLVM_LIBRARY_VISIBILITY PartialLink final : public Tool { +public: + PartialLink(const ToolChain &TC) : Tool("partial link", "partial-link", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool hasGoodDiagnostics() const override { return true; } + 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/test/Driver/sycl-offload-intelfpga.cpp b/clang/test/Driver/sycl-offload-intelfpga.cpp index 33fd08f64091e..88ba93c94921f 100644 --- a/clang/test/Driver/sycl-offload-intelfpga.cpp +++ b/clang/test/Driver/sycl-offload-intelfpga.cpp @@ -59,7 +59,7 @@ // Create the dummy archive // RUN: echo "Dummy AOCR image" > %t.aocr // RUN: echo "void foo() {}" > %t.c -// RUN: %clang -c %t.c +// RUN: %clang -c -o %t.o %t.c // RUN: clang-offload-wrapper -o %t-aocr.bc -host=x86_64-unknown-linux-gnu -kind=sycl -target=fpga_aocr-intel-unknown-sycldevice %t.aocr // RUN: llc -filetype=obj -o %t-aocr.o %t-aocr.bc // RUN: llvm-ar crv %t.a %t.o %t-aocr.o @@ -115,7 +115,7 @@ // Create the dummy archive // RUN: echo "Dummy AOCX image" > %t.aocx // RUN: echo "void foo() {}" > %t.c -// RUN: %clang -c %t.c +// RUN: %clang -c -o %t.o %t.c // RUN: clang-offload-wrapper -o %t-aocx.bc -host=x86_64-unknown-linux-gnu -kind=sycl -target=fpga_aocx-intel-unknown-sycldevice %t.aocx // RUN: llc -filetype=obj -o %t-aocx.o %t-aocx.bc // RUN: llvm-ar crv %t_aocx.a %t.o %t-aocx.o @@ -123,8 +123,11 @@ // RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCX-PHASES %s // RUN: %clang_cl -fsycl -fintelfpga %t_aocx.a -ccc-print-phases 2>&1 \ // RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCX-PHASES %s -// CHK-FPGA-AOCX-PHASES: 0: input, "{{.*}}", object, (host-sycl) +// CHK-FPGA-AOCX-PHASES: 0: input, "{{.*}}", fpga_aocx, (host-sycl) // CHK-FPGA-AOCX-PHASES: 1: linker, {0}, image, (host-sycl) +// CHK-FPGA-AOCX-PHASES: 2: clang-offload-unbundler, {0}, fpga_aocx +// CHK-FPGA-AOCX-PHASES: 3: clang-offload-wrapper, {2}, object, (device-sycl) +// CHK-FPGA-AOCX-PHASES: 4: offload, "host-sycl ({{.*}}x86_64{{.*}})" {1}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice{{(-coff)?}})" {3}, image // RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga %t_aocx.a -### 2>&1 \ // RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCX,CHK-FPGA-AOCX-LIN %s @@ -255,47 +258,78 @@ /// -fintelfpga static lib (aoco) // RUN: echo "Dummy AOCO image" > %t.aoco // RUN: echo "void foo() {}" > %t.c -// RUN: %clang -c %t.c +// RUN: echo "void foo2() {}" > %t2.c +// RUN: %clang -c -o %t.o %t.c +// RUN: %clang -fsycl -c -o %t2.o %t2.c +// RUN: %clang_cl -fsycl -c -o %t2_cl.o %t2.c // RUN: clang-offload-wrapper -o %t-aoco.bc -host=x86_64-unknown-linux-gnu -kind=sycl -target=fpga_aoco-intel-unknown-sycldevice %t.aoco // RUN: llc -filetype=obj -o %t-aoco.o %t-aoco.bc -// RUN: llvm-ar crv %t_aoco.a %t.o %t-aoco.o -// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga -foffload-static-lib=%t_aocx.a %s -### -ccc-print-phases 2>&1 \ -// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO-PHASES,CHK-FPGA-AOCO-PHASES-LIN %s -// RUN: %clang_cl -fsycl -fintelfpga -foffload-static-lib=%t_aoco.a %s -### -ccc-print-phases 2>&1 \ -// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO-PHASES,CHK-FPGA-AOCO-PHASES-WIN %s +// RUN: llvm-ar crv %t_aoco.a %t.o %t2.o %t-aoco.o +// RUN: llvm-ar crv %t_aoco_cl.a %t.o %t2_cl.o %t-aoco.o +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga -foffload-static-lib=%t_aoco.a %s -### -ccc-print-phases 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-FPGA-AOCO-PHASES %s // CHK-FPGA-AOCO-PHASES: 0: input, "[[INPUTA:.+\.a]]", object, (host-sycl) // CHK-FPGA-AOCO-PHASES: 1: input, "[[INPUTCPP:.+\.cpp]]", c++, (host-sycl) // CHK-FPGA-AOCO-PHASES: 2: preprocessor, {1}, c++-cpp-output, (host-sycl) // CHK-FPGA-AOCO-PHASES: 3: input, "[[INPUTCPP]]", c++, (device-sycl) // CHK-FPGA-AOCO-PHASES: 4: preprocessor, {3}, c++-cpp-output, (device-sycl) // CHK-FPGA-AOCO-PHASES: 5: compiler, {4}, sycl-header, (device-sycl) -// CHK-FPGA-AOCO-PHASES-LIN: 6: offload, "host-sycl (x86_64-unknown-linux-gnu)" {2}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {5}, c++-cpp-output -// CHK-FPGA-AOCO-PHASES-WIN: 6: offload, "host-sycl (x86_64-pc-windows-msvc)" {2}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice-coff)" {5}, c++-cpp-output +// CHK-FPGA-AOCO-PHASES: 6: offload, "host-sycl (x86_64-unknown-linux-gnu)" {2}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {5}, c++-cpp-output // CHK-FPGA-AOCO-PHASES: 7: compiler, {6}, ir, (host-sycl) // CHK-FPGA-AOCO-PHASES: 8: backend, {7}, assembler, (host-sycl) // CHK-FPGA-AOCO-PHASES: 9: assembler, {8}, object, (host-sycl) // CHK-FPGA-AOCO-PHASES: 10: linker, {0, 9}, image, (host-sycl) // CHK-FPGA-AOCO-PHASES: 11: compiler, {4}, ir, (device-sycl) // CHK-FPGA-AOCO-PHASES: 12: input, "[[INPUTA]]", archive -// CHK-FPGA-AOCO-PHASES-LIN: 13: clang-offload-unbundler, {9, 12}, object +// CHK-FPGA-AOCO-PHASES: 13: partial-link, {9, 12}, object +// CHK-FPGA-AOCO-PHASES: 14: clang-offload-unbundler, {13}, object +// CHK-FPGA-AOCO-PHASES: 15: linker, {11, 14}, ir, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 16: llvm-spirv, {15}, spirv, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 17: input, "[[INPUTA]]", fpga_aoco +// CHK-FPGA-AOCO-PHASES: 18: clang-offload-unbundler, {17}, fpga_aoco +// CHK-FPGA-AOCO-PHASES: 19: backend-compiler, {16, 18}, fpga_aocx, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 20: clang-offload-wrapper, {19}, object, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 21: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {20}, image + +/// FPGA AOCO Windows phases check +// RUN: %clang_cl -fsycl -fintelfpga -foffload-static-lib=%t_aoco_cl.a %s -### -ccc-print-phases 2>&1 \ +// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO-PHASES-WIN %s +// CHK-FPGA-AOCO-PHASES-WIN: 0: input, "{{.*}}", object, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 1: input, "[[INPUTSRC:.+\.cpp]]", c++, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 2: preprocessor, {1}, c++-cpp-output, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 3: input, "[[INPUTSRC]]", c++, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 4: preprocessor, {3}, c++-cpp-output, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 5: compiler, {4}, sycl-header, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 6: offload, "host-sycl (x86_64-pc-windows-msvc)" {2}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice-coff)" {5}, c++-cpp-output +// CHK-FPGA-AOCO-PHASES-WIN: 7: compiler, {6}, ir, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 8: backend, {7}, assembler, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 9: assembler, {8}, object, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 10: linker, {0, 9}, image, (host-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 11: compiler, {4}, ir, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 12: input, "[[INPUTA:.+\.a]]", archive // CHK-FPGA-AOCO-PHASES-WIN: 13: clang-offload-unbundler, {12}, archive -// CHK-FPGA-AOCO-PHASES: 14: linker, {11, 13}, ir, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 15: llvm-spirv, {14}, spirv, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 16: backend-compiler, {15}, fpga_aocx, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 17: clang-offload-wrapper, {16}, object, (device-sycl) -// CHK-FPGA-AOCO-PHASES-LIN: 18: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {17}, image -// CHK-FPGA-AOCO-PHASES-WIN: 18: offload, "host-sycl (x86_64-pc-windows-msvc)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice-coff)" {17}, image +// CHK-FPGA-AOCO-PHASES-WIN: 14: linker, {11, 13}, ir, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 15: llvm-spirv, {14}, spirv, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 16: input, "[[INPUTA]]", fpga_aoco +// CHK-FPGA-AOCO-PHASES-WIN: 17: clang-offload-unbundler, {16}, fpga_aoco +// CHK-FPGA-AOCO-PHASES-WIN: 18: backend-compiler, {15, 17}, fpga_aocx, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 19: clang-offload-wrapper, {18}, object, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 20: offload, "host-sycl (x86_64-pc-windows-msvc)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice-coff)" {19}, image /// aoco test, checking tools // RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga -foffload-static-lib=%t_aoco.a -### %s 2>&1 \ // RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO,CHK-FPGA-AOCO-LIN %s -// RUN: %clang_cl -fsycl -fintelfpga -foffload-static-lib=%t_aoco.a -### %s 2>&1 \ +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga %t_aoco.a -### %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO,CHK-FPGA-AOCO-LIN %s +// RUN: %clang_cl -fsycl -fintelfpga -foffload-static-lib=%t_aoco_cl.a -### %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO,CHK-FPGA-AOCO-WIN %s +// RUN: %clang_cl -fsycl -fintelfpga %t_aoco_cl.a -### %s 2>&1 \ // RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO,CHK-FPGA-AOCO-WIN %s // CHK-FPGA-AOCO-LIN: clang-offload-bundler{{.*}} "-type=ao" "-targets=sycl-fpga_aoco-intel-unknown-sycldevice" "-inputs=[[INPUTLIB:.+\.a]]" "-check-section" // CHK-FPGA-AOCO-LIN: clang{{.*}} "-emit-obj" {{.*}} "-o" "[[HOSTOBJ:.+\.o]]" -// CHK-FPGA-AOCO-LIN: ld{{.*}} "-r" "-o" "[[PARTLINKOBJ:.+\.o]]" "{{.*}}crt1.o" "{{.*}}crti.o" "[[HOSTOBJ]]" "[[INPUTLIB]]" "{{.*}}crtn.o" +// CHK-FPGA-AOCO-LIN: ld{{.*}} "-r" "-o" "[[PARTLINKOBJ:.+\.o]]" "{{.*}}crt1.o" "{{.*}}crti.o" {{.*}} "[[HOSTOBJ]]" "[[INPUTLIB]]" "{{.*}}crtn.o" // CHK-FPGA-AOCO-LIN: clang-offload-bundler{{.*}} "-type=oo" "-targets=sycl-spir64_fpga-unknown-unknown-sycldevice" "-inputs=[[PARTLINKOBJ]]" "-outputs={{.*}}" "-unbundle" -// CHK-FPGA-AOCO-WIN: clang-offload-bundler{{.*}} "-type=aoo" "-targets=sycl-spir64_fpga-unknown-unknown-sycldevice-coff" "-inputs=[[INPUTLIB:.+\.a]]" "-outputs={{.*}}" "-unbundle" +// CHK-FPGA-AOCO-WIN: clang-offload-bundler{{.*}} "-type=aoo" "-targets=sycl-spir64_fpga-unknown-unknown-sycldevice{{(-coff)?}}" "-inputs=[[INPUTLIB:.+\.a]]" "-outputs={{.*}}" "-unbundle" // CHK-FPGA-AOCO: llvm-link{{.*}} "@{{.*}}" "-o" "[[LINKEDBC:.+\.bc]]" // CHK-FPGA-AOCO: llvm-spirv{{.*}} "-o" "[[TARGSPV:.+\.spv]]" {{.*}} "[[LINKEDBC]]" // CHK-FPGA-AOCO: clang-offload-bundler{{.*}} "-type=aoo" "-targets=sycl-fpga_aoco-intel-unknown-sycldevice" "-inputs=[[INPUTLIB]]" "-outputs=[[AOCOLIST:.+\.txt]]" "-unbundle" @@ -304,7 +338,7 @@ // CHK-FPGA-AOCO-LIN: llc{{.*}} "-filetype=obj" "-o" "[[FINALOBJL:.+\.o]]" "[[FINALBC]]" // CHK-FPGA-AOCO-WIN: llc{{.*}} "-filetype=obj" "-o" "[[FINALOBJW:.+\.obj]]" "[[FINALBC]]" // CHK-FPGA-AOCO-LIN: ld{{.*}} "[[INPUTLIB]]" {{.*}} "[[FINALOBJL]]" -// CHK-FPGA-AOCO-WIN: link.exe{{.*}} "-defaultlib:[[INPUTLIB]]" {{.*}} "[[FINALOBJW]]" +// CHK-FPGA-AOCO-WIN: link.exe{{.*}} "{{.*}}[[INPUTLIB]]" {{.*}} "[[FINALOBJW]]" // TODO: SYCL specific fail - analyze and enable // XFAIL: windows-msvc diff --git a/clang/test/Driver/sycl-offload-static-lib-2.cpp b/clang/test/Driver/sycl-offload-static-lib-2.cpp new file mode 100644 index 0000000000000..0fd43773dec6a --- /dev/null +++ b/clang/test/Driver/sycl-offload-static-lib-2.cpp @@ -0,0 +1,108 @@ +/// +/// Perform several driver tests for SYCL offloading involving static libs +/// +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target + +/// ########################################################################### + +/// test behaviors of passing a fat static lib +// Build a fat static lib that will be used for all tests +// RUN: echo "void foo(void) {}" > %t1.cpp +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl %t1.cpp -c -o %t1_bundle.o +// RUN: llvm-ar crv %t.a %t1_bundle.o +// +// RUN: touch %t.a +// RUN: touch %t.o +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir %t.a -### %t.o 2>&1 \ +// RUN: | FileCheck %s -check-prefix=STATIC_LIB +// STATIC_LIB: ld{{(.exe)?}}" "-r" "-o" {{.*}} "[[INPUT:.+\.o]]" "-L/dummy/dir"{{.*}} "[[INPUT:.+\.a]]" +// STATIC_LIB: clang-offload-bundler{{.*}} "-type=oo" +// STATIC_LIB: llvm-link{{.*}} "@{{.*}}" + +/// ########################################################################### + +/// test behaviors of fat static lib with multiple objects +// RUN: touch %t.a +// RUN: touch %t-1.o +// RUN: touch %t-2.o +// RUN: touch %t-3.o +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl %t.a -### %t-1.o %t-2.o %t-3.o 2>&1 \ +// RUN: | FileCheck %s -check-prefix=STATIC_LIB_MULTI_O +// STATIC_LIB_MULTI_O: ld{{(.exe)?}}" "-r" "-o" {{.*}} "[[INPUT:.+\-1.o]]" "[[INPUT:.+\-2.o]]" "[[INPUT:.+\-3.o]]" "[[INPUT:.+\.a]]" +// STATIC_LIB_MULTI_O: clang-offload-bundler{{.*}} "-type=oo" +// STATIC_LIB_MULTI_O: llvm-link{{.*}} "@{{.*}}" + +/// ########################################################################### + +/// test behaviors of fat static lib from source +// RUN: touch %t.a +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl %t.a -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=STATIC_LIB_SRC +// STATIC_LIB_SRC: ld{{(.exe)?}}" "-r" "-o" {{.*}} "[[INPUT:.+\.a]]" +// STATIC_LIB_SRC: clang-offload-bundler{{.*}} "-type=oo" +// STATIC_LIB_SRC: llvm-link{{.*}} "@{{.*}}" + +/// ########################################################################### + +// RUN: touch %t.a +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl %t.a -o output_name -lOpenCL -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=STATIC_LIB_SRC2 +// STATIC_LIB_SRC2: ld{{(.exe)?}}" "-r" "-o" {{.*}} "[[INPUT:.+\.a]]" +// STATIC_LIB_SRC2: clang-offload-bundler{{.*}} "-type=oo" +// STATIC_LIB_SRC2: llvm-link{{.*}} "@{{.*}}" +// STATIC_LIB_SRC2: ld{{(.exe)?}}" {{.*}} "-o" "output_name" {{.*}} "-lOpenCL" + +/// ########################################################################### + +// RUN: touch %t.a +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl %t.a -o output_name -lstdc++ -z relro -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=STATIC_LIB_SRC3 +// STATIC_LIB_SRC3: ld{{(.exe)?}}" "-r" "-o" {{.*}} "[[INPUT:.+\.a]]" +// STATIC_LIB_SRC3: clang-offload-bundler{{.*}} "-type=oo" +// STATIC_LIB_SRC3: llvm-link{{.*}} "@{{.*}}" +// STATIC_LIB_SRC3: ld{{(.exe)?}}" {{.*}} "-o" "output_name" {{.*}} "-lstdc++" "-z" "relro" + +/// ########################################################################### + +/// test behaviors of -Wl,--whole-archive staticlib.a -Wl,--no-whole-archive +/// also test behaviors of -Wl,@arg with the above arguments +// RUN: touch %t.a +// RUN: touch %t_2.a +// RUN: touch %t.o +// RUN: echo "--whole-archive %t.a %t_2.a --no-whole-archive" > %t.arg +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir %t.o -Wl,--whole-archive %t.a %t_2.a -Wl,--no-whole-archive -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=WHOLE_STATIC_LIB,WHOLE_STATIC_LIB_1 +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir %t.o -Wl,@%t.arg -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=WHOLE_STATIC_LIB,WHOLE_STATIC_LIB_2 -DARGFILE=%t.arg +// WHOLE_STATIC_LIB: ld{{(.exe)?}}" "-r" "-o" "[[INPUT:.+\.o]]" "{{.*}}crt1.o" "{{.*}}crti.o" "-L/dummy/dir" {{.*}} "[[INPUTO:.+\.o]]" "--whole-archive" "[[INPUTA:.+\.a]]" "[[INPUTB:.+\.a]]" "--no-whole-archive" "{{.*}}crtn.o" +// WHOLE_STATIC_LIB: clang-offload-bundler{{.*}} "-type=oo" {{.*}} "-inputs=[[INPUT]]" +// WHOLE_STATIC_LIB: llvm-link{{.*}} "@{{.*}}" +// WHOLE_STATIC_LIB: llvm-spirv{{.*}} +// WHOLE_STATIC_LIB: clang-offload-wrapper{{.*}} +// WHOLE_STATIC_LIB: llc{{.*}} +// WHOLE_STATIC_LIB_1: ld{{.*}} "[[INPUTO]]" "--whole-archive" "[[INPUTA]]" "[[INPUTB]]" "--no-whole-archive" +// WHOLE_STATIC_LIB_2: ld{{.*}} "[[INPUTO]]" "@[[ARGFILE]]" + +/// test -Wl, behaviors for special case handling of -z and -rpath +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir %t.o -Wl,-rpath,nopass -Wl,-z,nopass %t.a %t_2.a -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=WL_CHECK +// WL_CHECK-NOT: ld{{(.exe)?}}" "-r" {{.*}} "{{.*}}crt1.o" "{{.*}}crti.o" "-L/dummy/dir" {{.*}} "nopass" {{.*}} "{{.*}}crtn.o" +// WL_CHECK: ld{{.*}}" "-rpath" "nopass" "-z" "nopass" + +/// ########################################################################### + +/// test behaviors of static lib with no source/object +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir %t.a -### 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=STATIC_LIB_NOSRC +// STATIC_LIB_NOSRC: clang-offload-bundler{{.*}} "-type=ao" "-targets=host-x86_64-unknown-linux-gnu" "-inputs=[[INPUTLIB:.+\.a]]" "-check-section" +// STATIC_LIB_NOSRC: ld{{.*}} "-r" "-o" "[[PARTIALOBJ:.+\.o]]" "{{.*}}crt1.o" {{.*}} "-L/dummy/dir" {{.*}} "[[INPUTLIB]]" +// STATIC_LIB_NOSRC: clang-offload-bundler{{.*}} "-type=oo" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs=[[PARTIALOBJ]]" "-outputs=[[DEVICELIST:.+\.txt]]" "-unbundle" +// STATIC_LIB_NOSRC: llvm-link{{.*}} "@[[DEVICELIST]]" "-o" "[[BCFILE:.+\.bc]]" +// STATIC_LIB_NOSRC: llvm-spirv{{.*}} "-o" "[[SPVFILE:.+\.spv]]" {{.*}} "[[BCFILE]]" +// STATIC_LIB_NOSRC: clang-offload-wrapper{{.*}} "-o=[[BCFILE2:.+\.bc]]" "-host=x86_64-unknown-linux-gnu" "-target=spir64" "-kind=sycl" "[[SPVFILE]]" +// STATIC_LIB_NOSRC: llc{{.*}} "-filetype=obj" "-o" "[[FINALOBJ:.+\.o]]" "[[BCFILE2]]" +// STATIC_LIB_NOSRC: ld{{.*}} "-L/dummy/dir" {{.*}} "[[INPUTLIB]]" "[[FINALOBJ]]" + +// fails on Windows due to the argument file to -Wl and directory separators +// XFAIL: windows-msvc diff --git a/clang/test/Driver/sycl-offload-static-lib.cpp b/clang/test/Driver/sycl-offload-static-lib.cpp index 897c34cf2bef2..3239170f9ab59 100644 --- a/clang/test/Driver/sycl-offload-static-lib.cpp +++ b/clang/test/Driver/sycl-offload-static-lib.cpp @@ -15,6 +15,14 @@ // FOFFLOAD_STATIC_LIB: clang-offload-bundler{{.*}} "-type=oo" // FOFFLOAD_STATIC_LIB: llvm-link{{.*}} "@{{.*}}" +/// Use of -foffload-static-lib and -foffload-whole-static-lib are deprecated +// RUN: touch dummy.a +// RUN: %clangxx -fsycl -foffload-static-lib=dummy.a -foffload-whole-static-lib=dummy.a -### 2>&1 \ +// RUN: | FileCheck %s -check-prefix=FOFFLOAD_STATIC_LIB_DEPRECATED +// RUN: %clang_cl -fsycl -foffload-static-lib=dummy.a -foffload-whole-static-lib=dummy.a -### 2>&1 \ +// RUN: | FileCheck %s -check-prefix=FOFFLOAD_STATIC_LIB_DEPRECATED +// FOFFLOAD_STATIC_LIB_DEPRECATED: option '-foffload-whole-static-lib=dummy.a' is deprecated, use 'dummy.a' directly instead + /// ########################################################################### /// test behaviors of -foffload-static-lib= with multiple objects @@ -48,11 +56,12 @@ // FOFFLOAD_STATIC_LIB_SRC: 10: linker, {0, 9}, image, (host-sycl) // FOFFLOAD_STATIC_LIB_SRC: 11: compiler, {4}, ir, (device-sycl) // FOFFLOAD_STATIC_LIB_SRC: 12: input, "[[INPUTA]]", archive -// FOFFLOAD_STATIC_LIB_SRC: 13: clang-offload-unbundler, {9, 12}, object -// FOFFLOAD_STATIC_LIB_SRC: 14: linker, {11, 13}, ir, (device-sycl) -// FOFFLOAD_STATIC_LIB_SRC: 15: llvm-spirv, {14}, spirv, (device-sycl) -// FOFFLOAD_STATIC_LIB_SRC: 16: clang-offload-wrapper, {15}, object, (device-sycl) -// FOFFLOAD_STATIC_LIB_SRC: 17: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64-unknown-unknown-sycldevice)" {16}, image +// FOFFLOAD_STATIC_LIB_SRC: 13: partial-link, {9, 12}, object +// FOFFLOAD_STATIC_LIB_SRC: 14: clang-offload-unbundler, {13}, object +// FOFFLOAD_STATIC_LIB_SRC: 15: linker, {11, 14}, ir, (device-sycl) +// FOFFLOAD_STATIC_LIB_SRC: 16: llvm-spirv, {15}, spirv, (device-sycl) +// FOFFLOAD_STATIC_LIB_SRC: 17: clang-offload-wrapper, {16}, object, (device-sycl) +// FOFFLOAD_STATIC_LIB_SRC: 18: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64-unknown-unknown-sycldevice)" {17}, image /// ########################################################################### @@ -92,7 +101,7 @@ // RUN: touch %t.o // RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -L/dummy/dir -foffload-whole-static-lib=%t.a -foffload-whole-static-lib=%t_2.a -### %t.o 2>&1 \ // RUN: | FileCheck %s -check-prefix=FOFFLOAD_WHOLE_STATIC_LIB -// FOFFLOAD_WHOLE_STATIC_LIB: ld{{(.exe)?}}" "-r" "-o" "[[INPUT:.+\.o]]" "{{.*}}crt1.o" "{{.*}}crti.o" "-L/dummy/dir" "[[INPUTO:.+\.o]]" "--whole-archive" "[[INPUTA:.+\.a]]" "[[INPUTB:.+\.a]]" "--no-whole-archive" "{{.*}}crtn.o" +// FOFFLOAD_WHOLE_STATIC_LIB: ld{{(.exe)?}}" "-r" "-o" "[[INPUT:.+\.o]]" "{{.*}}crt1.o" "{{.*}}crti.o" "-L/dummy/dir" {{.*}} "[[INPUTO:.+\.o]]" "--whole-archive" "[[INPUTA:.+\.a]]" "[[INPUTB:.+\.a]]" "--no-whole-archive" "{{.*}}crtn.o" // FOFFLOAD_WHOLE_STATIC_LIB: clang-offload-bundler{{.*}} "-type=oo" {{.*}} "-inputs=[[INPUT]]" // FOFFLOAD_WHOLE_STATIC_LIB: llvm-link{{.*}} "@{{.*}}" // FOFFLOAD_WHOLE_STATIC_LIB: llvm-spirv{{.*}} @@ -111,8 +120,9 @@ // FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 1: linker, {0}, image, (host-sycl) // FOFFLOAD_STATIC_LIB_NOSRC_PHASES_1: 2: input, "[[INPUTA]]", archive // FOFFLOAD_STATIC_LIB_NOSRC_PHASES_2: 2: input, "[[INPUTA]]", wholearchive -// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 3: clang-offload-unbundler, {2}, object -// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 4: linker, {3}, ir, (device-sycl) -// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 5: llvm-spirv, {4}, spirv, (device-sycl) -// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 6: clang-offload-wrapper, {5}, object, (device-sycl) -// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 7: offload, "host-sycl (x86_64-unknown-linux-gnu)" {1}, "device-sycl (spir64-unknown-unknown-sycldevice)" {6}, image +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 3: partial-link, {2}, object +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 4: clang-offload-unbundler, {3}, object +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 5: linker, {4}, ir, (device-sycl) +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 6: llvm-spirv, {5}, spirv, (device-sycl) +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 7: clang-offload-wrapper, {6}, object, (device-sycl) +// FOFFLOAD_STATIC_LIB_NOSRC_PHASES: 8: offload, "host-sycl (x86_64-unknown-linux-gnu)" {1}, "device-sycl (spir64-unknown-unknown-sycldevice)" {7}, image diff --git a/clang/test/Driver/sycl-offload-win.c b/clang/test/Driver/sycl-offload-win.c index 5192e12f45d1e..db65b5d70c113 100644 --- a/clang/test/Driver/sycl-offload-win.c +++ b/clang/test/Driver/sycl-offload-win.c @@ -6,8 +6,10 @@ // REQUIRES: x86-registered-target /// Test behaviors of -foffload-static-lib= with single object. -// RUN: touch %t.lib -// RUN: touch %t.obj +// Build the offload library that is used for the tests. +// RUN: echo "void foo() {}" > %t.c +// RUN: %clang_cl -fsycl -c -Fo%t.obj %t.c +// RUN: llvm-ar cr %t.lib %t.obj // RUN: %clang --target=x86_64-pc-windows-msvc -fsycl -foffload-static-lib=%t.lib %t.obj -### 2>&1 \ // RUN: | FileCheck -DOBJ=%t.obj -DLIB=%t.lib %s -check-prefixes=FOFFLOAD_STATIC_LIB,FOFFLOAD_STATIC_LIB_DEFAULT // RUN: %clang_cl --target=x86_64-pc-windows-msvc -fsycl -foffload-static-lib=%t.lib %t.obj -### 2>&1 \ @@ -40,8 +42,8 @@ /// ########################################################################### /// Test behaviors with multiple -foffload-static-lib= options. -// RUN: touch %t1.lib -// RUN: touch %t2.lib +// RUN: cp %t.lib %t1.lib +// RUN: cp %t.lib %t2.lib // RUN: touch %t.obj // RUN: %clang --target=x86_64-pc-windows-msvc -fsycl -foffload-static-lib=%t1.lib -foffload-static-lib=%t2.lib %t.obj -### 2>&1 \ // RUN: | FileCheck -DOBJ=%t.obj -DLIB1=%t1.lib -DLIB2=%t2.lib %s -check-prefixes=FOFFLOAD_STATIC_MULTI_LIB,FOFFLOAD_STATIC_MULTI_LIB_DEFAULT