Skip to content

Commit

Permalink
[OPENMP] Codegen for 'omp master' directive
Browse files Browse the repository at this point in the history
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)) {
    <Associated structured block>;
      __kmpc_end_master(log, gtid);
}

Differential Revision: http://reviews.llvm.org/D6473

llvm-svn: 223342
  • Loading branch information
alexey-bataev committed Dec 4, 2014
1 parent 0152732 commit 8d69065
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 3 deletions.
67 changes: 67 additions & 0 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Expand Up @@ -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;
}
Expand Down Expand Up @@ -631,6 +647,57 @@ void CGOpenMPRuntime::EmitOMPCriticalRegion(
CGF.EmitRuntimeCall(RTLFn, Args);
}

static void EmitOMPIfStmt(CodeGenFunction &CGF, llvm::Value *IfCond,
const std::function<void()> &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<void()> &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) {
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/CodeGen/CGOpenMPRuntime.h
Expand Up @@ -96,7 +96,11 @@ class CGOpenMPRuntime {
// 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;
Expand Down Expand Up @@ -287,6 +291,13 @@ class CGOpenMPRuntime {
const std::function<void()> &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<void()> &MasterOpGen,
SourceLocation Loc);

/// \brief Emits a barrier for OpenMP threads.
/// \param Flags Flags for the barrier.
///
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Expand Up @@ -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<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
EnsureInsertPoint();
}, S.getLocStart());
}

void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
Expand Down
46 changes: 46 additions & 0 deletions clang/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

0 comments on commit 8d69065

Please sign in to comment.