Index: include/clang/Driver/Action.h =================================================================== --- include/clang/Driver/Action.h +++ include/clang/Driver/Action.h @@ -67,9 +67,10 @@ VerifyDebugInfoJobClass, VerifyPCHJobClass, OffloadBundlingJobClass, + OffloadUnbundlingJobClass, JobClassFirst = PreprocessJobClass, - JobClassLast = OffloadBundlingJobClass + JobClassLast = OffloadUnbundlingJobClass }; // The offloading kind determines if this action is binded to a particular @@ -494,6 +495,52 @@ } }; +class OffloadUnbundlingJobAction final : public JobAction { + void anchor() override; + +public: + /// Type that provides information about the actions that depend on this + /// unbundling action. + struct DependingActionInfoTy final { + /// \brief The tool chain of the depending action. + const ToolChain *DependingToolChain = nullptr; + /// \brief The bound architecture of the depending action. + const char *DependingBoundArch = nullptr; + /// \brief The offload kind of the depending action. + const OffloadKind DependingOffloadKind = OFK_None; + DependingActionInfoTy(const ToolChain *DependingToolChain, + const char *DependingBoundArch, + const OffloadKind DependingOffloadKind) + : DependingToolChain(DependingToolChain), + DependingBoundArch(DependingBoundArch), + DependingOffloadKind(DependingOffloadKind){}; + }; + +private: + /// Constainer that kepps information about each dependence of this unbundling + /// action. + SmallVector DependingActionInfo; + +public: + // Offloading unbundling doesn't change the type of output. + OffloadUnbundlingJobAction(Action *Input); + + /// Register information about a depending action. + void registerDependingActionInfo(const ToolChain *TC, const char *BoundArch, + OffloadKind Kind) { + DependingActionInfo.push_back({TC, BoundArch, Kind}); + } + + /// Return the information about all depending actions. + ArrayRef getDependingActionsInfo() const { + return DependingActionInfo; + } + + static bool classof(const Action *A) { + return A->getKind() == OffloadUnbundlingJobClass; + } +}; + } // end namespace driver } // end namespace clang Index: include/clang/Driver/Types.h =================================================================== --- include/clang/Driver/Types.h +++ include/clang/Driver/Types.h @@ -72,6 +72,11 @@ /// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers). bool isObjC(ID Id); + /// isSrcFile - Is this a source file, i.e. something that still has to be + /// preprocessed. The logic behind this is the same that decides the first + /// compilation phase is a preprocessor one. + bool isSrcFile(ID Id); + /// lookupTypeForExtension - Lookup the type to use for the file /// extension \p Ext. ID lookupTypeForExtension(const char *Ext); Index: lib/Driver/Action.cpp =================================================================== --- lib/Driver/Action.cpp +++ lib/Driver/Action.cpp @@ -38,6 +38,8 @@ case VerifyPCHJobClass: return "verify-pch"; case OffloadBundlingJobClass: return "clang-offload-bundler"; + case OffloadUnbundlingJobClass: + return "clang-offload-unbundler"; } llvm_unreachable("invalid class"); @@ -47,6 +49,9 @@ // Offload action set its own kinds on their dependences. if (Kind == OffloadClass) return; + // Unbundling actions use the host kinds. + if (Kind == OffloadUnbundlingJobClass) + return; assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) && "Setting device kind to a different device??"); @@ -353,3 +358,8 @@ OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs) : JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {} + +void OffloadUnbundlingJobAction::anchor() {} + +OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input) + : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {} Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -1854,6 +1854,17 @@ return ABRT_Success; } + // If this is an unbundling action use it as is for each OpenMP toolchain. + if (auto *UA = dyn_cast(HostAction)) { + OpenMPDeviceActions.clear(); + for (unsigned I = 0; I < ToolChains.size(); ++I) { + OpenMPDeviceActions.push_back(UA); + UA->registerDependingActionInfo(ToolChains[I], /*BoundArch=*/nullptr, + Action::OFK_OpenMP); + } + return ABRT_Success; + } + // When generating code for OpenMP we use the host compile phase result as // dependence to the device compile phase so that it can learn what // declaration should be emitted. However, this is not the only use for @@ -2043,11 +2054,25 @@ /// 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. - bool addHostDependenceToDeviceActions(Action *HostAction, + bool addHostDependenceToDeviceActions(Action *&HostAction, const Arg *InputArg) { if (!IsValid) return true; + // If we are supporting bundling/unbundling and the current action is an + // input action of non-source file, we replace the host action by the + // unbundling action. + if (CanUseBundler && isa(HostAction) && + InputArg->getOption().getKind() == llvm::opt::Option::InputClass && + !types::isSrcFile(HostAction->getType())) { + auto UnbundlingHostAction = + C.MakeAction(HostAction); + UnbundlingHostAction->registerDependingActionInfo( + C.getSingleOffloadToolChain(), + /*BoundArch=*/nullptr, Action::OFK_Host); + HostAction = UnbundlingHostAction; + } + assert(HostAction && "Invalid host action!"); // Register the offload kinds that are used. Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -265,6 +265,7 @@ return getClang(); case Action::OffloadBundlingJobClass: + case Action::OffloadUnbundlingJobClass: // FIXME: Add a tool for the bundling actions. return nullptr; } Index: lib/Driver/Types.cpp =================================================================== --- lib/Driver/Types.cpp +++ lib/Driver/Types.cpp @@ -153,6 +153,10 @@ } } +bool types::isSrcFile(ID Id) { + return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; +} + types::ID types::lookupTypeForExtension(const char *Ext) { return llvm::StringSwitch(Ext) .Case("c", TY_C) Index: test/Driver/openmp-offload.c =================================================================== --- test/Driver/openmp-offload.c +++ test/Driver/openmp-offload.c @@ -267,3 +267,56 @@ // CHK-BUACTIONS: 17: backend, {2}, assembler, (host-openmp) // CHK-BUACTIONS: 18: assembler, {17}, object, (host-openmp) // CHK-BUACTIONS: 19: clang-offload-bundler, {9, 16, 18}, object, (host-openmp) + +/// ########################################################################### + +/// Check separate compilation with offloading - unbundling actions +// RUN: touch %t.i +// RUN: %clang -### -ccc-print-phases -fopenmp -o %t.out -lsomelib -target powerpc64le-linux -fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu %t.i 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-UBACTIONS %s + +// CHK-UBACTIONS: 0: input, "somelib", object, (host-openmp) +// CHK-UBACTIONS: 1: input, "[[INPUT:.+\.i]]", cpp-output, (host-openmp) +// CHK-UBACTIONS: 2: clang-offload-unbundler, {1}, cpp-output, (host-openmp) +// CHK-UBACTIONS: 3: compiler, {2}, ir, (host-openmp) +// CHK-UBACTIONS: 4: backend, {3}, assembler, (host-openmp) +// CHK-UBACTIONS: 5: assembler, {4}, object, (host-openmp) +// CHK-UBACTIONS: 6: linker, {0, 5}, image, (host-openmp) +// CHK-UBACTIONS: 7: input, "somelib", object, (device-openmp) +// CHK-UBACTIONS: 8: compiler, {2}, ir, (device-openmp) +// CHK-UBACTIONS: 9: offload, "host-openmp (powerpc64le--linux)" {3}, "device-openmp (powerpc64le-ibm-linux-gnu)" {8}, ir +// CHK-UBACTIONS: 10: backend, {9}, assembler, (device-openmp) +// CHK-UBACTIONS: 11: assembler, {10}, object, (device-openmp) +// CHK-UBACTIONS: 12: linker, {7, 11}, image, (device-openmp) +// CHK-UBACTIONS: 13: input, "somelib", object, (device-openmp) +// CHK-UBACTIONS: 14: compiler, {2}, ir, (device-openmp) +// CHK-UBACTIONS: 15: offload, "host-openmp (powerpc64le--linux)" {3}, "device-openmp (x86_64-pc-linux-gnu)" {14}, ir +// CHK-UBACTIONS: 16: backend, {15}, assembler, (device-openmp) +// CHK-UBACTIONS: 17: assembler, {16}, object, (device-openmp) +// CHK-UBACTIONS: 18: linker, {13, 17}, image, (device-openmp) +// CHK-UBACTIONS: 19: offload, "host-openmp (powerpc64le--linux)" {6}, "device-openmp (powerpc64le-ibm-linux-gnu)" {12}, "device-openmp (x86_64-pc-linux-gnu)" {18}, image + +/// ########################################################################### + +/// Check separate compilation with offloading - unbundling/bundling actions +// RUN: touch %t.i +// RUN: %clang -### -ccc-print-phases -fopenmp -c -o %t.o -lsomelib -target powerpc64le-linux -fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu %t.i 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-UBUACTIONS %s + +// CHK-UBUACTIONS: 0: input, "[[INPUT:.+\.i]]", cpp-output, (host-openmp) +// CHK-UBUACTIONS: 1: clang-offload-unbundler, {0}, cpp-output, (host-openmp) +// CHK-UBUACTIONS: 2: compiler, {1}, ir, (host-openmp) +// CHK-UBUACTIONS: 3: compiler, {1}, ir, (device-openmp) +// CHK-UBUACTIONS: 4: offload, "host-openmp (powerpc64le--linux)" {2}, "device-openmp (powerpc64le-ibm-linux-gnu)" {3}, ir +// CHK-UBUACTIONS: 5: backend, {4}, assembler, (device-openmp) +// CHK-UBUACTIONS: 6: assembler, {5}, object, (device-openmp) +// CHK-UBUACTIONS: 7: offload, "device-openmp (powerpc64le-ibm-linux-gnu)" {6}, object +// CHK-UBUACTIONS: 8: compiler, {1}, ir, (device-openmp) +// CHK-UBUACTIONS: 9: offload, "host-openmp (powerpc64le--linux)" {2}, "device-openmp (x86_64-pc-linux-gnu)" {8}, ir +// CHK-UBUACTIONS: 10: backend, {9}, assembler, (device-openmp) +// CHK-UBUACTIONS: 11: assembler, {10}, object, (device-openmp) +// CHK-UBUACTIONS: 12: offload, "device-openmp (x86_64-pc-linux-gnu)" {11}, object +// CHK-UBUACTIONS: 13: backend, {2}, assembler, (host-openmp) +// CHK-UBUACTIONS: 14: assembler, {13}, object, (host-openmp) +// CHK-UBUACTIONS: 15: clang-offload-bundler, {7, 12, 14}, object, (host-openmp) +