Index: lib/CodeGen/CGOpenMPRuntime.h =================================================================== --- lib/CodeGen/CGOpenMPRuntime.h +++ lib/CodeGen/CGOpenMPRuntime.h @@ -16,6 +16,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -27,6 +28,7 @@ class Function; class Module; class StructLayout; +class ArrayType; class FunctionType; class StructType; class Type; @@ -67,8 +69,14 @@ // Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro // microtask, ...); OMPRTL__kmpc_fork_call, - // Call to kmp_int32 kmpc_global_thread_num(ident_t *loc); - OMPRTL__kmpc_global_thread_num + // Call to __kmpc_int32 kmpc_global_thread_num(ident_t *loc); + OMPRTL__kmpc_global_thread_num, + // Call to void __kmpc_critical(ident_t ∗loc, kmp_int32 global_tid, + // kmp_critical_name ∗crit); + OMPRTL__kmpc_critical, + // Call to void __kmpc_end_critical(ident_t ∗loc, kmp_int32 global_tid, + // kmp_critical_name ∗crit); + OMPRTL__kmpc_end_critical }; private: @@ -134,6 +142,11 @@ /// \brief Map of local gtid and functions. typedef llvm::DenseMap OpenMPGtidMapTy; OpenMPGtidMapTy OpenMPGtidMap; + /// \brief Type kmp_critical_name, originally defined as typedef kmp_int32 + /// kmp_critical_name[8]; + llvm::ArrayType *KmpCriticalNameTy; + /// \brief Map of critical regions names and the corresponding lock objects. + llvm::StringMap CriticalRegionVarNames; public: explicit CGOpenMPRuntime(CodeGenModule &CGM); @@ -170,6 +183,11 @@ /// \param Function OpenMP runtime function. /// \return Specified function. llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function); + + /// \brief Returns corresponding lock object for the specified critical region + /// name. If the lock object does not exist it is created, otherwise the + /// reference to the existing copy is returned. + llvm::Value *GetCriticalRegionLock(StringRef CriticalName); }; } // namespace CodeGen } // namespace clang Index: lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntime.cpp +++ lib/CodeGen/CGOpenMPRuntime.cpp @@ -34,6 +34,7 @@ llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty), llvm::PointerType::getUnqual(CGM.Int32Ty)}; Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true); + KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8); } llvm::Value * @@ -196,6 +197,48 @@ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num"); break; } + case OMPRTL__kmpc_critical: { + // Build void __kmpc_critical(ident_t ∗loc, kmp_int32 global_tid, + // kmp_critical_name ∗crit); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical"); + break; + } + case OMPRTL__kmpc_end_critical: { + // Build void __kmpc_end_critical(ident_t ∗loc, kmp_int32 global_tid, + // kmp_critical_name ∗crit); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical"); + break; + } } return RTLFn; } + +llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + Out << ".gomp_critical_user_" << CriticalName << ".var"; + auto RuntimeCriticalName = Out.str(); + auto LockIter = CriticalRegionVarNames.find(RuntimeCriticalName); + if (LockIter != CriticalRegionVarNames.end()) + return LockIter->getValue(); + + auto &Elem = + CriticalRegionVarNames.GetOrCreateValue(RuntimeCriticalName, nullptr); + auto Lock = new llvm::GlobalVariable( + CGM.getModule(), KmpCriticalNameTy, /*IsConstant*/ false, + llvm::GlobalValue::CommonLinkage, + llvm::Constant::getNullValue(KmpCriticalNameTy), Elem.getKey()); + Elem.setValue(Lock); + return Lock; +} + Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -94,8 +94,30 @@ llvm_unreachable("CodeGen for 'omp master' is not supported yet."); } -void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &) { - llvm_unreachable("CodeGen for 'omp critical' is not supported yet."); +void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { + // __kmpc_critical(); + // + // __kmpc_end_critical(); + // + + auto Lock = CGM.getOpenMPRuntime().GetCriticalRegionLock( + S.getDirectiveName().getAsString()); + // Prepare other arguments and build a call to __kmpc_critical + llvm::Value *Args[] = { + CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()), + CGM.getOpenMPRuntime().GetOpenMPGlobalThreadNum(*this, S.getLocStart()), + Lock}; + auto RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction( + CGOpenMPRuntime::OMPRTL__kmpc_critical); + EmitRuntimeCall(RTLFn, Args); + { + RunCleanupsScope Scope(*this); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EnsureInsertPoint(); + } + RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction( + CGOpenMPRuntime::OMPRTL__kmpc_end_critical); + EmitRuntimeCall(RTLFn, Args); } void Index: test/OpenMP/critical_codegen.cpp =================================================================== --- test/OpenMP/critical_codegen.cpp +++ test/OpenMP/critical_codegen.cpp @@ -0,0 +1,38 @@ +// 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: [[UNNAMED_LOCK:@.+]] = common global [8 x i32] zeroinitializer +// CHECK: [[THE_NAME_LOCK:@.+]] = common global [8 x i32] zeroinitializer + +// 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: call void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]]) +// CHECK-NEXT: store i8 2, i8* [[A_ADDR]] +// CHECK-NEXT: call void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]]) +#pragma omp critical + a = 2; +// CHECK: call void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]]) +// CHECK-NEXT: call void [[FOO]]() +// CHECK-NEXT: call void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]]) +#pragma omp critical(the_name) + foo(); +// CHECK-NOT: call void @__kmpc_critical +// CHECK-NOT: call void @__kmpc_end_critical + return a; +} + +#endif