Code improvements in OpenMP CodeGen.

This patch makes class OMPPrivateScope a common class for all private variables. Reworked processing of firstprivate variables (now it is based on OMPPrivateScope too).

llvm-svn: 219486
This commit is contained in:
Alexey Bataev 2014-10-10 09:48:26 +00:00
parent afe56ae75d
commit 435ad7ba5e
3 changed files with 108 additions and 71 deletions

View File

@ -25,26 +25,17 @@ using namespace clang;
using namespace CodeGen;
void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
CodeGenFunction::OuterDeclMapTy OuterDeclMap;
CGF.EmitOMPFirstprivateClause(Directive, OuterDeclMap);
if (!OuterDeclMap.empty()) {
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPFirstprivateClause(Directive, PrivateScope);
if (PrivateScope.Privatize()) {
// Emit implicit barrier to synchronize threads and avoid data races.
auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>(
CGOpenMPRuntime::OMP_IDENT_KMPC |
CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL);
CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(),
Flags);
// Remap captured variables to use their private copies in the outlined
// function.
for (auto I : OuterDeclMap) {
CGF.LocalDeclMap[I.first] = I.second;
}
}
CGCapturedStmtInfo::EmitBody(CGF, S);
// Clear mappings of captured private variables.
for (auto I : OuterDeclMap) {
CGF.LocalDeclMap.erase(I.first);
}
}
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)

View File

@ -94,7 +94,7 @@ void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
void CodeGenFunction::EmitOMPFirstprivateClause(
const OMPExecutableDirective &D,
CodeGenFunction::OuterDeclMapTy &OuterDeclMap) {
CodeGenFunction::OMPPrivateScope &PrivateScope) {
auto PrivateFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_firstprivate;
};
@ -104,25 +104,34 @@ void CodeGenFunction::EmitOMPFirstprivateClause(
auto IRef = C->varlist_begin();
auto InitsRef = C->inits().begin();
for (auto IInit : C->private_copies()) {
auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
bool IsRegistered;
if (*InitsRef != nullptr) {
// Emit VarDecl with copy init for arrays.
auto *FD = CapturedStmtInfo->lookup(
cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()));
auto *FD = CapturedStmtInfo->lookup(OrigVD);
LValue Base = MakeNaturalAlignAddrLValue(
CapturedStmtInfo->getContextValue(),
getContext().getTagDeclType(FD->getParent()));
auto OriginalAddr = EmitLValueForField(Base, FD);
auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
auto Emission = EmitAutoVarAlloca(*VD);
// Emit initialization of aggregate firstprivate vars.
EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
VD->getInit(), (*IRef)->getType(), VDInit);
EmitAutoVarCleanups(Emission);
IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
auto Emission = EmitAutoVarAlloca(*VD);
// Emit initialization of aggregate firstprivate vars.
EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
VD->getInit(), (*IRef)->getType(), VDInit);
EmitAutoVarCleanups(Emission);
return Emission.getAllocatedAddress();
});
} else
// Emit VarDecl with copy init.
EmitDecl(*VD);
OuterDeclMap[cast<DeclRefExpr>(*IRef)->getDecl()] = GetAddrOfLocalVar(VD);
IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
// Emit private VarDecl with copy init.
EmitDecl(*VD);
return GetAddrOfLocalVar(VD);
});
assert(IsRegistered && "counter already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
++IRef, ++InitsRef;
}
}
@ -239,7 +248,7 @@ static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM,
unsigned Alignment = ClauseAlignment;
if (Alignment == 0) {
// OpenMP [2.8.1, Description]
// If no optional parameter isspecified, implementation-defined default
// If no optional parameter is specified, implementation-defined default
// alignments for SIMD instructions on the target platforms are assumed.
Alignment = CGM.getTargetCodeGenInfo().getOpenMPSimdDefaultAlignment(
E->getType());
@ -253,6 +262,24 @@ static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM,
}
}
static void EmitPrivateLoopCounters(CodeGenFunction &CGF,
CodeGenFunction::OMPPrivateScope &LoopScope,
ArrayRef<Expr *> Counters) {
for (auto *E : Counters) {
auto VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
bool IsRegistered = LoopScope.addPrivate(VD, [&]() -> llvm::Value * {
// Emit var without initialization.
auto VarEmission = CGF.EmitAutoVarAlloca(*VD);
CGF.EmitAutoVarCleanups(VarEmission);
return VarEmission.getAllocatedAddress();
});
assert(IsRegistered && "counter already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
}
(void)LoopScope.Privatize();
}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
// Pragma 'simd' code depends on presence of 'lastprivate'.
// If present, we have to separate last iteration of the loop:
@ -330,7 +357,7 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
// Emit 'then' code.
{
OMPPrivateScope LoopScope(*this);
LoopScope.addPrivates(S.counters());
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
EmitOMPInnerLoop(S, LoopScope, /* SeparateIter */ true);
EmitOMPLoopBody(S, /* SeparateIter */ true);
}
@ -341,7 +368,7 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
} else {
{
OMPPrivateScope LoopScope(*this);
LoopScope.addPrivates(S.counters());
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
EmitOMPInnerLoop(S, LoopScope);
}
EmitOMPSimdFinal(S);

View File

@ -586,6 +586,68 @@ public:
void rescopeLabels();
};
/// \brief The scope used to remap some variables as private in the OpenMP
/// loop body (or other captured region emitted without outlining), and to
/// restore old vars back on exit.
class OMPPrivateScope : public RunCleanupsScope {
typedef llvm::DenseMap<const VarDecl *, llvm::Value *> VarDeclMapTy;
VarDeclMapTy SavedLocals;
VarDeclMapTy SavedPrivates;
private:
OMPPrivateScope(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
void operator=(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
public:
/// \brief Enter a new OpenMP private scope.
explicit OMPPrivateScope(CodeGenFunction &CGF) : RunCleanupsScope(CGF) {}
/// \brief Registers \a LocalVD variable as a private and apply \a
/// PrivateGen function for it to generate corresponding private variable.
/// \a PrivateGen returns an address of the generated private variable.
/// \return true if the variable is registered as private, false if it has
/// been privatized already.
bool
addPrivate(const VarDecl *LocalVD,
const std::function<llvm::Value *()> &PrivateGen) {
assert(PerformCleanup && "adding private to dead scope");
assert(LocalVD->isLocalVarDecl() && "privatizing non-local variable");
if (SavedLocals.count(LocalVD) > 0) return false;
SavedLocals[LocalVD] = CGF.LocalDeclMap.lookup(LocalVD);
CGF.LocalDeclMap.erase(LocalVD);
SavedPrivates[LocalVD] = PrivateGen();
CGF.LocalDeclMap[LocalVD] = SavedLocals[LocalVD];
return true;
}
/// \brief Privatizes local variables previously registered as private.
/// Registration is separate from the actual privatization to allow
/// initializers use values of the original variables, not the private one.
/// This is important, for example, if the private variable is a class
/// variable initialized by a constructor that references other private
/// variables. But at initialization original variables must be used, not
/// private copies.
/// \return true if at least one variable was privatized, false otherwise.
bool Privatize() {
for (auto VDPair : SavedPrivates) {
CGF.LocalDeclMap[VDPair.first] = VDPair.second;
}
SavedPrivates.clear();
return !SavedLocals.empty();
}
void ForceCleanup() {
RunCleanupsScope::ForceCleanup();
// Remap vars back to the original values.
for (auto I : SavedLocals) {
CGF.LocalDeclMap[I.first] = I.second;
}
SavedLocals.clear();
}
/// \brief Exit scope - all the mapped variables are restored.
~OMPPrivateScope() { ForceCleanup(); }
};
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added.
@ -867,48 +929,6 @@ private:
};
SmallVector<BreakContinue, 8> BreakContinueStack;
/// \brief The scope used to remap some variables as private in the OpenMP
/// loop body (or other captured region emitted without outlining), and to
/// restore old vars back on exit.
class OMPPrivateScope : public RunCleanupsScope {
DeclMapTy SavedLocals;
private:
OMPPrivateScope(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
void operator=(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
public:
/// \brief Enter a new OpenMP private scope.
explicit OMPPrivateScope(CodeGenFunction &CGF) : RunCleanupsScope(CGF) {}
/// \brief Add and remap private variables (without initialization).
/// \param Vars - a range of DeclRefExprs for the private variables.
template <class IT> void addPrivates(IT Vars) {
assert(PerformCleanup && "adding private to dead scope");
for (auto E : Vars) {
auto D = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
assert(!SavedLocals.lookup(D) && "remapping a var twice");
SavedLocals[D] = CGF.LocalDeclMap.lookup(D);
CGF.LocalDeclMap.erase(D);
// Emit var without initialization.
auto VarEmission = CGF.EmitAutoVarAlloca(*D);
CGF.EmitAutoVarCleanups(VarEmission);
}
}
void ForceCleanup() {
RunCleanupsScope::ForceCleanup();
// Remap vars back to the original values.
for (auto I : SavedLocals) {
CGF.LocalDeclMap[I.first] = I.second;
}
SavedLocals.clear();
}
/// \brief Exit scope - all the mapped variables are restored.
~OMPPrivateScope() { ForceCleanup(); }
};
CodeGenPGO PGO;
public:
@ -1973,12 +1993,11 @@ public:
llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
typedef llvm::DenseMap<const Decl *, llvm::Value *> OuterDeclMapTy;
void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
const Expr *AssignExpr, QualType Type,
const VarDecl *VDInit);
void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
OuterDeclMapTy &OuterDeclMap);
OMPPrivateScope &PrivateScope);
void EmitOMPParallelDirective(const OMPParallelDirective &S);
void EmitOMPSimdDirective(const OMPSimdDirective &S);