[clang] f627956 - [OPENMP]Fix PR52117: Crash caused by target region inside of task construct.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 3 07:01:44 PST 2021


Author: Alexey Bataev
Date: 2021-12-03T07:01:00-08:00
New Revision: f6279562dae456f6c58d5f7484ba4bae5c2071fa

URL: https://github.com/llvm/llvm-project/commit/f6279562dae456f6c58d5f7484ba4bae5c2071fa
DIFF: https://github.com/llvm/llvm-project/commit/f6279562dae456f6c58d5f7484ba4bae5c2071fa.diff

LOG: [OPENMP]Fix PR52117: Crash caused by target region inside of task construct.

Need to do the analysis of the captured expressions in the clauses.
Previously the compiler ignored them and it may lead to a compiler crash
trying to get the address of the mapped variables.

Differential Revision: https://reviews.llvm.org/D114546

Added: 
    clang/test/OpenMP/task_target_device_codegen.c

Modified: 
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/Analysis/cfg-openmp.cpp
    clang/test/OpenMP/taskloop_codegen.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index d3e3d1e2ffcb6..581b7c8841d33 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3500,7 +3500,8 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
       return;
     if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
       // Check the datasharing rules for the expressions in the clauses.
-      if (!CS) {
+      if (!CS || (isa<OMPCapturedExprDecl>(VD) && !CS->capturesVariable(VD) &&
+                  !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr)) {
         if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
           if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
             Visit(CED->getInit());
@@ -3819,6 +3820,10 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
   }
   void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
     for (OMPClause *C : S->clauses()) {
+      // Skip analysis of arguments of private clauses for task|target
+      // directives.
+      if (isa_and_nonnull<OMPPrivateClause>(C))
+        continue;
       // Skip analysis of arguments of implicitly defined firstprivate clause
       // for task|target directives.
       // Skip analysis of arguments of implicitly defined map clause for target
@@ -3841,6 +3846,15 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
     VisitStmt(S);
   }
 
+  void VisitCallExpr(CallExpr *S) {
+    for (Stmt *C : S->arguments()) {
+      if (C) {
+        // Check implicitly captured variables in the task-based directives to
+        // check if they must be firstprivatized.
+        Visit(C);
+      }
+    }
+  }
   void VisitStmt(Stmt *S) {
     for (Stmt *C : S->children()) {
       if (C) {

diff  --git a/clang/test/Analysis/cfg-openmp.cpp b/clang/test/Analysis/cfg-openmp.cpp
index 9e61d656698b9..353efbec919bc 100644
--- a/clang/test/Analysis/cfg-openmp.cpp
+++ b/clang/test/Analysis/cfg-openmp.cpp
@@ -598,19 +598,19 @@ void tls(int argc) {
 void tdpf(int argc) {
   int x, cond, fp, rd, lin, step, map;
 // CHECK-DAG:   [B1]
-// CHECK-DAG:  [[#TDPF:]]: cond
-// CHECK-DAG:  [[#TDPF+1]]: [B1.[[#TDPF]]] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-DAG:  [[#TDPF:]]: [B1.{{.+}}]
+// CHECK-DAG:  [[#TDPF+1]]: [B1.[[#TDPF+6]]] (ImplicitCastExpr, LValueToRValue, int)
 // CHECK-DAG:  [[#TDPF+2]]: [B1.[[#TDPF+1]]] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK-DAG:  [[#TDPF+3]]: [B1.[[#TDPF+6]]]
-// CHECK-DAG:  [[#TDPF+4]]: [B1.[[#TDPF+7]]]
+// CHECK-DAG:  [[#TDPF+3]]: [B1.[[#TDPF+7]]]
+// CHECK-DAG:  [[#TDPF+4]]: [B1.[[#TDPF+8]]]
 // CHECK-DAG:  [[#TDPF+5]]: #pragma omp teams distribute parallel for if(cond) firstprivate(fp) reduction(+: rd)
 // CHECK-DAG:    for (int i = 0;
 // CHECK-DAG:        [B3.[[#TDPFB:]]];
-// CHECK-DAG:  [[#TDPF+6]]: fp
-// CHECK-DAG:  [[#TDPF+7]]: rd
-// CHECK-DAG:  [[#TDPF+8]]: argc
-// CHECK-DAG:  [[#TDPF+9]]: x
-// CHECK-DAG:  [[#TDPF+10]]: cond
+// CHECK-DAG:  [[#TDPF+6]]: cond
+// CHECK-DAG:  [[#TDPF+7]]: fp
+// CHECK-DAG:  [[#TDPF+8]]: rd
+// CHECK-DAG:  [[#TDPF+9]]: argc
+// CHECK-DAG:  [[#TDPF+10]]: x
 // CHECK-DAG:  [[#TDPF+11]]: #pragma omp target
 // CHECK-DAG:   [B3]
 // CHECK-DAG:  [[#TDPFB-3]]: x
@@ -627,19 +627,19 @@ void tdpf(int argc) {
 void tdpfs(int argc) {
   int x, cond, fp, rd, lin, step, map;
 // CHECK-DAG:   [B1]
-// CHECK-DAG:  [[#TDPFS:]]: cond
-// CHECK-DAG:  [[#TDPFS+1]]: [B1.[[#TDPFS]]] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-DAG:  [[#TDPFS:]]: [B1.{{.+}}]
+// CHECK-DAG:  [[#TDPFS+1]]: [B1.[[#TDPFS+6]]] (ImplicitCastExpr, LValueToRValue, int)
 // CHECK-DAG:  [[#TDPFS+2]]: [B1.[[#TDPFS+1]]] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK-DAG:  [[#TDPFS+3]]: [B1.[[#TDPFS+6]]]
-// CHECK-DAG:  [[#TDPFS+4]]: [B1.[[#TDPFS+7]]]
+// CHECK-DAG:  [[#TDPFS+3]]: [B1.[[#TDPFS+7]]]
+// CHECK-DAG:  [[#TDPFS+4]]: [B1.[[#TDPFS+8]]]
 // CHECK-DAG:  [[#TDPFS+5]]: #pragma omp teams distribute parallel for simd if(cond) firstprivate(fp) reduction(+: rd)
 // CHECK-DAG:    for (int i = 0;
 // CHECK-DAG:        [B3.[[#TDPFSB:]]];
-// CHECK-DAG:  [[#TDPFS+6]]: fp
-// CHECK-DAG:  [[#TDPFS+7]]: rd
-// CHECK-DAG:  [[#TDPFS+8]]: argc
-// CHECK-DAG:  [[#TDPFS+9]]: x
-// CHECK-DAG:  [[#TDPFS+10]]: cond
+// CHECK-DAG:  [[#TDPFS+6]]: cond
+// CHECK-DAG:  [[#TDPFS+7]]: fp
+// CHECK-DAG:  [[#TDPFS+8]]: rd
+// CHECK-DAG:  [[#TDPFS+9]]: argc
+// CHECK-DAG:  [[#TDPFS+10]]: x
 // CHECK-DAG:  [[#TDPFS+11]]: #pragma omp target
 // CHECK-DAG:   [B3]
 // CHECK-DAG:  [[#TDPFSB-3]]: x

diff  --git a/clang/test/OpenMP/task_target_device_codegen.c b/clang/test/OpenMP/task_target_device_codegen.c
new file mode 100644
index 0000000000000..f5f537f590789
--- /dev/null
+++ b/clang/test/OpenMP/task_target_device_codegen.c
@@ -0,0 +1,105 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[       .].+[.|,]" --prefix-filecheck-ir-name _
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fopenmp-version=50 -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fopenmp-version=50 -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// SIMD-ONLY0-NOT: {{__kmpc|__tgt}}
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+void test_task_affinity() {
+  int t;
+#pragma omp task
+  {
+#pragma omp target device(t)
+    ;
+  }
+}
+#endif
+// CHECK-LABEL: define {{[^@]+}}@test_task_affinity
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[T:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1:[0-9]+]])
+// CHECK-NEXT:    [[TMP1:%.*]] = call i8* @__kmpc_omp_task_alloc(%struct.ident_t* @[[GLOB1]], i32 [[TMP0]], i32 1, i64 48, i64 0, i32 (i32, i8*)* bitcast (i32 (i32, %struct.kmp_task_t_with_privates*)* @.omp_task_entry. to i32 (i32, i8*)*))
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[TMP1]] to %struct.kmp_task_t_with_privates*
+// CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES:%.*]], %struct.kmp_task_t_with_privates* [[TMP2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], %struct.kmp_task_t_with_privates* [[TMP2]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], %struct..kmp_privates.t* [[TMP4]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP6:%.*]] = load i32, i32* [[T]], align 4
+// CHECK-NEXT:    store i32 [[TMP6]], i32* [[TMP5]], align 8
+// CHECK-NEXT:    [[TMP7:%.*]] = call i32 @__kmpc_omp_task(%struct.ident_t* @[[GLOB1]], i32 [[TMP0]], i8* [[TMP1]])
+// CHECK-NEXT:    ret void
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_test_task_affinity_l18
+// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret void
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@.omp_task_privates_map.
+// CHECK-SAME: (%struct..kmp_privates.t* noalias [[TMP0:%.*]], i32** noalias [[TMP1:%.*]]) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[DOTADDR:%.*]] = alloca %struct..kmp_privates.t*, align 8
+// CHECK-NEXT:    [[DOTADDR1:%.*]] = alloca i32**, align 8
+// CHECK-NEXT:    store %struct..kmp_privates.t* [[TMP0]], %struct..kmp_privates.t** [[DOTADDR]], align 8
+// CHECK-NEXT:    store i32** [[TMP1]], i32*** [[DOTADDR1]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = load %struct..kmp_privates.t*, %struct..kmp_privates.t** [[DOTADDR]], align 8
+// CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], %struct..kmp_privates.t* [[TMP2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32**, i32*** [[DOTADDR1]], align 8
+// CHECK-NEXT:    store i32* [[TMP3]], i32** [[TMP4]], align 8
+// CHECK-NEXT:    ret void
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@.omp_task_entry.
+// CHECK-SAME: (i32 [[TMP0:%.*]], %struct.kmp_task_t_with_privates* noalias [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[DOTGLOBAL_TID__ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTPART_ID__ADDR_I:%.*]] = alloca i32*, align 8
+// CHECK-NEXT:    [[DOTPRIVATES__ADDR_I:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:    [[DOTCOPY_FN__ADDR_I:%.*]] = alloca void (i8*, ...)*, align 8
+// CHECK-NEXT:    [[DOTTASK_T__ADDR_I:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:    [[__CONTEXT_ADDR_I:%.*]] = alloca %struct.anon*, align 8
+// CHECK-NEXT:    [[DOTFIRSTPRIV_PTR_ADDR_I:%.*]] = alloca i32*, align 8
+// CHECK-NEXT:    [[DOTCAPTURE_EXPR__I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTADDR1:%.*]] = alloca %struct.kmp_task_t_with_privates*, align 8
+// CHECK-NEXT:    store i32 [[TMP0]], i32* [[DOTADDR]], align 4
+// CHECK-NEXT:    store %struct.kmp_task_t_with_privates* [[TMP1]], %struct.kmp_task_t_with_privates** [[DOTADDR1]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* [[DOTADDR]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = load %struct.kmp_task_t_with_privates*, %struct.kmp_task_t_with_privates** [[DOTADDR1]], align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES:%.*]], %struct.kmp_task_t_with_privates* [[TMP3]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T:%.*]], %struct.kmp_task_t* [[TMP4]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T]], %struct.kmp_task_t* [[TMP4]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP7:%.*]] = load i8*, i8** [[TMP6]], align 8
+// CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[TMP7]] to %struct.anon*
+// CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], %struct.kmp_task_t_with_privates* [[TMP3]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP10:%.*]] = bitcast %struct..kmp_privates.t* [[TMP9]] to i8*
+// CHECK-NEXT:    [[TMP11:%.*]] = bitcast %struct.kmp_task_t_with_privates* [[TMP3]] to i8*
+// CHECK-NEXT:    call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]])
+// CHECK-NEXT:    call void @llvm.experimental.noalias.scope.decl(metadata [[META6:![0-9]+]])
+// CHECK-NEXT:    call void @llvm.experimental.noalias.scope.decl(metadata [[META8:![0-9]+]])
+// CHECK-NEXT:    call void @llvm.experimental.noalias.scope.decl(metadata [[META10:![0-9]+]])
+// CHECK-NEXT:    store i32 [[TMP2]], i32* [[DOTGLOBAL_TID__ADDR_I]], align 4, !noalias !12
+// CHECK-NEXT:    store i32* [[TMP5]], i32** [[DOTPART_ID__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    store i8* [[TMP10]], i8** [[DOTPRIVATES__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    store void (i8*, ...)* bitcast (void (%struct..kmp_privates.t*, i32**)* @.omp_task_privates_map. to void (i8*, ...)*), void (i8*, ...)** [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    store i8* [[TMP11]], i8** [[DOTTASK_T__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    store %struct.anon* [[TMP8]], %struct.anon** [[__CONTEXT_ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    [[TMP12:%.*]] = load %struct.anon*, %struct.anon** [[__CONTEXT_ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    [[TMP13:%.*]] = load void (i8*, ...)*, void (i8*, ...)** [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    [[TMP14:%.*]] = load i8*, i8** [[DOTPRIVATES__ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    [[TMP15:%.*]] = bitcast void (i8*, ...)* [[TMP13]] to void (i8*, i32**)*
+// CHECK-NEXT:    call void [[TMP15]](i8* [[TMP14]], i32** [[DOTFIRSTPRIV_PTR_ADDR_I]]) #[[ATTR4:[0-9]+]]
+// CHECK-NEXT:    [[TMP16:%.*]] = load i32*, i32** [[DOTFIRSTPRIV_PTR_ADDR_I]], align 8, !noalias !12
+// CHECK-NEXT:    [[TMP17:%.*]] = load i32, i32* [[TMP16]], align 4
+// CHECK-NEXT:    store i32 [[TMP17]], i32* [[DOTCAPTURE_EXPR__I]], align 4, !noalias !12
+// CHECK-NEXT:    call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_test_task_affinity_l18() #[[ATTR4]]
+// CHECK-NEXT:    ret i32 0
+//

diff  --git a/clang/test/OpenMP/taskloop_codegen.cpp b/clang/test/OpenMP/taskloop_codegen.cpp
index 7402c2ad65eba..1c46c9be0d512 100644
--- a/clang/test/OpenMP/taskloop_codegen.cpp
+++ b/clang/test/OpenMP/taskloop_codegen.cpp
@@ -238,8 +238,8 @@ class St {
 // CHECK-LABEL: taskloop_with_class
 void taskloop_with_class() {
   St s1;
-  // CHECK: [[TD:%.+]] = call i8* @__kmpc_omp_task_alloc(%struct.ident_t* @{{.+}}, i32 [[GTID:%.+]], i32 1, i64 88, i64 8, i32 (i32, i8*)* bitcast (i32 (i32, [[TD_TYPE:%.+]]*)* @{{.+}} to i32 (i32, i8*)*))
-  // CHECK: call void @__kmpc_taskloop(%struct.ident_t* @{{.+}}, i32 [[GTID]], i8* [[TD]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 1, i32 0, i64 0, i8* bitcast (void ([[TD_TYPE]]*, [[TD_TYPE]]*, i32)* @{{.+}} to i8*))
+  // CHECK: [[TD:%.+]] = call i8* @__kmpc_omp_task_alloc(%struct.ident_t* @{{.+}}, i32 [[GTID:%.+]], i32 1, i64 80, i64 8, i32 (i32, i8*)* bitcast (i32 (i32, [[TD_TYPE:%.+]]*)* @{{.+}} to i32 (i32, i8*)*))
+  // CHECK: call void @__kmpc_taskloop(%struct.ident_t* @{{.+}}, i32 [[GTID]], i8* [[TD]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 1, i32 0, i64 0, i8* null)
 #pragma omp taskloop
   for (St s = St(); s < s1; s += 1) {
   }


        


More information about the cfe-commits mailing list