Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/Driver/Driver.cpp
Show First 20 Lines • Show All 3,435 Lines • ▼ Show 20 Lines | void appendLinkDeviceActions(ActionList &AL) override { | ||||
} | } | ||||
} | } | ||||
Action* appendLinkHostActions(ActionList &AL) override { return AL.back(); } | Action* appendLinkHostActions(ActionList &AL) override { return AL.back(); } | ||||
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} | void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} | ||||
}; | }; | ||||
/// OpenMP action builder. The host bitcode is passed to the device frontend | |||||
/// and all the device linked images are passed to the host link phase. | |||||
class OpenMPActionBuilder final : public DeviceActionBuilder { | |||||
/// The OpenMP actions for the current input. | |||||
ActionList OpenMPDeviceActions; | |||||
/// The linker inputs obtained for each toolchain. | |||||
SmallVector<ActionList, 8> DeviceLinkerInputs; | |||||
public: | |||||
OpenMPActionBuilder(Compilation &C, DerivedArgList &Args, | |||||
const Driver::InputList &Inputs) | |||||
: DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {} | |||||
ActionBuilderReturnCode | |||||
getDeviceDependences(OffloadAction::DeviceDependences &DA, | |||||
phases::ID CurPhase, phases::ID FinalPhase, | |||||
PhasesTy &Phases) override { | |||||
if (OpenMPDeviceActions.empty()) | |||||
return ABRT_Inactive; | |||||
// We should always have an action for each input. | |||||
assert(OpenMPDeviceActions.size() == ToolChains.size() && | |||||
"Number of OpenMP actions and toolchains do not match."); | |||||
// The host only depends on device action in the linking phase, when all | |||||
// the device images have to be embedded in the host image. | |||||
if (CurPhase == phases::Link) { | |||||
assert(ToolChains.size() == DeviceLinkerInputs.size() && | |||||
"Toolchains and linker inputs sizes do not match."); | |||||
auto LI = DeviceLinkerInputs.begin(); | |||||
for (auto *A : OpenMPDeviceActions) { | |||||
LI->push_back(A); | |||||
++LI; | |||||
} | |||||
// We passed the device action as a host dependence, so we don't need to | |||||
// do anything else with them. | |||||
OpenMPDeviceActions.clear(); | |||||
return ABRT_Success; | |||||
} | |||||
// By default, we produce an action for each device arch. | |||||
for (Action *&A : OpenMPDeviceActions) | |||||
A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); | |||||
return ABRT_Success; | |||||
} | |||||
ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { | |||||
// If this is an input action replicate it for each OpenMP toolchain. | |||||
if (auto *IA = dyn_cast<InputAction>(HostAction)) { | |||||
OpenMPDeviceActions.clear(); | |||||
for (unsigned I = 0; I < ToolChains.size(); ++I) | |||||
OpenMPDeviceActions.push_back( | |||||
C.MakeAction<InputAction>(IA->getInputArg(), IA->getType())); | |||||
return ABRT_Success; | |||||
} | |||||
// If this is an unbundling action use it as is for each OpenMP toolchain. | |||||
if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { | |||||
OpenMPDeviceActions.clear(); | |||||
auto *IA = cast<InputAction>(UA->getInputs().back()); | |||||
std::string FileName = IA->getInputArg().getAsString(Args); | |||||
// Check if the type of the file is the same as the action. Do not | |||||
// unbundle it if it is not. Do not unbundle .so files, for example, | |||||
// which are not object files. | |||||
if (IA->getType() == types::TY_Object && | |||||
(!llvm::sys::path::has_extension(FileName) || | |||||
types::lookupTypeForExtension( | |||||
llvm::sys::path::extension(FileName).drop_front()) != | |||||
types::TY_Object)) | |||||
return ABRT_Inactive; | |||||
for (unsigned I = 0; I < ToolChains.size(); ++I) { | |||||
OpenMPDeviceActions.push_back(UA); | |||||
UA->registerDependentActionInfo( | |||||
ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP); | |||||
} | |||||
return ABRT_Success; | |||||
} | |||||
// When generating code for OpenMP we use the host compile phase result as | |||||
// a dependence to the device compile phase so that it can learn what | |||||
// declarations should be emitted. However, this is not the only use for | |||||
// the host action, so we prevent it from being collapsed. | |||||
if (isa<CompileJobAction>(HostAction)) { | |||||
HostAction->setCannotBeCollapsedWithNextDependentAction(); | |||||
assert(ToolChains.size() == OpenMPDeviceActions.size() && | |||||
"Toolchains and device action sizes do not match."); | |||||
OffloadAction::HostDependence HDep( | |||||
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), | |||||
/*BoundArch=*/nullptr, Action::OFK_OpenMP); | |||||
auto TC = ToolChains.begin(); | |||||
for (Action *&A : OpenMPDeviceActions) { | |||||
assert(isa<CompileJobAction>(A)); | |||||
OffloadAction::DeviceDependences DDep; | |||||
DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); | |||||
A = C.MakeAction<OffloadAction>(HDep, DDep); | |||||
++TC; | |||||
} | |||||
} | |||||
return ABRT_Success; | |||||
} | |||||
void appendTopLevelActions(ActionList &AL) override { | |||||
if (OpenMPDeviceActions.empty()) | |||||
return; | |||||
// We should always have an action for each input. | |||||
assert(OpenMPDeviceActions.size() == ToolChains.size() && | |||||
"Number of OpenMP actions and toolchains do not match."); | |||||
// Append all device actions followed by the proper offload action. | |||||
auto TI = ToolChains.begin(); | |||||
for (auto *A : OpenMPDeviceActions) { | |||||
OffloadAction::DeviceDependences Dep; | |||||
Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP); | |||||
AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); | |||||
++TI; | |||||
} | |||||
// We no longer need the action stored in this builder. | |||||
OpenMPDeviceActions.clear(); | |||||
} | |||||
void appendLinkDeviceActions(ActionList &AL) override { | |||||
assert(ToolChains.size() == DeviceLinkerInputs.size() && | |||||
"Toolchains and linker inputs sizes do not match."); | |||||
// Append a new link action for each device. | |||||
auto TC = ToolChains.begin(); | |||||
for (auto &LI : DeviceLinkerInputs) { | |||||
auto *DeviceLinkAction = | |||||
C.MakeAction<LinkJobAction>(LI, types::TY_Image); | |||||
OffloadAction::DeviceDependences DeviceLinkDeps; | |||||
DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, | |||||
Action::OFK_OpenMP); | |||||
AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps, | |||||
DeviceLinkAction->getType())); | |||||
++TC; | |||||
} | |||||
DeviceLinkerInputs.clear(); | |||||
} | |||||
Action* appendLinkHostActions(ActionList &AL) override { | |||||
// Create wrapper bitcode from the result of device link actions and compile | |||||
// it to an object which will be added to the host link command. | |||||
auto *BC = C.MakeAction<OffloadWrapperJobAction>(AL, types::TY_LLVM_BC); | |||||
auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm); | |||||
return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object); | |||||
} | |||||
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} | |||||
bool initialize() override { | |||||
// Get the OpenMP toolchains. If we don't get any, the action builder will | |||||
// know there is nothing to do related to OpenMP offloading. | |||||
auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); | |||||
for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; | |||||
++TI) | |||||
ToolChains.push_back(TI->second); | |||||
DeviceLinkerInputs.resize(ToolChains.size()); | |||||
return false; | |||||
} | |||||
bool canUseBundlerUnbundler() const override { | |||||
// OpenMP should use bundled files whenever possible. | |||||
return true; | |||||
} | |||||
}; | |||||
/// | /// | ||||
/// TODO: Add the implementation for other specialized builders here. | /// TODO: Add the implementation for other specialized builders here. | ||||
/// | /// | ||||
/// Specialized builders being used by this offloading action builder. | /// Specialized builders being used by this offloading action builder. | ||||
SmallVector<DeviceActionBuilder *, 4> SpecializedBuilders; | SmallVector<DeviceActionBuilder *, 4> SpecializedBuilders; | ||||
/// Flag set to true if all valid builders allow file bundling/unbundling. | /// Flag set to true if all valid builders allow file bundling/unbundling. | ||||
bool CanUseBundler; | bool CanUseBundler; | ||||
public: | public: | ||||
OffloadingActionBuilder(Compilation &C, DerivedArgList &Args, | OffloadingActionBuilder(Compilation &C, DerivedArgList &Args, | ||||
const Driver::InputList &Inputs) | const Driver::InputList &Inputs) | ||||
: C(C) { | : C(C) { | ||||
// Create a specialized builder for each device toolchain. | // Create a specialized builder for each device toolchain. | ||||
IsValid = true; | IsValid = true; | ||||
// Create a specialized builder for CUDA. | // Create a specialized builder for CUDA. | ||||
SpecializedBuilders.push_back(new CudaActionBuilder(C, Args, Inputs)); | SpecializedBuilders.push_back(new CudaActionBuilder(C, Args, Inputs)); | ||||
// Create a specialized builder for HIP. | // Create a specialized builder for HIP. | ||||
SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs)); | SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs)); | ||||
// Create a specialized builder for OpenMP. | |||||
SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs)); | |||||
// | // | ||||
// TODO: Build other specialized builders here. | // TODO: Build other specialized builders here. | ||||
// | // | ||||
// Initialize all the builders, keeping track of errors. If all valid | // Initialize all the builders, keeping track of errors. If all valid | ||||
// builders agree that we can use bundling, set the flag to true. | // builders agree that we can use bundling, set the flag to true. | ||||
unsigned ValidBuilders = 0u; | unsigned ValidBuilders = 0u; | ||||
unsigned ValidBuildersSupportingBundling = 0u; | unsigned ValidBuildersSupportingBundling = 0u; | ||||
▲ Show 20 Lines • Show All 1,849 Lines • ▼ Show 20 Lines | InputInfoList Driver::BuildJobsForActionNoCache( | ||||
else { | else { | ||||
// We only have to generate a prefix for the host if this is not a top-level | // We only have to generate a prefix for the host if this is not a top-level | ||||
// action. | // action. | ||||
std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( | std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( | ||||
A->getOffloadingDeviceKind(), TC->getTriple().normalize(), | A->getOffloadingDeviceKind(), TC->getTriple().normalize(), | ||||
/*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) || | /*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) || | ||||
!(A->getOffloadingHostActiveKinds() == Action::OFK_None || | !(A->getOffloadingHostActiveKinds() == Action::OFK_None || | ||||
AtTopLevel)); | AtTopLevel)); | ||||
if (isa<OffloadWrapperJobAction>(JA)) { | |||||
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) | |||||
BaseInput = FinalOutput->getValue(); | |||||
else | |||||
BaseInput = getDefaultImageName(); | |||||
BaseInput = | |||||
C.getArgs().MakeArgString(std::string(BaseInput) + "-wrapper"); | |||||
} | |||||
Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, | Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, | ||||
AtTopLevel, MultipleArchs, | AtTopLevel, MultipleArchs, | ||||
OffloadingPrefix), | OffloadingPrefix), | ||||
BaseInput); | BaseInput); | ||||
} | } | ||||
if (CCCPrintBindings && !CCGenDiagnostics) { | if (CCCPrintBindings && !CCGenDiagnostics) { | ||||
llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' | llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' | ||||
▲ Show 20 Lines • Show All 879 Lines • Show Last 20 Lines |