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 *
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);
+}
#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"
class Function;
class Module;
class StructLayout;
+class ArrayType;
class FunctionType;
class StructType;
class Type;
// 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:
/// \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.
/// \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
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
--- /dev/null
+// 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