forked from OSchip/llvm-project
[OPENMP] Initial codegen for 'single' directive.
This patch emits the following code for the single directive: #pragma omp single <body> <----> if(__kmpc_single(...)) { <body> __kmpc_end_single(...); } Differential Revision: http://reviews.llvm.org/D7045 llvm-svn: 228275
This commit is contained in:
parent
520449d55e
commit
6956e2e683
|
@ -484,6 +484,22 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
|
|||
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_taskyield");
|
||||
break;
|
||||
}
|
||||
case OMPRTL__kmpc_single: {
|
||||
// Build kmp_int32 __kmpc_single(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_single");
|
||||
break;
|
||||
}
|
||||
case OMPRTL__kmpc_end_single: {
|
||||
// Build void __kmpc_end_single(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_single");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return RTLFn;
|
||||
}
|
||||
|
@ -805,6 +821,39 @@ void CGOpenMPRuntime::EmitOMPTaskyieldCall(CodeGenFunction &CGF,
|
|||
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::EmitOMPSingleRegion(
|
||||
CodeGenFunction &CGF, const std::function<void()> &SingleOpGen,
|
||||
SourceLocation Loc) {
|
||||
// if(__kmpc_single(ident_t *, gtid)) {
|
||||
// SingleOpGen();
|
||||
// __kmpc_end_single(ident_t *, gtid);
|
||||
// }
|
||||
// Prepare arguments and build a call to __kmpc_single
|
||||
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
|
||||
GetOpenMPThreadID(CGF, Loc)};
|
||||
auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_single);
|
||||
auto *IsSingle = CGF.EmitRuntimeCall(RTLFn, Args);
|
||||
EmitOMPIfStmt(CGF, IsSingle, [&]() -> void {
|
||||
SingleOpGen();
|
||||
// Build a call to __kmpc_end_single.
|
||||
// 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_single() on
|
||||
// fallthrough rather than pushing a normal cleanup for it.
|
||||
RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_end_single);
|
||||
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||
});
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF,
|
||||
SourceLocation Loc, bool IsExplicit) {
|
||||
// Build call __kmpc_cancel_barrier(loc, thread_id);
|
||||
|
|
|
@ -91,6 +91,10 @@ private:
|
|||
// Call to kmp_int32 __kmpc_omp_taskyield(ident_t *, kmp_int32 global_tid,
|
||||
// int end_part);
|
||||
OMPRTL__kmpc_omp_taskyield,
|
||||
// Call to kmp_int32 __kmpc_single(ident_t *, kmp_int32 global_tid);
|
||||
OMPRTL__kmpc_single,
|
||||
// Call to void __kmpc_end_single(ident_t *, kmp_int32 global_tid);
|
||||
OMPRTL__kmpc_end_single,
|
||||
};
|
||||
|
||||
/// \brief Values for bit flags used in the ident_t to describe the fields.
|
||||
|
@ -312,6 +316,13 @@ public:
|
|||
/// \brief Emits code for a taskyield directive.
|
||||
virtual void EmitOMPTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc);
|
||||
|
||||
/// \brief Emits a single region.
|
||||
/// \param SingleOpGen Generator for the statement associated with the given
|
||||
/// single region.
|
||||
virtual void EmitOMPSingleRegion(CodeGenFunction &CGF,
|
||||
const std::function<void()> &SingleOpGen,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// \brief Emits explicit barrier for OpenMP threads.
|
||||
/// \param IsExplicit true, if it is explicitly specified barrier.
|
||||
///
|
||||
|
|
|
@ -707,8 +707,13 @@ void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &) {
|
|||
llvm_unreachable("CodeGen for 'omp section' is not supported yet.");
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &) {
|
||||
llvm_unreachable("CodeGen for 'omp single' is not supported yet.");
|
||||
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
|
||||
CGM.getOpenMPRuntime().EmitOMPSingleRegion(*this, [&]() -> void {
|
||||
InlinedOpenMPRegion Region(*this, S.getAssociatedStmt());
|
||||
RunCleanupsScope Scope(*this);
|
||||
EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
|
||||
EnsureInsertPoint();
|
||||
}, S.getLocStart());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
|
||||
|
|
|
@ -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_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: [[IS_SINGLE:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// CHECK-NEXT: br i1 [[IS_SINGLE]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// CHECK: [[THEN]]
|
||||
// CHECK-NEXT: store i8 2, i8* [[A_ADDR]]
|
||||
// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: br label {{%?}}[[EXIT]]
|
||||
// CHECK: [[EXIT]]
|
||||
#pragma omp single
|
||||
a = 2;
|
||||
// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: [[IS_SINGLE:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// CHECK-NEXT: br i1 [[IS_SINGLE]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// CHECK: [[THEN]]
|
||||
// CHECK-NEXT: call void [[FOO]]()
|
||||
// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: br label {{%?}}[[EXIT]]
|
||||
// CHECK: [[EXIT]]
|
||||
#pragma omp single
|
||||
foo();
|
||||
// CHECK-NOT: call i32 @__kmpc_single
|
||||
// CHECK-NOT: call void @__kmpc_end_single
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue