425 lines
14 KiB
C++
425 lines
14 KiB
C++
//===- Action.cpp - Abstract compilation steps ----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Driver/Action.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include <cassert>
|
|
#include <string>
|
|
|
|
using namespace clang;
|
|
using namespace driver;
|
|
using namespace llvm::opt;
|
|
|
|
Action::~Action() = default;
|
|
|
|
const char *Action::getClassName(ActionClass AC) {
|
|
switch (AC) {
|
|
case InputClass: return "input";
|
|
case BindArchClass: return "bind-arch";
|
|
case OffloadClass:
|
|
return "offload";
|
|
case PreprocessJobClass: return "preprocessor";
|
|
case PrecompileJobClass: return "precompiler";
|
|
case HeaderModulePrecompileJobClass: return "header-module-precompiler";
|
|
case AnalyzeJobClass: return "analyzer";
|
|
case MigrateJobClass: return "migrator";
|
|
case CompileJobClass: return "compiler";
|
|
case BackendJobClass: return "backend";
|
|
case AssembleJobClass: return "assembler";
|
|
case IfsMergeJobClass: return "interface-stub-merger";
|
|
case LinkJobClass: return "linker";
|
|
case LipoJobClass: return "lipo";
|
|
case DsymutilJobClass: return "dsymutil";
|
|
case VerifyDebugInfoJobClass: return "verify-debug-info";
|
|
case VerifyPCHJobClass: return "verify-pch";
|
|
case OffloadBundlingJobClass:
|
|
return "clang-offload-bundler";
|
|
case OffloadUnbundlingJobClass:
|
|
return "clang-offload-unbundler";
|
|
case OffloadWrapperJobClass:
|
|
return "clang-offload-wrapper";
|
|
case StaticLibJobClass:
|
|
return "static-lib-linker";
|
|
}
|
|
|
|
llvm_unreachable("invalid class");
|
|
}
|
|
|
|
void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
|
|
// 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??");
|
|
assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
|
|
OffloadingDeviceKind = OKind;
|
|
OffloadingArch = OArch;
|
|
|
|
for (auto *A : Inputs)
|
|
A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
|
|
}
|
|
|
|
void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
|
|
// Offload action set its own kinds on their dependences.
|
|
if (Kind == OffloadClass)
|
|
return;
|
|
|
|
assert(OffloadingDeviceKind == OFK_None &&
|
|
"Setting a host kind in a device action.");
|
|
ActiveOffloadKindMask |= OKinds;
|
|
OffloadingArch = OArch;
|
|
|
|
for (auto *A : Inputs)
|
|
A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);
|
|
}
|
|
|
|
void Action::propagateOffloadInfo(const Action *A) {
|
|
if (unsigned HK = A->getOffloadingHostActiveKinds())
|
|
propagateHostOffloadInfo(HK, A->getOffloadingArch());
|
|
else
|
|
propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
|
|
A->getOffloadingArch());
|
|
}
|
|
|
|
std::string Action::getOffloadingKindPrefix() const {
|
|
switch (OffloadingDeviceKind) {
|
|
case OFK_None:
|
|
break;
|
|
case OFK_Host:
|
|
llvm_unreachable("Host kind is not an offloading device kind.");
|
|
break;
|
|
case OFK_Cuda:
|
|
return "device-cuda";
|
|
case OFK_OpenMP:
|
|
return "device-openmp";
|
|
case OFK_HIP:
|
|
return "device-hip";
|
|
|
|
// TODO: Add other programming models here.
|
|
}
|
|
|
|
if (!ActiveOffloadKindMask)
|
|
return {};
|
|
|
|
std::string Res("host");
|
|
assert(!((ActiveOffloadKindMask & OFK_Cuda) &&
|
|
(ActiveOffloadKindMask & OFK_HIP)) &&
|
|
"Cannot offload CUDA and HIP at the same time");
|
|
if (ActiveOffloadKindMask & OFK_Cuda)
|
|
Res += "-cuda";
|
|
if (ActiveOffloadKindMask & OFK_HIP)
|
|
Res += "-hip";
|
|
if (ActiveOffloadKindMask & OFK_OpenMP)
|
|
Res += "-openmp";
|
|
|
|
// TODO: Add other programming models here.
|
|
|
|
return Res;
|
|
}
|
|
|
|
/// Return a string that can be used as prefix in order to generate unique files
|
|
/// for each offloading kind.
|
|
std::string
|
|
Action::GetOffloadingFileNamePrefix(OffloadKind Kind,
|
|
StringRef NormalizedTriple,
|
|
bool CreatePrefixForHost) {
|
|
// Don't generate prefix for host actions unless required.
|
|
if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))
|
|
return {};
|
|
|
|
std::string Res("-");
|
|
Res += GetOffloadKindName(Kind);
|
|
Res += "-";
|
|
Res += NormalizedTriple;
|
|
return Res;
|
|
}
|
|
|
|
/// Return a string with the offload kind name. If that is not defined, we
|
|
/// assume 'host'.
|
|
StringRef Action::GetOffloadKindName(OffloadKind Kind) {
|
|
switch (Kind) {
|
|
case OFK_None:
|
|
case OFK_Host:
|
|
return "host";
|
|
case OFK_Cuda:
|
|
return "cuda";
|
|
case OFK_OpenMP:
|
|
return "openmp";
|
|
case OFK_HIP:
|
|
return "hip";
|
|
|
|
// TODO: Add other programming models here.
|
|
}
|
|
|
|
llvm_unreachable("invalid offload kind");
|
|
}
|
|
|
|
void InputAction::anchor() {}
|
|
|
|
InputAction::InputAction(const Arg &_Input, types::ID _Type)
|
|
: Action(InputClass, _Type), Input(_Input) {}
|
|
|
|
void BindArchAction::anchor() {}
|
|
|
|
BindArchAction::BindArchAction(Action *Input, StringRef ArchName)
|
|
: Action(BindArchClass, Input), ArchName(ArchName) {}
|
|
|
|
void OffloadAction::anchor() {}
|
|
|
|
OffloadAction::OffloadAction(const HostDependence &HDep)
|
|
: Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
|
|
OffloadingArch = HDep.getBoundArch();
|
|
ActiveOffloadKindMask = HDep.getOffloadKinds();
|
|
HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
|
|
HDep.getBoundArch());
|
|
}
|
|
|
|
OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
|
|
: Action(OffloadClass, DDeps.getActions(), Ty),
|
|
DevToolChains(DDeps.getToolChains()) {
|
|
auto &OKinds = DDeps.getOffloadKinds();
|
|
auto &BArchs = DDeps.getBoundArchs();
|
|
|
|
// If all inputs agree on the same kind, use it also for this action.
|
|
if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
|
|
OffloadingDeviceKind = OKinds.front();
|
|
|
|
// If we have a single dependency, inherit the architecture from it.
|
|
if (OKinds.size() == 1)
|
|
OffloadingArch = BArchs.front();
|
|
|
|
// Propagate info to the dependencies.
|
|
for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
|
|
getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
|
|
}
|
|
|
|
OffloadAction::OffloadAction(const HostDependence &HDep,
|
|
const DeviceDependences &DDeps)
|
|
: Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),
|
|
DevToolChains(DDeps.getToolChains()) {
|
|
// We use the kinds of the host dependence for this action.
|
|
OffloadingArch = HDep.getBoundArch();
|
|
ActiveOffloadKindMask = HDep.getOffloadKinds();
|
|
HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
|
|
HDep.getBoundArch());
|
|
|
|
// Add device inputs and propagate info to the device actions. Do work only if
|
|
// we have dependencies.
|
|
for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
|
|
if (auto *A = DDeps.getActions()[i]) {
|
|
getInputs().push_back(A);
|
|
A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
|
|
DDeps.getBoundArchs()[i]);
|
|
}
|
|
}
|
|
|
|
void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
|
|
if (!HostTC)
|
|
return;
|
|
assert(!getInputs().empty() && "No dependencies for offload action??");
|
|
auto *A = getInputs().front();
|
|
Work(A, HostTC, A->getOffloadingArch());
|
|
}
|
|
|
|
void OffloadAction::doOnEachDeviceDependence(
|
|
const OffloadActionWorkTy &Work) const {
|
|
auto I = getInputs().begin();
|
|
auto E = getInputs().end();
|
|
if (I == E)
|
|
return;
|
|
|
|
// We expect to have the same number of input dependences and device tool
|
|
// chains, except if we also have a host dependence. In that case we have one
|
|
// more dependence than we have device tool chains.
|
|
assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&
|
|
"Sizes of action dependences and toolchains are not consistent!");
|
|
|
|
// Skip host action
|
|
if (HostTC)
|
|
++I;
|
|
|
|
auto TI = DevToolChains.begin();
|
|
for (; I != E; ++I, ++TI)
|
|
Work(*I, *TI, (*I)->getOffloadingArch());
|
|
}
|
|
|
|
void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
|
|
doOnHostDependence(Work);
|
|
doOnEachDeviceDependence(Work);
|
|
}
|
|
|
|
void OffloadAction::doOnEachDependence(bool IsHostDependence,
|
|
const OffloadActionWorkTy &Work) const {
|
|
if (IsHostDependence)
|
|
doOnHostDependence(Work);
|
|
else
|
|
doOnEachDeviceDependence(Work);
|
|
}
|
|
|
|
bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }
|
|
|
|
Action *OffloadAction::getHostDependence() const {
|
|
assert(hasHostDependence() && "Host dependence does not exist!");
|
|
assert(!getInputs().empty() && "No dependencies for offload action??");
|
|
return HostTC ? getInputs().front() : nullptr;
|
|
}
|
|
|
|
bool OffloadAction::hasSingleDeviceDependence(
|
|
bool DoNotConsiderHostActions) const {
|
|
if (DoNotConsiderHostActions)
|
|
return getInputs().size() == (HostTC ? 2 : 1);
|
|
return !HostTC && getInputs().size() == 1;
|
|
}
|
|
|
|
Action *
|
|
OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {
|
|
assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&
|
|
"Single device dependence does not exist!");
|
|
// The previous assert ensures the number of entries in getInputs() is
|
|
// consistent with what we are doing here.
|
|
return HostTC ? getInputs()[1] : getInputs().front();
|
|
}
|
|
|
|
void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
|
|
const char *BoundArch,
|
|
OffloadKind OKind) {
|
|
DeviceActions.push_back(&A);
|
|
DeviceToolChains.push_back(&TC);
|
|
DeviceBoundArchs.push_back(BoundArch);
|
|
DeviceOffloadKinds.push_back(OKind);
|
|
}
|
|
|
|
OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
|
|
const char *BoundArch,
|
|
const DeviceDependences &DDeps)
|
|
: HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {
|
|
for (auto K : DDeps.getOffloadKinds())
|
|
HostOffloadKinds |= K;
|
|
}
|
|
|
|
void JobAction::anchor() {}
|
|
|
|
JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
|
|
: Action(Kind, Input, Type) {}
|
|
|
|
JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
|
|
: Action(Kind, Inputs, Type) {}
|
|
|
|
void PreprocessJobAction::anchor() {}
|
|
|
|
PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(PreprocessJobClass, Input, OutputType) {}
|
|
|
|
void PrecompileJobAction::anchor() {}
|
|
|
|
PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(PrecompileJobClass, Input, OutputType) {}
|
|
|
|
PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,
|
|
types::ID OutputType)
|
|
: JobAction(Kind, Input, OutputType) {
|
|
assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");
|
|
}
|
|
|
|
void HeaderModulePrecompileJobAction::anchor() {}
|
|
|
|
HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction(
|
|
Action *Input, types::ID OutputType, const char *ModuleName)
|
|
: PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType),
|
|
ModuleName(ModuleName) {}
|
|
|
|
void AnalyzeJobAction::anchor() {}
|
|
|
|
AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(AnalyzeJobClass, Input, OutputType) {}
|
|
|
|
void MigrateJobAction::anchor() {}
|
|
|
|
MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(MigrateJobClass, Input, OutputType) {}
|
|
|
|
void CompileJobAction::anchor() {}
|
|
|
|
CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(CompileJobClass, Input, OutputType) {}
|
|
|
|
void BackendJobAction::anchor() {}
|
|
|
|
BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(BackendJobClass, Input, OutputType) {}
|
|
|
|
void AssembleJobAction::anchor() {}
|
|
|
|
AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
|
|
: JobAction(AssembleJobClass, Input, OutputType) {}
|
|
|
|
void IfsMergeJobAction::anchor() {}
|
|
|
|
IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)
|
|
: JobAction(IfsMergeJobClass, Inputs, Type) {}
|
|
|
|
void LinkJobAction::anchor() {}
|
|
|
|
LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
|
|
: JobAction(LinkJobClass, Inputs, Type) {}
|
|
|
|
void LipoJobAction::anchor() {}
|
|
|
|
LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
|
|
: JobAction(LipoJobClass, Inputs, Type) {}
|
|
|
|
void DsymutilJobAction::anchor() {}
|
|
|
|
DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
|
|
: JobAction(DsymutilJobClass, Inputs, Type) {}
|
|
|
|
void VerifyJobAction::anchor() {}
|
|
|
|
VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
|
|
types::ID Type)
|
|
: JobAction(Kind, Input, Type) {
|
|
assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
|
|
"ActionClass is not a valid VerifyJobAction");
|
|
}
|
|
|
|
void VerifyDebugInfoJobAction::anchor() {}
|
|
|
|
VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
|
|
types::ID Type)
|
|
: VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
|
|
|
|
void VerifyPCHJobAction::anchor() {}
|
|
|
|
VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
|
|
: VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
|
|
|
|
void OffloadBundlingJobAction::anchor() {}
|
|
|
|
OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
|
|
: JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {}
|
|
|
|
void OffloadUnbundlingJobAction::anchor() {}
|
|
|
|
OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
|
|
: JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
|
|
|
|
void OffloadWrapperJobAction::anchor() {}
|
|
|
|
OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
|
|
types::ID Type)
|
|
: JobAction(OffloadWrapperJobClass, Inputs, Type) {}
|
|
|
|
void StaticLibJobAction::anchor() {}
|
|
|
|
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
|
|
: JobAction(StaticLibJobClass, Inputs, Type) {}
|