From 0f34da12e42311e943186622412f64d0a93ccf2a Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Thu, 2 Jul 2015 04:17:07 +0000 Subject: [PATCH] [OPENMP 4.0] Codegen for 'cancellation point' directive. The next code is generated for this construct: ``` if (__kmpc_cancellationpoint(ident_t *loc, kmp_int32 global_tid, kmp_int32 cncl_kind) != 0) ; ``` llvm-svn: 241239 --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 53 +++++++++++++++++ clang/lib/CodeGen/CGOpenMPRuntime.h | 11 ++++ clang/lib/CodeGen/CGStmtOpenMP.cpp | 76 +++++++++++++----------- clang/lib/CodeGen/CodeGenFunction.h | 4 +- clang/test/OpenMP/cancellation_point_codegen.cpp | 70 ++++++++++++++++++++++ 5 files changed, 178 insertions(+), 36 deletions(-) create mode 100644 clang/test/OpenMP/cancellation_point_codegen.cpp diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index f9553a2..5fe81c2 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -806,6 +806,15 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_wait_deps"); break; } + case OMPRTL__kmpc_cancellationpoint: { + // Build kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 cncl_kind) + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancellationpoint"); + break; + } } return RTLFn; } @@ -2677,3 +2686,47 @@ void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF, CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr); } +void CGOpenMPRuntime::emitCancellationPointCall( + CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion) { + // Build call kmp_int32 OMPRTL__kmpc_cancellationpoint(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 cncl_kind); + enum { + CancelNoreq = 0, + CancelParallel = 1, + CancelLoop = 2, + CancelSections = 3, + CancelTaskgroup = 4 + } CancelKind = CancelNoreq; + if (CancelRegion == OMPD_parallel) + CancelKind = CancelParallel; + else if (CancelRegion == OMPD_for) + CancelKind = CancelLoop; + else if (CancelRegion == OMPD_sections) + CancelKind = CancelSections; + else { + assert(CancelRegion == OMPD_taskgroup); + CancelKind = CancelTaskgroup; + } + llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(CancelKind)}; + // Ignore return result until untied tasks are supported. + auto *Result = CGF.EmitRuntimeCall( + createRuntimeFunction(OMPRTL__kmpc_cancellationpoint), Args); + // if (__kmpc_cancellationpoint()) + // exit from construct; + auto *ExitBB = CGF.createBasicBlock(".cancel.exit"); + auto *ContBB = CGF.createBasicBlock(".cancel.continue"); + auto *Cmp = CGF.Builder.CreateIsNotNull(Result); + CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB); + CGF.EmitBlock(ExitBB); + if (CancelRegion == OMPD_parallel || CancelRegion == OMPD_taskgroup) { + CGF.EmitBranchThroughCleanup(CGF.ReturnBlock); + } else { + assert(CancelRegion == OMPD_for || CancelRegion == OMPD_sections); + BreakStmt PseudoBrStmt(Loc); + CGF.EmitBreakStmt(PseudoBrStmt); + } + CGF.EmitBlock(ContBB, /*IsFinished=*/true); +} + diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 27a0a32..b34ef42 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -146,6 +146,9 @@ private: // gtid, kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); OMPRTL__kmpc_omp_wait_deps, + // Call to kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 cncl_kind); + OMPRTL__kmpc_cancellationpoint, }; /// \brief Values for bit flags used in the ident_t to describe the fields. @@ -676,6 +679,14 @@ public: /// \brief Emit code for 'taskwait' directive. virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc); + + /// \brief Emit code for 'cancellation point' construct. + /// \param CancelRegion Region kind for which the cancellation point must be + /// emitted. + /// + virtual void emitCancellationPointCall(CodeGenFunction &CGF, + SourceLocation Loc, + OpenMPDirectiveKind CancelRegion); }; } // namespace CodeGen diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 8666b46..655fae1 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -505,7 +505,8 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { emitCommonOMPParallelDirective(*this, S, CodeGen); } -void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D) { +void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, + JumpDest LoopExit) { RunCleanupsScope BodyScope(*this); // Update counters values on current iteration. for (auto I : D.updates()) { @@ -521,7 +522,7 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D) { // On a continue in the body, jump to the end. auto Continue = getJumpDestInCurrentScope("omp.body.continue"); - BreakContinueStack.push_back(BreakContinue(JumpDest(), Continue)); + BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); // Emit loop body. EmitStmt(D.getBody()); // The end (updates/cleanups). @@ -827,10 +828,10 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { CGF.EmitOMPReductionClauseInit(S, LoopScope); HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); - CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), - S.getCond(), S.getInc(), + CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), + S.getInc(), [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S); + CGF.EmitOMPLoopBody(S, JumpDest()); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); @@ -979,19 +980,17 @@ void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind, } SourceLocation Loc = S.getLocStart(); - EmitOMPInnerLoop( - S, LoopScope.requiresCleanups(), S.getCond(), - S.getInc(), - [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S); - CGF.EmitStopPoint(&S); - }, - [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) { - if (Ordered) { - CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd( - CGF, Loc, IVSize, IVSigned); - } - }); + EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), + [&S, LoopExit](CodeGenFunction &CGF) { + CGF.EmitOMPLoopBody(S, LoopExit); + CGF.EmitStopPoint(&S); + }, + [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) { + if (Ordered) { + CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd( + CGF, Loc, IVSize, IVSigned); + } + }); EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); @@ -1140,6 +1139,7 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { RT.emitForInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); + auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB; @@ -1147,11 +1147,12 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { // while (idx <= UB) { BODY; ++idx; } EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), - [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S); + [&S, LoopExit](CodeGenFunction &CGF) { + CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); + EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. RT.emitForStaticFinish(*this, S.getLocStart()); } else { @@ -1216,8 +1217,8 @@ static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty, return LVal; } -static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF, - const OMPExecutableDirective &S) { +OpenMPDirectiveKind +CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { auto *Stmt = cast(S.getAssociatedStmt())->getCapturedStmt(); auto *CS = dyn_cast(Stmt); if (CS && CS->size() > 1) { @@ -1313,15 +1314,15 @@ static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF, CGF.EmitLoadOfScalar(IL, S.getLocStart()))); }; - CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, CodeGen); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, CodeGen); // Emit barrier for lastprivates only if 'sections' directive has 'nowait' // clause. Otherwise the barrier will be generated by the codegen for the // directive. if (HasLastprivates && S.getSingleClause(OMPC_nowait)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. - CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(), - OMPD_unknown); + CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), + OMPD_unknown); } return OMPD_sections; } @@ -1341,12 +1342,17 @@ static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF, CGF.EmitOMPPrivateClause(S, SingleScope); (void)SingleScope.Privatize(); + CGF.BreakContinueStack.push_back( + BreakContinue(CGF.getJumpDestInCurrentScope( + CGF.createBasicBlock("omp.sections.exit")), + JumpDest())); CGF.EmitStmt(Stmt); - CGF.EnsureInsertPoint(); + CGF.EmitBlock(CGF.BreakContinueStack.back().BreakBlock.getBlock()); + CGF.BreakContinueStack.pop_back(); }; - CGF.CGM.getOpenMPRuntime().emitSingleRegion(CGF, CodeGen, S.getLocStart(), - llvm::None, llvm::None, - llvm::None, llvm::None); + CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(), + llvm::None, llvm::None, llvm::None, + llvm::None); // Emit barrier for firstprivates, lastprivates or reductions only if // 'sections' directive has 'nowait' clause. Otherwise the barrier will be // generated by the codegen for the directive. @@ -1354,15 +1360,15 @@ static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF, S.getSingleClause(OMPC_nowait)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. - CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(), - OMPD_unknown); + CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), + OMPD_unknown); } return OMPD_single; } void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); - OpenMPDirectiveKind EmittedAs = emitSections(*this, S); + OpenMPDirectiveKind EmittedAs = EmitSections(S); // Emit an implicit barrier at the end. if (!S.getSingleClause(OMPC_nowait)) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), EmittedAs); @@ -1481,7 +1487,7 @@ void CodeGenFunction::EmitOMPParallelSectionsDirective( // directives: 'parallel' with 'sections' directive. LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { - (void)emitSections(CGF, S); + (void)CGF.EmitSections(S); // Emit implicit barrier at the end of parallel region. CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(), OMPD_parallel); @@ -2102,7 +2108,7 @@ void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &) { void CodeGenFunction::EmitOMPCancellationPointDirective( const OMPCancellationPointDirective &S) { - llvm_unreachable( - "CodeGen for 'omp cancellation point' is not supported yet."); + CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getLocStart(), + S.getCancelRegion()); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 2ba893e..e359876 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2236,7 +2236,7 @@ public: private: /// Helpers for the OpenMP loop directives. - void EmitOMPLoopBody(const OMPLoopDirective &D); + void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit); void EmitOMPSimdInit(const OMPLoopDirective &D); void EmitOMPSimdFinal(const OMPLoopDirective &D); /// \brief Emit code for the worksharing loop-based directive. @@ -2248,6 +2248,8 @@ private: OMPPrivateScope &LoopScope, bool Ordered, llvm::Value *LB, llvm::Value *UB, llvm::Value *ST, llvm::Value *IL, llvm::Value *Chunk); + /// \brief Emit code for sections directive. + OpenMPDirectiveKind EmitSections(const OMPExecutableDirective &S); public: diff --git a/clang/test/OpenMP/cancellation_point_codegen.cpp b/clang/test/OpenMP/cancellation_point_codegen.cpp new file mode 100644 index 0000000..9ed1203 --- /dev/null +++ b/clang/test/OpenMP/cancellation_point_codegen.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +int main (int argc, char **argv) { +// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( +#pragma omp parallel +{ +#pragma omp cancellation point parallel + argv[0][0] = argc; +} +// CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( +#pragma omp sections +{ +#pragma omp cancellation point sections +} +// CHECK: call i32 @__kmpc_single( +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] +// CHECK: [[EXIT]] +// CHECK: br label +// CHECK: [[CONTINUE]] +// CHECK: br label +// CHECK: call void @__kmpc_end_single( +#pragma omp for +for (int i = 0; i < argc; ++i) { +#pragma omp cancellation point for +} +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 2) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] +// CHECK: [[EXIT]] +// CHECK: br label +// CHECK: [[CONTINUE]] +// CHECK: br label +// CHECK: call void @__kmpc_for_static_fini( +#pragma omp task +{ +#pragma omp cancellation point taskgroup +} +// CHECK: call i8* @__kmpc_omp_task_alloc( +// CHECK: call i32 @__kmpc_omp_task( + return argc; +} + +// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}, +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], +// CHECK: [[EXIT]] +// CHECK: br label %[[RETURN:.+]] +// CHECK: [[RETURN]] +// CHECK: ret void + +// CHECK: define internal i32 @{{[^(]+}}(i32 +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 4) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], +// CHECK: [[EXIT]] +// CHECK: br label %[[RETURN:.+]] +// CHECK: [[RETURN]] +// CHECK: ret i32 0 + +#endif -- 2.7.4