From: Alexey Bataev Date: Thu, 4 Dec 2014 07:23:53 +0000 (+0000) Subject: [OPENMP] Codegen for 'omp master' directive X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=528f83c9a59bd64e608db95b26570a8aea3c5ec2;p=clang [OPENMP] Codegen for 'omp master' directive Patch adds 2 library functions to OpenMPRuntime class - int32 kmpc_master(ident_t *, int32 gtid) and void kmpc_end_master(ident_t *, int32 gtid); For 'omp master' directive the next code is generated: if (__kmpc_master(loc, gtid)) { ; __kmpc_end_master(log, gtid); } Differential Revision: http://reviews.llvm.org/D6473 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@223342 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index cc4d7e2c9b..65dd4d6559 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -371,6 +371,22 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_flush"); break; } + case OMPRTL__kmpc_master: { + // Build kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid); + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_master"); + break; + } + case OMPRTL__kmpc_end_master: { + // Build void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid); + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_master"); + break; + } } return RTLFn; } @@ -631,6 +647,57 @@ void CGOpenMPRuntime::EmitOMPCriticalRegion( CGF.EmitRuntimeCall(RTLFn, Args); } +static void EmitOMPIfStmt(CodeGenFunction &CGF, llvm::Value *IfCond, + const std::function &BodyOpGen) { + llvm::Value *CallBool = CGF.EmitScalarConversion( + IfCond, + CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true), + CGF.getContext().BoolTy); + + auto *ThenBlock = CGF.createBasicBlock("omp_if.then"); + auto *ContBlock = CGF.createBasicBlock("omp_if.end"); + // Generate the branch (If-stmt) + CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock); + CGF.EmitBlock(ThenBlock); + BodyOpGen(); + // Emit the rest of bblocks/branches + CGF.EmitBranch(ContBlock); + CGF.EmitBlock(ContBlock, true); +} + +void CGOpenMPRuntime::EmitOMPMasterRegion( + CodeGenFunction &CGF, const std::function &MasterOpGen, + SourceLocation Loc) { + // if(__kmpc_master(ident_t *, gtid)) { + // MasterOpGen(); + // __kmpc_end_master(ident_t *, gtid); + // } + // Prepare arguments and build a call to __kmpc_master + llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), + GetOpenMPThreadID(CGF, Loc)}; + auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_master); + auto *IsMaster = CGF.EmitRuntimeCall(RTLFn, Args); + EmitOMPIfStmt(CGF, IsMaster, [&]() -> void { + MasterOpGen(); + // Build a call to __kmpc_end_master. + // OpenMP [1.2.2 OpenMP Language Terminology] + // For C/C++, an executable statement, possibly compound, with a single + // entry at the top and a single exit at the bottom, or an OpenMP construct. + // * Access to the structured block must not be the result of a branch. + // * The point of exit cannot be a branch out of the structured block. + // * The point of entry must not be a call to setjmp(). + // * longjmp() and throw() must not violate the entry/exit criteria. + // * An expression statement, iteration statement, selection statement, or + // try block is considered to be a structured block if the corresponding + // compound statement obtained by enclosing it in { and } would be a + // structured block. + // It is analyzed in Sema, so we can just call __kmpc_end_master() on + // fallthrough rather than pushing a normal cleanup for it. + RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_end_master); + CGF.EmitRuntimeCall(RTLFn, Args); + }); +} + void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) { diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h index d259726731..65348c9c3a 100644 --- a/lib/CodeGen/CGOpenMPRuntime.h +++ b/lib/CodeGen/CGOpenMPRuntime.h @@ -96,7 +96,11 @@ private: // kmp_int32 num_threads); OMPRTL__kmpc_push_num_threads, // Call to void __kmpc_flush(ident_t *loc, ...); - OMPRTL__kmpc_flush + OMPRTL__kmpc_flush, + // Call to kmp_int32 __kmpc_master(ident_t *, kmp_int32 global_tid); + OMPRTL__kmpc_master, + // Call to void __kmpc_end_master(ident_t *, kmp_int32 global_tid); + OMPRTL__kmpc_end_master, }; CodeGenModule &CGM; @@ -287,6 +291,13 @@ public: const std::function &CriticalOpGen, SourceLocation Loc); + /// \brief Emits a master region. + /// \param MasterOpGen Generator for the statement associated with the given + /// master region. + virtual void EmitOMPMasterRegion(CodeGenFunction &CGF, + const std::function &MasterOpGen, + SourceLocation Loc); + /// \brief Emits a barrier for OpenMP threads. /// \param Flags Flags for the barrier. /// diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 79af4bc00d..90776e5a70 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -490,8 +490,13 @@ void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &) { llvm_unreachable("CodeGen for 'omp single' is not supported yet."); } -void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &) { - llvm_unreachable("CodeGen for 'omp master' is not supported yet."); +void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { + CGM.getOpenMPRuntime().EmitOMPMasterRegion( + *this, [&]() -> void { + RunCleanupsScope Scope(*this); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EnsureInsertPoint(); + }, S.getLocStart()); } void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { diff --git a/test/OpenMP/master_codegen.cpp b/test/OpenMP/master_codegen.cpp new file mode 100644 index 0000000000..d354bae2d7 --- /dev/null +++ b/test/OpenMP/master_codegen.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* } + +// CHECK: define void [[FOO:@.+]]() + +void foo() {} + +// CHECK-LABEL: @main +int main() { + // CHECK: [[A_ADDR:%.+]] = alloca i8 + char a; + +// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]]) +// CHECK: [[RES:%.+]] = call i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]]) +// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]] +// CHECK: [[THEN]] +// CHECK-NEXT: store i8 2, i8* [[A_ADDR]] +// CHECK-NEXT: call void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]]) +// CHECK-NEXT: br label {{%?}}[[EXIT]] +// CHECK: [[EXIT]] +#pragma omp master + a = 2; +// CHECK: [[RES:%.+]] = call i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]]) +// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]] +// CHECK: [[THEN]] +// CHECK-NEXT: call void [[FOO]]() +// CHECK-NEXT: call void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]]) +// CHECK-NEXT: br label {{%?}}[[EXIT]] +// CHECK: [[EXIT]] +#pragma omp master + foo(); +// CHECK-NOT: call i32 @__kmpc_master +// CHECK-NOT: call void @__kmpc_end_master + return a; +} + +#endif