]> granicus.if.org Git - clang/commitdiff
[OPENMP] Codegen for 'omp critical' directive.
authorAlexey Bataev <a.bataev@hotmail.com>
Mon, 22 Sep 2014 10:01:53 +0000 (10:01 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Mon, 22 Sep 2014 10:01:53 +0000 (10:01 +0000)
This patch adds codegen for constructs:
#pragma omp critical [name]
<body>

It generates global variable ".gomp_critical_user_[name].var" of type int32[8]. Then it generates library call "kmpc_critical(loc, gtid, .gomp_critical_user_[name].var)", code for <body> statement and final call "kmpc_end_critical(loc, gtid, .gomp_critical_user_[name].var)".
Differential Revision: http://reviews.llvm.org/D5202

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218239 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGOpenMPRuntime.cpp
lib/CodeGen/CGOpenMPRuntime.h
lib/CodeGen/CGStmtOpenMP.cpp
test/OpenMP/critical_codegen.cpp [new file with mode: 0644]

index 7e68c4829e7d0d2aa362f2a80ed163f68cce8db8..813c3681af7a5dbc3d3713bb782a654237d9b204 100644 (file)
@@ -34,6 +34,7 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
   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,66 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
     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 &Elem = CriticalRegionVarNames.GetOrCreateValue(RuntimeCriticalName);
+  if (Elem.getValue() != nullptr)
+    return Elem.getValue();
+
+  auto Lock = new llvm::GlobalVariable(
+      CGM.getModule(), KmpCriticalNameTy, /*IsConstant*/ false,
+      llvm::GlobalValue::CommonLinkage,
+      llvm::Constant::getNullValue(KmpCriticalNameTy), Elem.getKey());
+  Elem.setValue(Lock);
+  return Lock;
+}
+
+void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
+                                                 llvm::Value *RegionLock,
+                                                 SourceLocation Loc) {
+  // Prepare other arguments and build a call to __kmpc_critical
+  llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+                         GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+  auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
+  CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
+                                               llvm::Value *RegionLock,
+                                               SourceLocation Loc) {
+  // Prepare other arguments and build a call to __kmpc_critical
+  llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+                         GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+  auto RTLFn =
+      CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
+  CGF.EmitRuntimeCall(RTLFn, Args);
+}
index 3759a77103950f7cb1118f4fe1dfd8fe0efefe2a..d32c43a8b03b8dff22e66f194d551c8ef6ee6b71 100644 (file)
@@ -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 Constant;
 class Function;
 class Module;
 class StructLayout;
+class ArrayType;
 class FunctionType;
 class StructType;
 class Type;
@@ -67,8 +69,14 @@ public:
     // 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,10 +142,15 @@ private:
   /// \brief Map of local gtid and functions.
   typedef llvm::DenseMap<llvm::Function *, llvm::Value *> 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<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
 
 public:
   explicit CGOpenMPRuntime(CodeGenModule &CGM);
-  ~CGOpenMPRuntime() {}
+  virtual ~CGOpenMPRuntime() {}
 
   /// \brief Cleans up references to the objects in finished function.
   /// \param CGF Reference to finished CodeGenFunction.
@@ -170,6 +183,31 @@ public:
   /// \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);
+
+  /// \brief Emits start of the critical region by calling void
+  /// __kmpc_critical(ident_t ∗loc, kmp_int32 global_tid, kmp_critical_name
+  /// ∗\a RegionLock)
+  /// \param CGF Reference to current CodeGenFunction.
+  /// \param RegionLock The lock object for critical region.
+  /// \param Loc Location of the construct.
+  virtual void EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
+                                          llvm::Value *RegionLock,
+                                          SourceLocation Loc);
+
+  /// \brief Emits end of the critical region by calling void
+  /// __kmpc_end_critical(ident_t ∗loc, kmp_int32 global_tid, kmp_critical_name
+  /// ∗\a RegionLock)
+  /// \param CGF Reference to current CodeGenFunction.
+  /// \param RegionLock The lock object for critical region.
+  /// \param Loc Location of the construct.
+  virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
+                                        llvm::Value *RegionLock,
+                                        SourceLocation Loc);
 };
 } // namespace CodeGen
 } // namespace clang
index 74b73a55603575a82d5c14fc348940e55bc345f4..6906044b62cf398916673c413ad2df4f83db4b0e 100644 (file)
@@ -98,8 +98,22 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &) {
   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();
+  // <captured_body>
+  // __kmpc_end_critical();
+  //
+
+  auto Lock = CGM.getOpenMPRuntime().GetCriticalRegionLock(
+      S.getDirectiveName().getAsString());
+  CGM.getOpenMPRuntime().EmitOMPCriticalRegionStart(*this, Lock,
+                                                    S.getLocStart());
+  {
+    RunCleanupsScope Scope(*this);
+    EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+    EnsureInsertPoint();
+  }
+  CGM.getOpenMPRuntime().EmitOMPCriticalRegionEnd(*this, Lock, S.getLocEnd());
 }
 
 void
diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp
new file mode 100644 (file)
index 0000000..dda532c
--- /dev/null
@@ -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