mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-25 06:18:56 -04:00

Summary: This patch adds new logic to create the necessary tool chains to support offloading for OpenMP. The OpenMP related options are checked and the tool chains created accordingly. Diagnostics are emitted in case the options are illegal or express unknown targets. Reviewers: echristo, tra, jlebar, rsmith, ABataev, hfinkel Subscribers: whchung, mkuron, mehdi_amini, cfe-commits, Hahnfeld, arpith-jacob, carlo.bertolli, caomhin Differential Revision: https://reviews.llvm.org/D21843 llvm-svn: 285311
349 lines
11 KiB
C++
349 lines
11 KiB
C++
//===--- Action.cpp - Abstract compilation steps --------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Driver/Action.h"
|
|
#include "clang/Driver/ToolChain.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/Regex.h"
|
|
#include <cassert>
|
|
using namespace clang::driver;
|
|
using namespace llvm::opt;
|
|
|
|
Action::~Action() {}
|
|
|
|
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 AnalyzeJobClass: return "analyzer";
|
|
case MigrateJobClass: return "migrator";
|
|
case CompileJobClass: return "compiler";
|
|
case BackendJobClass: return "backend";
|
|
case AssembleJobClass: return "assembler";
|
|
case LinkJobClass: return "linker";
|
|
case LipoJobClass: return "lipo";
|
|
case DsymutilJobClass: return "dsymutil";
|
|
case VerifyDebugInfoJobClass: return "verify-debug-info";
|
|
case VerifyPCHJobClass: return "verify-pch";
|
|
}
|
|
|
|
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;
|
|
|
|
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";
|
|
|
|
// TODO: Add other programming models here.
|
|
}
|
|
|
|
if (!ActiveOffloadKindMask)
|
|
return "";
|
|
|
|
std::string Res("host");
|
|
if (ActiveOffloadKindMask & OFK_Cuda)
|
|
Res += "-cuda";
|
|
if (ActiveOffloadKindMask & OFK_OpenMP)
|
|
Res += "-openmp";
|
|
|
|
// TODO: Add other programming models here.
|
|
|
|
return Res;
|
|
}
|
|
|
|
std::string
|
|
Action::getOffloadingFileNamePrefix(llvm::StringRef NormalizedTriple) const {
|
|
// A file prefix is only generated for device actions and consists of the
|
|
// offload kind and triple.
|
|
if (!OffloadingDeviceKind)
|
|
return "";
|
|
|
|
std::string Res("-");
|
|
Res += getOffloadingKindPrefix();
|
|
Res += "-";
|
|
Res += NormalizedTriple;
|
|
return Res;
|
|
}
|
|
|
|
void InputAction::anchor() {}
|
|
|
|
InputAction::InputAction(const Arg &_Input, types::ID _Type)
|
|
: Action(InputClass, _Type), Input(_Input) {
|
|
}
|
|
|
|
void BindArchAction::anchor() {}
|
|
|
|
BindArchAction::BindArchAction(Action *Input, llvm::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) {}
|
|
|
|
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 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) {}
|