From: Alexey Bataev Date: Fri, 10 Oct 2014 09:48:26 +0000 (+0000) Subject: Code improvements in OpenMP CodeGen. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=71286955698503348bcdd437c76eb2b2c0c28033;p=clang 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219486 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index c439833cfe..bef723f5ae 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -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::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) diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 8d7d08fca2..1b3e786b30 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -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(cast(IInit)->getDecl()); + auto *OrigVD = cast(cast(*IRef)->getDecl()); + auto *VD = cast(cast(IInit)->getDecl()); + bool IsRegistered; if (*InitsRef != nullptr) { // Emit VarDecl with copy init for arrays. - auto *FD = CapturedStmtInfo->lookup( - cast(cast(*IRef)->getDecl())); + auto *FD = CapturedStmtInfo->lookup(OrigVD); LValue Base = MakeNaturalAlignAddrLValue( CapturedStmtInfo->getContextValue(), getContext().getTagDeclType(FD->getParent())); auto OriginalAddr = EmitLValueForField(Base, FD); auto VDInit = cast(cast(*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(*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 Counters) { + for (auto *E : Counters) { + auto VD = cast(cast(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); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 92a743160e..d8d715db8b 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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 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 &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 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 void addPrivates(IT Vars) { - assert(PerformCleanup && "adding private to dead scope"); - for (auto E : Vars) { - auto D = cast(cast(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 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);