Allocator->containsUnexpandedParameterPack())
return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ llvm::FoldingSetNodeID AEId;
const Expr *AE = Allocator->IgnoreParenImpCasts();
+ AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
- llvm::FoldingSetNodeID AEId, DAEId;
- AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
- DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true);
+ llvm::FoldingSetNodeID DAEId;
+ DefAllocator->IgnoreImpCasts()->Profile(DAEId, S.getASTContext(),
+ /*Canonical=*/true);
if (AEId == DAEId) {
AllocatorKindRes = AllocatorKind;
break;
/// Tries to find omp_allocator_handle_t type.
static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
DSAStackTy *Stack) {
- QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT();
- if (!OMPAllocatorHandleT.isNull())
+ if (!Stack->getOMPAllocatorHandleT().isNull())
return true;
- // Build the predefined allocator expressions.
+
+ // Set the allocator handle type.
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_allocator_handle_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ S.Diag(Loc, diag::err_omp_implied_type_not_found)
+ << "omp_allocator_handle_t";
+ return false;
+ }
+ QualType AllocatorHandleEnumTy = PT.get();
+ AllocatorHandleEnumTy.addConst();
+ Stack->setOMPAllocatorHandleT(AllocatorHandleEnumTy);
+
+ // Fill the predefined allocator map.
bool ErrorFound = false;
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
ErrorFound = true;
break;
}
- if (OMPAllocatorHandleT.isNull())
- OMPAllocatorHandleT = AllocatorType;
- if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) {
+ Res = S.PerformImplicitConversion(Res.get(), AllocatorHandleEnumTy,
+ Sema::AA_Initializing,
+ /* AllowExplicit */ true);
+ if (!Res.isUsable()) {
ErrorFound = true;
break;
}
<< "omp_allocator_handle_t";
return false;
}
- OMPAllocatorHandleT.addConst();
- Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT);
+
return true;
}
AllocatorExpr = D.Allocator->IgnoreParenImpCasts();
auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr);
bool IsPredefinedAllocator = false;
- if (DRE)
- IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl());
- if (!DRE ||
- !(Context.hasSameUnqualifiedType(
- AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) ||
- Context.typesAreCompatible(AllocatorExpr->getType(),
- DSAStack->getOMPAllocatorHandleT(),
- /*CompareUnqualified=*/true)) ||
- (!IsPredefinedAllocator &&
- (AllocatorExpr->getType().isConstant(Context) ||
- !AllocatorExpr->isLValue()))) {
+ if (DRE) {
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorTy =
+ getAllocatorKind(*this, DSAStack, AllocatorExpr);
+ IsPredefinedAllocator =
+ AllocatorTy !=
+ OMPAllocateDeclAttr::AllocatorTypeTy::OMPUserDefinedMemAlloc;
+ }
+ QualType OMPAllocatorHandleT = DSAStack->getOMPAllocatorHandleT();
+ QualType AllocatorExprType = AllocatorExpr->getType();
+ bool IsTypeCompatible = IsPredefinedAllocator;
+ IsTypeCompatible = IsTypeCompatible ||
+ Context.hasSameUnqualifiedType(AllocatorExprType,
+ OMPAllocatorHandleT);
+ IsTypeCompatible =
+ IsTypeCompatible ||
+ Context.typesAreCompatible(AllocatorExprType, OMPAllocatorHandleT);
+ bool IsNonConstantLValue =
+ !AllocatorExprType.isConstant(Context) && AllocatorExpr->isLValue();
+ if (!DRE || !IsTypeCompatible ||
+ (!IsPredefinedAllocator && !IsNonConstantLValue)) {
Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected)
<< "omp_allocator_handle_t" << (DRE ? 1 : 0)
<< AllocatorExpr->getType() << D.Allocator->getSourceRange();
--- /dev/null
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --prefix-filecheck-ir-name _
+// RUN: %clang_cc1 -fopenmp -O1 -x c -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+
+typedef enum omp_allocator_handle_t {
+ omp_null_allocator = 0,
+ omp_default_mem_alloc = 1,
+ omp_large_cap_mem_alloc = 2,
+ omp_const_mem_alloc = 3,
+ omp_high_bw_mem_alloc = 4,
+ omp_low_lat_mem_alloc = 5,
+ omp_cgroup_mem_alloc = 6,
+ omp_pteam_mem_alloc = 7,
+ omp_thread_mem_alloc = 8,
+ KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef enum omp_memspace_handle_t {
+ omp_default_mem_space = 0,
+ omp_large_cap_mem_space = 1,
+ omp_const_mem_space = 2,
+ omp_high_bw_mem_space = 3,
+ omp_low_lat_mem_space = 4,
+ llvm_omp_target_host_mem_space = 100,
+ llvm_omp_target_shared_mem_space = 101,
+ llvm_omp_target_device_mem_space = 102,
+ KMP_MEMSPACE_MAX_HANDLE = __UINTPTR_MAX__
+} omp_memspace_handle_t;
+
+typedef enum {
+ omp_atk_sync_hint = 1,
+ omp_atk_alignment = 2,
+ omp_atk_access = 3,
+ omp_atk_pool_size = 4,
+ omp_atk_fallback = 5,
+ omp_atk_fb_data = 6,
+ omp_atk_pinned = 7,
+ omp_atk_partition = 8
+} omp_alloctrait_key_t;
+
+typedef __UINTPTR_TYPE__ omp_uintptr_t;
+typedef __SIZE_TYPE__ size_t;
+
+typedef struct {
+ omp_alloctrait_key_t key;
+ omp_uintptr_t value;
+} omp_alloctrait_t;
+
+extern omp_allocator_handle_t
+omp_init_allocator(omp_memspace_handle_t memspace, int ntraits,
+ const omp_alloctrait_t traits[]);
+
+#define N 1024
+
+void foo() {
+ int *x;
+
+ omp_memspace_handle_t x_memspace = omp_default_mem_space;
+ omp_alloctrait_t x_traits[1] = {omp_atk_alignment, 64};
+ omp_allocator_handle_t x_alloc = omp_init_allocator(x_memspace, 1, x_traits);
+
+#pragma omp parallel for allocate(x_alloc : x) private(x)
+ for (int i = 0; i < N; i++) {
+ (void)x;
+ }
+}
+// CHECK-LABEL: define {{[^@]+}}@foo
+// CHECK-SAME: () local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[X_TRAITS:%.*]] = alloca [1 x %struct.omp_alloctrait_t], align 16
+// CHECK-NEXT: [[X_ALLOC:%.*]] = alloca i64, align 8
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[X_TRAITS]]) #[[ATTR5:[0-9]+]]
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(16) [[X_TRAITS]], ptr noundef nonnull align 16 dereferenceable(16) @__const.foo.x_traits, i64 16, i1 false)
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr nonnull [[X_ALLOC]]) #[[ATTR5]]
+// CHECK-NEXT: [[CALL:%.*]] = call i64 @omp_init_allocator(i64 noundef 0, i32 noundef 1, ptr noundef nonnull [[X_TRAITS]]) #[[ATTR5]]
+// CHECK-NEXT: store i64 [[CALL]], ptr [[X_ALLOC]], align 8, !tbaa [[TBAA3:![0-9]+]]
+// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @[[GLOB2:[0-9]+]], i32 1, ptr nonnull @.omp_outlined., ptr nonnull [[X_ALLOC]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr nonnull [[X_ALLOC]]) #[[ATTR5]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[X_TRAITS]]) #[[ATTR5]]
+// CHECK-NEXT: ret void
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@.omp_outlined.
+// CHECK-SAME: (ptr noalias nocapture noundef readonly [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture readnone [[DOTBOUND_TID_:%.*]], ptr nocapture noundef nonnull readonly align 8 dereferenceable(8) [[X_ALLOC:%.*]]) #[[ATTR4:[0-9]+]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[DOTOMP_LB]]) #[[ATTR5]]
+// CHECK-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA6:![0-9]+]]
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[DOTOMP_UB]]) #[[ATTR5]]
+// CHECK-NEXT: store i32 1023, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[DOTOMP_STRIDE]]) #[[ATTR5]]
+// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[DOTOMP_IS_LAST]]) #[[ATTR5]]
+// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[X_ALLOC]], align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[CONV:%.*]] = inttoptr i64 [[TMP1]] to ptr
+// CHECK-NEXT: [[DOTX__VOID_ADDR:%.*]] = tail call ptr @__kmpc_alloc(i32 [[TMP0]], i64 8, ptr [[CONV]])
+// CHECK-NEXT: call void @__kmpc_for_static_init_4(ptr nonnull @[[GLOB1:[0-9]+]], i32 [[TMP0]], i32 34, ptr nonnull [[DOTOMP_IS_LAST]], ptr nonnull [[DOTOMP_LB]], ptr nonnull [[DOTOMP_UB]], ptr nonnull [[DOTOMP_STRIDE]], i32 1, i32 1)
+// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smin.i32(i32 [[TMP2]], i32 1023)
+// CHECK-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA6]]
+// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr nonnull @[[GLOB1]], i32 [[TMP0]])
+// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr [[X_ALLOC]], align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[CONV5:%.*]] = inttoptr i64 [[TMP3]] to ptr
+// CHECK-NEXT: call void @__kmpc_free(i32 [[TMP0]], ptr [[DOTX__VOID_ADDR]], ptr [[CONV5]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[DOTOMP_IS_LAST]]) #[[ATTR5]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[DOTOMP_STRIDE]]) #[[ATTR5]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[DOTOMP_UB]]) #[[ATTR5]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[DOTOMP_LB]]) #[[ATTR5]]
+// CHECK-NEXT: ret void
+//