diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3280,13 +3280,15 @@ 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(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; @@ -16496,10 +16498,22 @@ /// 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(I); @@ -16519,9 +16533,10 @@ 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; } @@ -16532,8 +16547,7 @@ << "omp_allocator_handle_t"; return false; } - OMPAllocatorHandleT.addConst(); - Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT); + return true; } @@ -23656,17 +23670,26 @@ AllocatorExpr = D.Allocator->IgnoreParenImpCasts(); auto *DRE = dyn_cast(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(); diff --git a/clang/test/OpenMP/bug54082.c b/clang/test/OpenMP/bug54082.c new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/bug54082.c @@ -0,0 +1,114 @@ +// 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 unsigned long long omp_uintptr_t; +typedef unsigned long long 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 +// diff --git a/clang/test/OpenMP/target_uses_allocators.c b/clang/test/OpenMP/target_uses_allocators.c --- a/clang/test/OpenMP/target_uses_allocators.c +++ b/clang/test/OpenMP/target_uses_allocators.c @@ -6,7 +6,7 @@ #ifndef HEADER #define HEADER -enum omp_allocator_handle_t { +typedef enum omp_allocator_handle_t { omp_null_allocator = 0, omp_default_mem_alloc = 1, omp_large_cap_mem_alloc = 2, @@ -17,7 +17,7 @@ omp_pteam_mem_alloc = 7, omp_thread_mem_alloc = 8, KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__ -}; +} omp_allocator_handle_t; // CHECK: define {{.*}}[[FIE:@.+]]() void fie(void) { @@ -105,4 +105,4 @@ // CHECK-NEXT: %.x..void.addr = call ptr @__kmpc_alloc(i32 %[[#R0]], i64 4, ptr inttoptr (i64 8 to ptr)) // CHECK-NEXT: %[[#R1:]] = load i32, ptr %x.addr, align 4 // CHECK-NEXT: store i32 %[[#R1]], ptr %.x..void.addr, align 4 -// CHECK-NEXT: call void @__kmpc_free(i32 %[[#R0]], ptr %.x..void.addr, ptr inttoptr (i64 8 to ptr)) \ No newline at end of file +// CHECK-NEXT: call void @__kmpc_free(i32 %[[#R0]], ptr %.x..void.addr, ptr inttoptr (i64 8 to ptr)) diff --git a/openmp/runtime/test/parallel/bug54082.c b/openmp/runtime/test/parallel/bug54082.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/parallel/bug54082.c @@ -0,0 +1,54 @@ +// This test is adapted from test_parallel_for_allocate.c in SOLLVE V&V. +// https://github.com/SOLLVE/sollve_vv/blob/master/tests/5.0/parallel_for/test_parallel_for_allocate.c +// RUN: %libomp-compile-and-run +#include + +#include +#include + +#define N 1024 + +int main(int argc, char *argv[]) { + int errors = 0; + int *x; + int result[N][N]; + int successful_alloc = 0; + + 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); + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + result[i][j] = -1; + } + } + +#pragma omp parallel for allocate(x_alloc: x) private(x) shared(result) + for (int i = 0; i < N; i++) { + x = (int *)malloc(N * sizeof(int)); + if (x != NULL) { +#pragma omp simd simdlen(16) aligned(x : 64) + for (int j = 0; j < N; j++) { + x[j] = j * i; + } + for (int j = 0; j < N; j++) { + result[i][j] = x[j]; + } + free(x); + successful_alloc++; + } + } + + errors += successful_alloc < 1; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + errors += result[i][j] != i * j; + } + } + + omp_destroy_allocator(x_alloc); + + return errors; +}