|
43 | 43 | #include "ToolChains/TCE.h"
|
44 | 44 | #include "ToolChains/WebAssembly.h"
|
45 | 45 | #include "ToolChains/XCore.h"
|
| 46 | +#include "ToolChains/SYCL.h" |
46 | 47 | #include "clang/Basic/Version.h"
|
47 | 48 | #include "clang/Config/config.h"
|
48 | 49 | #include "clang/Driver/Action.h"
|
@@ -693,6 +694,61 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
|
693 | 694 | << OpenMPTargets->getAsString(C.getInputArgs());
|
694 | 695 | }
|
695 | 696 |
|
| 697 | + // |
| 698 | + // SYCL |
| 699 | + // |
| 700 | + // We need to generate a SYCL toolchain if the user specified targets with |
| 701 | + // the -fsycl-targets option. |
| 702 | + if (Arg *SYCLTargets = |
| 703 | + C.getInputArgs().getLastArg(options::OPT_fsycl_targets_EQ)) { |
| 704 | + if (SYCLTargets->getNumValues()) { |
| 705 | + // We expect that -fsycl-targets is always used in conjunction with the |
| 706 | + // -fsycl option |
| 707 | + bool HasValidSYCLRuntime = C.getInputArgs().hasFlag( |
| 708 | + options::OPT_fsycl, options::OPT_fno_sycl, false); |
| 709 | + |
| 710 | + if (HasValidSYCLRuntime) { |
| 711 | + llvm::StringMap<const char *> FoundNormalizedTriples; |
| 712 | + for (const char *Val : SYCLTargets->getValues()) { |
| 713 | + llvm::Triple TT(Val); |
| 714 | + std::string NormalizedName = TT.normalize(); |
| 715 | + |
| 716 | + // Make sure we don't have a duplicate triple. |
| 717 | + auto Duplicate = FoundNormalizedTriples.find(NormalizedName); |
| 718 | + if (Duplicate != FoundNormalizedTriples.end()) { |
| 719 | + Diag(clang::diag::warn_drv_sycl_offload_target_duplicate) |
| 720 | + << Val << Duplicate->second; |
| 721 | + continue; |
| 722 | + } |
| 723 | + |
| 724 | + // Store the current triple so that we can check for duplicates in the |
| 725 | + // following iterations. |
| 726 | + FoundNormalizedTriples[NormalizedName] = Val; |
| 727 | + |
| 728 | + // If the specified target is invalid, emit a diagnostic. |
| 729 | + if (TT.getArch() == llvm::Triple::UnknownArch) |
| 730 | + Diag(clang::diag::err_drv_invalid_sycl_target) << Val; |
| 731 | + else { |
| 732 | + const ToolChain *HostTC = |
| 733 | + C.getSingleOffloadToolChain<Action::OFK_Host>(); |
| 734 | + const llvm::Triple &HostTriple = HostTC->getTriple(); |
| 735 | + // Use the SYCL and host triples as the key into the ToolChains map, |
| 736 | + // because the device toolchain we create depends on both. |
| 737 | + auto &SYCLTC = ToolChains[TT.str() + "/" + HostTriple.str()]; |
| 738 | + if (!SYCLTC) { |
| 739 | + SYCLTC = llvm::make_unique<toolchains::SYCLToolChain>( |
| 740 | + *this, TT, *HostTC, C.getInputArgs()); |
| 741 | + } |
| 742 | + C.addOffloadDeviceToolChain(SYCLTC.get(), Action::OFK_SYCL); |
| 743 | + } |
| 744 | + } |
| 745 | + } else |
| 746 | + Diag(clang::diag::err_drv_expecting_fsycl_with_fsycl_targets); |
| 747 | + } else |
| 748 | + Diag(clang::diag::warn_drv_empty_joined_argument) |
| 749 | + << SYCLTargets->getAsString(C.getInputArgs()); |
| 750 | + } |
| 751 | + |
696 | 752 | //
|
697 | 753 | // TODO: Add support for other offloading programming models here.
|
698 | 754 | //
|
@@ -2852,6 +2908,154 @@ class OffloadingActionBuilder final {
|
2852 | 2908 | }
|
2853 | 2909 | };
|
2854 | 2910 |
|
| 2911 | + /// SYCL action builder. The host bitcode is passed to the device frontend |
| 2912 | + /// and all the device linked images are passed to the host link phase. |
| 2913 | + /// SPIR related are wrapped before added to the fat binary |
| 2914 | + class SYCLActionBuilder final : public DeviceActionBuilder { |
| 2915 | + /// The SYCL actions for the current input. |
| 2916 | + ActionList SYCLDeviceActions; |
| 2917 | + |
| 2918 | + /// The linker inputs obtained for each toolchain. |
| 2919 | + SmallVector<ActionList, 8> DeviceLinkerInputs; |
| 2920 | + |
| 2921 | + /// The compiler inputs obtained for each toolchain |
| 2922 | + Action * DeviceCompilerInput = nullptr; |
| 2923 | + |
| 2924 | + public: |
| 2925 | + SYCLActionBuilder(Compilation &C, DerivedArgList &Args, |
| 2926 | + const Driver::InputList &Inputs) |
| 2927 | + : DeviceActionBuilder(C, Args, Inputs, Action::OFK_SYCL) {} |
| 2928 | + |
| 2929 | + ActionBuilderReturnCode |
| 2930 | + getDeviceDependences(OffloadAction::DeviceDependences &DA, |
| 2931 | + phases::ID CurPhase, phases::ID FinalPhase, |
| 2932 | + PhasesTy &Phases) override { |
| 2933 | + |
| 2934 | + // We should always have an action for each input. |
| 2935 | + assert(SYCLDeviceActions.size() == ToolChains.size() && |
| 2936 | + "Number of SYCL actions and toolchains do not match."); |
| 2937 | + |
| 2938 | + // FIXME: This adds the integrated header generation pass before the |
| 2939 | + // Host compilation pass so the Host can use the header generated. This |
| 2940 | + // can be improved upon to where the header generation and spv generation |
| 2941 | + // is done in the same step. Currently, its not too efficient. |
| 2942 | + // The host depends on the generated integrated header from the device |
| 2943 | + // compilation. |
| 2944 | + if (CurPhase == phases::Compile) { |
| 2945 | + for (Action *&A : SYCLDeviceActions) { |
| 2946 | + DeviceCompilerInput = |
| 2947 | + C.MakeAction<CompileJobAction>(A, types::TY_SYCL_Header); |
| 2948 | + } |
| 2949 | + DA.add(*DeviceCompilerInput, *ToolChains.front(), /*BoundArch=*/nullptr, |
| 2950 | + Action::OFK_SYCL); |
| 2951 | + // Clear the input file, it is already a dependence to a host |
| 2952 | + // action. |
| 2953 | + DeviceCompilerInput = nullptr; |
| 2954 | + } |
| 2955 | + |
| 2956 | + // The host only depends on device action in the linking phase, when all |
| 2957 | + // the device images have to be embedded in the host image. |
| 2958 | + if (CurPhase == phases::Link) { |
| 2959 | + assert(ToolChains.size() == DeviceLinkerInputs.size() && |
| 2960 | + "Toolchains and linker inputs sizes do not match."); |
| 2961 | + auto LI = DeviceLinkerInputs.begin(); |
| 2962 | + for (auto *A : SYCLDeviceActions) { |
| 2963 | + LI->push_back(A); |
| 2964 | + ++LI; |
| 2965 | + } |
| 2966 | + |
| 2967 | + // We passed the device action as a host dependence, so we don't need to |
| 2968 | + // do anything else with them. |
| 2969 | + SYCLDeviceActions.clear(); |
| 2970 | + return ABRT_Success; |
| 2971 | + } |
| 2972 | + |
| 2973 | + // By default, we produce an action for each device arch. |
| 2974 | + for (Action *&A : SYCLDeviceActions) { |
| 2975 | + A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A, |
| 2976 | + AssociatedOffloadKind); |
| 2977 | + } |
| 2978 | + |
| 2979 | + return ABRT_Success; |
| 2980 | + } |
| 2981 | + |
| 2982 | + ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { |
| 2983 | + |
| 2984 | + // If this is an input action replicate it for each SYCL toolchain. |
| 2985 | + if (auto *IA = dyn_cast<InputAction>(HostAction)) { |
| 2986 | + SYCLDeviceActions.clear(); |
| 2987 | + for (unsigned I = 0; I < ToolChains.size(); ++I) |
| 2988 | + SYCLDeviceActions.push_back( |
| 2989 | + C.MakeAction<InputAction>(IA->getInputArg(), IA->getType())); |
| 2990 | + return ABRT_Success; |
| 2991 | + } |
| 2992 | + |
| 2993 | + // If this is an unbundling action use it as is for each SYCL toolchain. |
| 2994 | + if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { |
| 2995 | + SYCLDeviceActions.clear(); |
| 2996 | + for (unsigned I = 0; I < ToolChains.size(); ++I) { |
| 2997 | + SYCLDeviceActions.push_back(UA); |
| 2998 | + UA->registerDependentActionInfo( |
| 2999 | + ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_SYCL); |
| 3000 | + } |
| 3001 | + return ABRT_Success; |
| 3002 | + } |
| 3003 | + return ABRT_Success; |
| 3004 | + } |
| 3005 | + |
| 3006 | + void appendTopLevelActions(ActionList &AL) override { |
| 3007 | + if (SYCLDeviceActions.empty()) |
| 3008 | + return; |
| 3009 | + |
| 3010 | + // We should always have an action for each input. |
| 3011 | + assert(SYCLDeviceActions.size() == ToolChains.size() && |
| 3012 | + "Number of SYCL actions and toolchains do not match."); |
| 3013 | + |
| 3014 | + // Append all device actions followed by the proper offload action. |
| 3015 | + auto TI = ToolChains.begin(); |
| 3016 | + for (auto *A : SYCLDeviceActions) { |
| 3017 | + OffloadAction::DeviceDependences Dep; |
| 3018 | + Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_SYCL); |
| 3019 | + AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); |
| 3020 | + ++TI; |
| 3021 | + } |
| 3022 | + // We no longer need the action stored in this builder. |
| 3023 | + SYCLDeviceActions.clear(); |
| 3024 | + } |
| 3025 | + |
| 3026 | + void appendLinkDependences(OffloadAction::DeviceDependences &DA) override { |
| 3027 | + assert(ToolChains.size() == DeviceLinkerInputs.size() && |
| 3028 | + "Toolchains and linker inputs sizes do not match."); |
| 3029 | + |
| 3030 | + // Append a new link action for each device. |
| 3031 | + auto TC = ToolChains.begin(); |
| 3032 | + for (auto &LI : DeviceLinkerInputs) { |
| 3033 | + auto *DeviceLinkAction = |
| 3034 | + C.MakeAction<LinkJobAction>(LI, types::TY_Image); |
| 3035 | + DA.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, |
| 3036 | + Action::OFK_SYCL); |
| 3037 | + ++TC; |
| 3038 | + } |
| 3039 | + } |
| 3040 | + |
| 3041 | + bool initialize() override { |
| 3042 | + // Get the SYCL toolchains. If we don't get any, the action builder will |
| 3043 | + // know there is nothing to do related to SYCL offloading. |
| 3044 | + auto SYCLTCRange = C.getOffloadToolChains<Action::OFK_SYCL>(); |
| 3045 | + for (auto TI = SYCLTCRange.first, TE = SYCLTCRange.second; TI != TE; |
| 3046 | + ++TI) |
| 3047 | + ToolChains.push_back(TI->second); |
| 3048 | + |
| 3049 | + DeviceLinkerInputs.resize(ToolChains.size()); |
| 3050 | + return false; |
| 3051 | + } |
| 3052 | + |
| 3053 | + bool canUseBundlerUnbundler() const override { |
| 3054 | + // SYCL should use bundled files whenever possible. |
| 3055 | + return true; |
| 3056 | + } |
| 3057 | + }; |
| 3058 | + |
2855 | 3059 | ///
|
2856 | 3060 | /// TODO: Add the implementation for other specialized builders here.
|
2857 | 3061 | ///
|
@@ -2879,6 +3083,9 @@ class OffloadingActionBuilder final {
|
2879 | 3083 | // Create a specialized builder for OpenMP.
|
2880 | 3084 | SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs));
|
2881 | 3085 |
|
| 3086 | + // Create a specialized builder for SYCL. |
| 3087 | + SpecializedBuilders.push_back(new SYCLActionBuilder(C, Args, Inputs)); |
| 3088 | + |
2882 | 3089 | //
|
2883 | 3090 | // TODO: Build other specialized builders here.
|
2884 | 3091 | //
|
|
0 commit comments