diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2016-11-28 17:55:42 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2016-11-28 17:55:42 +0000 |
commit | dd822f5bd55340546dbdb928d926e392a99f43ac (patch) | |
tree | cc6d8d7d6781748c017033303932149975a282b2 | |
parent | 88f283a13932ed6cf275d457311501bc0d686cbd (diff) | |
download | llvm-dd822f5bd55340546dbdb928d926e392a99f43ac.zip llvm-dd822f5bd55340546dbdb928d926e392a99f43ac.tar.gz llvm-dd822f5bd55340546dbdb928d926e392a99f43ac.tar.bz2 |
Merging r287227:
------------------------------------------------------------------------
r287227 | abataev | 2016-11-17 15:12:05 +0000 (Thu, 17 Nov 2016) | 4 lines
[OPENMP] Fixed codegen for 'omp cancel' construct.
If 'omp cancel' construct is used in a worksharing construct it may
cause hanging of the software in case if reduction clause is used. Patch fixes this problem by avoiding extra reduction processing for branches that were canceled.
------------------------------------------------------------------------
llvm-svn: 288048
-rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 50 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 97 | ||||
-rw-r--r-- | clang/test/OpenMP/cancel_codegen.cpp | 2 |
3 files changed, 98 insertions, 51 deletions
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 8937685..d214340 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1767,17 +1767,11 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic, EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&CodeGen = [DynamicOrOrdered, ELoc](CodeGenFunction &CGF) { + auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) { if (!DynamicOrOrdered) - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - CodeGen(*this); - - OpenMPDirectiveKind DKind = S.getDirectiveKind(); - if (DKind == OMPD_for || DKind == OMPD_parallel_for || - DKind == OMPD_distribute_parallel_for) - OMPCancelStack.back().CodeGen = CodeGen; + OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } void CodeGenFunction::EmitOMPForOuterLoop( @@ -1889,11 +1883,12 @@ void CodeGenFunction::EmitOMPDistributeOuterLoop( void CodeGenFunction::EmitOMPDistributeParallelForDirective( const OMPDistributeParallelForDirective &S) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - OMPCancelStackRAII CancelRegion(*this); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_distribute_parallel_for, [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); + OMPCancelStackRAII CancelRegion(CGF, OMPD_distribute_parallel_for, + /*HasCancel=*/false); CGF.EmitStmt( cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); }); @@ -2082,15 +2077,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&CodeGen = [ELoc](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + auto &&CodeGen = [&S](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - CodeGen(*this); - OpenMPDirectiveKind DKind = S.getDirectiveKind(); - if (DKind == OMPD_for || DKind == OMPD_parallel_for || - DKind == OMPD_distribute_parallel_for) - OMPCancelStack.back().CodeGen = CodeGen; + OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } else { const bool IsMonotonic = Ordered || ScheduleKind.Schedule == OMPC_SCHEDULE_static || @@ -2140,11 +2130,11 @@ void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { bool HasLastprivates = false; auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { + OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel()); HasLastprivates = CGF.EmitOMPWorksharingLoop(S); }; { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - OMPCancelStackRAII CancelRegion(*this); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen, S.hasCancel()); } @@ -2187,7 +2177,6 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { bool HasLastprivates = false; auto &&CodeGen = [&S, Stmt, CS, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { - OMPCancelStackRAII CancelRegion(CGF); auto &C = CGF.CGM.getContext(); auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); // Emit helper vars inits. @@ -2282,12 +2271,10 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen, [](CodeGenFunction &) {}); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&FinalCodeGen = [ELoc](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + auto &&CodeGen = [&S](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - FinalCodeGen(CGF); - CGF.OMPCancelStack.back().CodeGen = FinalCodeGen; + CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen); CGF.EmitOMPReductionClauseFinal(S); // Emit post-update of the reduction variables if IsLastIter != 0. emitPostUpdateForReductionClause( @@ -2309,6 +2296,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { HasCancel = OSD->hasCancel(); else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S)) HasCancel = OPSD->hasCancel(); + OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen, HasCancel); // Emit barrier for lastprivates only if 'sections' directive has 'nowait' @@ -2412,7 +2400,7 @@ void CodeGenFunction::EmitOMPParallelForDirective( // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'for' directive. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPCancelStackRAII CancelRegion(CGF); + OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel()); CGF.EmitOMPWorksharingLoop(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen); @@ -3412,14 +3400,14 @@ void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { CodeGenFunction::JumpDest CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) { - if (Kind == OMPD_parallel || Kind == OMPD_task) + if (Kind == OMPD_parallel || Kind == OMPD_task || + Kind == OMPD_target_parallel) return ReturnBlock; assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections || Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for || - Kind == OMPD_distribute_parallel_for); - if (!OMPCancelStack.back().ExitBlock.isValid()) - OMPCancelStack.back().ExitBlock = getJumpDestInCurrentScope("cancel.exit"); - return OMPCancelStack.back().ExitBlock; + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_target_parallel_for); + return OMPCancelStack.getExitBlock(); } // Generate the instructions for '#pragma omp target data' directive. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f61ba69..fb19a26 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -965,33 +965,92 @@ private: }; SmallVector<BreakContinue, 8> BreakContinueStack; - /// Data for exit block for proper support of OpenMP cancellation constructs. - struct OMPCancel { - JumpDest ExitBlock; - llvm::function_ref<void(CodeGenFunction &CGF)> CodeGen; - OMPCancel() : CodeGen([](CodeGenFunction &CGF) {}) {} + /// Handles cancellation exit points in OpenMP-related constructs. + class OpenMPCancelExitStack { + /// Tracks cancellation exit point and join point for cancel-related exit + /// and normal exit. + struct CancelExit { + CancelExit() = default; + CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock, + JumpDest ContBlock) + : Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {} + OpenMPDirectiveKind Kind = OMPD_unknown; + /// true if the exit block has been emitted already by the special + /// emitExit() call, false if the default codegen is used. + bool HasBeenEmitted = false; + JumpDest ExitBlock; + JumpDest ContBlock; + }; + + SmallVector<CancelExit, 8> Stack; + + public: + OpenMPCancelExitStack() : Stack(1) {} + ~OpenMPCancelExitStack() = default; + /// Fetches the exit block for the current OpenMP construct. + JumpDest getExitBlock() const { return Stack.back().ExitBlock; } + /// Emits exit block with special codegen procedure specific for the related + /// OpenMP construct + emits code for normal construct cleanup. + void emitExit(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, + const llvm::function_ref<void(CodeGenFunction &)> &CodeGen) { + if (Stack.back().Kind == Kind && getExitBlock().isValid()) { + assert(CGF.getOMPCancelDestination(Kind).isValid()); + assert(CGF.HaveInsertPoint()); + assert(!Stack.back().HasBeenEmitted); + auto IP = CGF.Builder.saveAndClearIP(); + CGF.EmitBlock(Stack.back().ExitBlock.getBlock()); + CodeGen(CGF); + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + CGF.Builder.restoreIP(IP); + Stack.back().HasBeenEmitted = true; + } + CodeGen(CGF); + } + /// Enter the cancel supporting \a Kind construct. + /// \param Kind OpenMP directive that supports cancel constructs. + /// \param HasCancel true, if the construct has inner cancel directive, + /// false otherwise. + void enter(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, bool HasCancel) { + Stack.push_back({Kind, + HasCancel ? CGF.getJumpDestInCurrentScope("cancel.exit") + : JumpDest(), + HasCancel ? CGF.getJumpDestInCurrentScope("cancel.cont") + : JumpDest()}); + } + /// Emits default exit point for the cancel construct (if the special one + /// has not be used) + join point for cancel/normal exits. + void exit(CodeGenFunction &CGF) { + if (getExitBlock().isValid()) { + assert(CGF.getOMPCancelDestination(Stack.back().Kind).isValid()); + bool HaveIP = CGF.HaveInsertPoint(); + if (!Stack.back().HasBeenEmitted) { + if (HaveIP) + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + CGF.EmitBlock(Stack.back().ExitBlock.getBlock()); + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + } + CGF.EmitBlock(Stack.back().ContBlock.getBlock()); + if (!HaveIP) { + CGF.Builder.CreateUnreachable(); + CGF.Builder.ClearInsertionPoint(); + } + } + Stack.pop_back(); + } }; - SmallVector<OMPCancel, 8> OMPCancelStack; + OpenMPCancelExitStack OMPCancelStack; /// Controls insertion of cancellation exit blocks in worksharing constructs. class OMPCancelStackRAII { CodeGenFunction &CGF; public: - OMPCancelStackRAII(CodeGenFunction &CGF) : CGF(CGF) { - CGF.OMPCancelStack.push_back({}); - } - ~OMPCancelStackRAII() { - if (CGF.HaveInsertPoint() && - CGF.OMPCancelStack.back().ExitBlock.isValid()) { - auto CJD = CGF.getJumpDestInCurrentScope("cancel.cont"); - CGF.EmitBranchThroughCleanup(CJD); - CGF.EmitBlock(CGF.OMPCancelStack.back().ExitBlock.getBlock()); - CGF.OMPCancelStack.back().CodeGen(CGF); - CGF.EmitBranchThroughCleanup(CJD); - CGF.EmitBlock(CJD.getBlock()); - } + OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, + bool HasCancel) + : CGF(CGF) { + CGF.OMPCancelStack.enter(CGF, Kind, HasCancel); } + ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); } }; CodeGenPGO PGO; diff --git a/clang/test/OpenMP/cancel_codegen.cpp b/clang/test/OpenMP/cancel_codegen.cpp index 059a8d3..a09214c 100644 --- a/clang/test/OpenMP/cancel_codegen.cpp +++ b/clang/test/OpenMP/cancel_codegen.cpp @@ -92,7 +92,7 @@ for (int i = 0; i < argc; ++i) { } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( int r = 0; -#pragma omp parallel for reduction(+:r) +#pragma omp parallel for reduction(+: r) for (int i = 0; i < argc; ++i) { #pragma omp cancel for r += i; |