jdoerfert updated this revision to Diff 340126.
jdoerfert added a comment.
Avoid heap memory, copy when necessary, add documentation, address comments
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D101030/new/
https://reviews.llvm.org/D101030
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/AttrImpl.cpp
clang/lib/CodeGen/CGDecl.cpp
clang/lib/CodeGen/CGOpenMPRuntime.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/test/OpenMP/declare_target_codegen.cpp
clang/test/OpenMP/declare_target_codegen_globalization.cpp
clang/test/OpenMP/declare_target_device_only_compilation.cpp
clang/test/OpenMP/declare_target_messages.cpp
clang/test/OpenMP/declare_target_only_one_side_compilation.cpp
clang/test/OpenMP/nvptx_allocate_codegen.cpp
clang/test/OpenMP/nvptx_declare_target_var_ctor_dtor_codegen.cpp
clang/test/OpenMP/nvptx_declare_variant_name_mangling.cpp
llvm/include/llvm/Frontend/OpenMP/OMP.td
Index: llvm/include/llvm/Frontend/OpenMP/OMP.td
===================================================================
--- llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -922,6 +922,13 @@
VersionedClause<OMPC_DistSchedule>
];
}
+def OMP_BeginDeclareTarget : Directive<"begin declare target"> {
+ let allowedClauses = [
+ VersionedClause<OMPC_To>,
+ VersionedClause<OMPC_Link>,
+ VersionedClause<OMPC_DeviceType>,
+ ];
+}
def OMP_DeclareTarget : Directive<"declare target"> {
let allowedClauses = [
VersionedClause<OMPC_To>,
Index: clang/test/OpenMP/nvptx_declare_variant_name_mangling.cpp
===================================================================
--- clang/test/OpenMP/nvptx_declare_variant_name_mangling.cpp
+++ clang/test/OpenMP/nvptx_declare_variant_name_mangling.cpp
@@ -6,8 +6,8 @@
// CHECK-DAG: @_Z3barv
// CHECK-DAG: @_Z3bazv
-// CHECK-DAG: @"_Z53bar$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"
-// CHECK-DAG: @"_Z53baz$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"
+// CHECK-DAG: define{{.*}}@"_Z53bar$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"
+// CHECK-DAG: define{{.*}}@"_Z53baz$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"
// CHECK-DAG: call i32 @"_Z53bar$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"()
// CHECK-DAG: call i32 @"_Z53baz$ompvariant$S2$s7$Pnvptx$Pnvptx64$S3$s9$Pmatch_anyv"()
Index: clang/test/OpenMP/nvptx_declare_target_var_ctor_dtor_codegen.cpp
===================================================================
--- clang/test/OpenMP/nvptx_declare_target_var_ctor_dtor_codegen.cpp
+++ clang/test/OpenMP/nvptx_declare_target_var_ctor_dtor_codegen.cpp
@@ -34,21 +34,16 @@
#pragma omp declare target (bar)
int caz() { return 0; }
-// DEVICE-DAG: define{{ hidden | }}i32 [[FOO:@.*foo.*]]()
// DEVICE-DAG: define{{ hidden | }}i32 [[BAR:@.*bar.*]]()
-// DEVICE-DAG: define{{ hidden | }}i32 [[BAZ:@.*baz.*]]()
-// DEVICE-DAG: define{{ hidden | }}i32 [[DOO:@.*doo.*]]()
-// DEVICE-DAG: define{{ hidden | }}i32 [[CAR:@.*car.*]]()
-// DEVICE-DAG: define{{ hidden | }}i32 [[CAZ:@.*caz.*]]()
static int c = foo() + bar() + baz();
#pragma omp declare target (c)
-// HOST-DAG: @[[C_CTOR:__omp_offloading__.+_c_l44_ctor]] = private constant i8 0
-// DEVICE-DAG: define internal void [[C_CTOR:@__omp_offloading__.+_c_l44_ctor]]()
-// DEVICE-DAG: call i32 [[FOO]]()
-// DEVICE-DAG: call i32 [[BAR]]()
-// DEVICE-DAG: call i32 [[BAZ]]()
-// DEVICE-DAG: ret void
+// HOST-DAG: @[[C_CTOR:__omp_offloading__.+_c_l39_ctor]] = private constant i8 0
+
+// DEVICE-DAG: define internal void [[C_CTOR:@__omp_offloading__.+_c_l39_ctor]]()
+// DEVICE-DAG: define{{ hidden | }}i32 [[FOO:@.*foo.*]]()
+// DEVICE-DAG: define{{ hidden | }}i32 [[BAZ:@.*baz.*]]()
+// DEVICE-DAG: define{{ hidden | }}i32 [[DOO:@.*doo.*]]()
struct S {
int a;
@@ -60,17 +55,14 @@
#pragma omp declare target
S cd = doo() + car() + caz() + baz();
#pragma omp end declare target
-// HOST-DAG: @[[CD_CTOR:__omp_offloading__.+_cd_l61_ctor]] = private constant i8 0
-// DEVICE-DAG: define internal void [[CD_CTOR:@__omp_offloading__.+_cd_l61_ctor]]()
-// DEVICE-DAG: call i32 [[DOO]]()
-// DEVICE-DAG: call i32 [[CAR]]()
-// DEVICE-DAG: call i32 [[CAZ]]()
-// DEVICE-DAG: ret void
-
-// HOST-DAG: @[[CD_DTOR:__omp_offloading__.+_cd_l61_dtor]] = private constant i8 0
-// DEVICE-DAG: define internal void [[CD_DTOR:@__omp_offloading__.+_cd_l61_dtor]]()
-// DEVICE-DAG: call void
-// DEVICE-DAG: ret void
+// HOST-DAG: @[[CD_CTOR:__omp_offloading__.+_cd_l56_ctor]] = private constant i8 0
+// DEVICE-DAG: define internal void [[CD_CTOR:@__omp_offloading__.+_cd_l56_ctor]]()
+
+// DEVICE-DAG: define{{ hidden | }}i32 [[CAR:@.*car.*]]()
+// DEVICE-DAG: define{{ hidden | }}i32 [[CAZ:@.*caz.*]]()
+
+// HOST-DAG: @[[CD_DTOR:__omp_offloading__.+_cd_l56_dtor]] = private constant i8 0
+// DEVICE-DAG: define internal void [[CD_DTOR:@__omp_offloading__.+_cd_l56_dtor]]()
// HOST-DAG: @.omp_offloading.entry_name{{.*}} = internal unnamed_addr constant [{{[0-9]+}} x i8] c"[[C_ADDR]]\00"
// HOST-DAG: @.omp_offloading.entry.[[C_ADDR]] = weak{{.*}} constant %struct.__tgt_offload_entry { i8* bitcast (i32* @[[C_ADDR]] to i8*), i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* @.omp_offloading.entry_name{{.*}}, i32 0, i32 0), i64 4, i32 0, i32 0 }, section "omp_offloading_entries", align 1
@@ -91,13 +83,13 @@
return 0;
}
-// DEVICE: define weak{{.*}} void @__omp_offloading_{{.*}}_{{.*}}maini1{{.*}}_l[[@LINE-7]](i32* nonnull align {{[0-9]+}} dereferenceable{{[^,]*}}
-// DEVICE: [[C:%.+]] = load i32, i32* [[C_ADDR]],
-// DEVICE: store i32 [[C]], i32* %
+// DEVICE-DAG: define weak{{.*}} void @__omp_offloading_{{.*}}_{{.*}}maini1{{.*}}_l[[@LINE-7]](i32* nonnull align {{[0-9]+}} dereferenceable{{[^,]*}}
+// DEVICE-DAG: [[C:%.+]] = load i32, i32* [[C_ADDR]],
+// DEVICE-DAG: store i32 [[C]], i32* %
-// HOST: define internal void @__omp_offloading_{{.*}}_{{.*}}maini1{{.*}}_l[[@LINE-11]](i32* nonnull align {{[0-9]+}} dereferenceable{{.*}})
-// HOST: [[C:%.*]] = load i32, i32* @[[C_ADDR]],
-// HOST: store i32 [[C]], i32* %
+// HOST-DAG: define internal void @__omp_offloading_{{.*}}_{{.*}}maini1{{.*}}_l[[@LINE-11]](i32* nonnull align {{[0-9]+}} dereferenceable{{.*}})
+// HOST-DAG: [[C:%.*]] = load i32, i32* @[[C_ADDR]],
+// HOST-DAG: store i32 [[C]], i32* %
// HOST-DAG: !{i32 1, !"[[CD_ADDR]]", i32 0, i32 {{[0-9]+}}}
// HOST-DAG: !{i32 1, !"[[C_ADDR]]", i32 0, i32 {{[0-9]+}}}
Index: clang/test/OpenMP/nvptx_allocate_codegen.cpp
===================================================================
--- clang/test/OpenMP/nvptx_allocate_codegen.cpp
+++ clang/test/OpenMP/nvptx_allocate_codegen.cpp
@@ -81,7 +81,19 @@
}
}
-#pragma omp end declare target
+int LateAllocateDecl1;
+#pragma omp declare target
+
+int LateAllocateDecl2;
+#pragma omp declare target to(LateAllocateDecl2)
+
+int LateAllocateDecl3;
+#pragma omp declare target(LateAllocateDecl3)
+
+#pragma omp allocate(LateAllocateDecl1) allocator(omp_const_mem_alloc)
+#pragma omp allocate(LateAllocateDecl2) allocator(omp_const_mem_alloc)
+#pragma omp allocate(LateAllocateDecl3) allocator(omp_const_mem_alloc)
+
#endif
// CHECK-LABEL: define {{[^@]+}}@main
// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
Index: clang/test/OpenMP/declare_target_only_one_side_compilation.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/declare_target_only_one_side_compilation.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix HOST
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix DEVICE
+
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-pc-linux-gnu -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix HOST
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-pc-linux-gnu -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-i386-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-i386-host.bc -o - | FileCheck %s --check-prefix DEVICE
+
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -fopenmp-targets=x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix HOST
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -fopenmp-targets=x86_64-unknown-linux-gnu -emit-llvm-bc %s -o %t-x86_64-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86_64-host.bc -o - | FileCheck %s --check-prefix DEVICE
+
+// expected-no-diagnostics
+
+#pragma omp declare target
+#pragma omp begin declare variant match(device = {kind(nohost)})
+int G1;
+static int G2;
+#pragma omp end declare variant
+#pragma omp end declare target
+
+#pragma omp begin declare target device_type(nohost)
+int G3;
+static int G4;
+#pragma omp end declare target
+
+#pragma omp declare target
+int G5;
+static int G6;
+#pragma omp end declare target
+
+#pragma omp declare target to(G5, G6) device_type(nohost)
+
+#pragma omp begin declare target device_type(host)
+int G7;
+static int G8;
+#pragma omp end declare target
+
+#pragma omp declare target
+int G9;
+static int G10;
+#pragma omp end declare target
+
+int G11;
+static int G12;
+#pragma omp declare target to(G9, G10, G11, G12) device_type(host)
+
+// TODO: The code below should probably work but it is not 100% clear.
+#if 0
+#pragma omp declare target
+#pragma omp begin declare variant match(device = {kind(host)})
+int GX;
+static int GY;
+#pragma omp end declare variant
+#pragma omp end declare target
+#endif
+
+// TODO: It is odd, probably wrong, that we don't mangle all variables.
+
+// DEVICE-DAG: @G1 = hidden {{.*}}global i32 0, align 4
+// DEVICE-DAG: @_ZL2G2 = internal {{.*}}global i32 0, align 4
+// DEVICE-DAG: @G3 = hidden {{.*}}global i32 0, align 4
+// DEVICE-DAG: @_ZL2G4 = internal {{.*}}global i32 0, align 4
+// DEVICE-DAG: @G5 = hidden {{.*}}global i32 0, align 4
+// DEVICE-DAG: @_ZL2G6 = internal {{.*}}global i32 0, align 4
+// DEVICE-NOT: ref
+// DEVICE-NOT: llvm.used
+// DEVICE-NOT: omp_offload
+
+// HOST-DAG: @G7 = dso_local global i32 0, align 4
+// HOST-DAG: @_ZL2G8 = internal global i32 0, align 4
+// HOST-DAG: @G9 = dso_local global i32 0, align 4
+// HOST-DAG: @_ZL3G10 = internal global i32 0, align 4
+// HOST-DAG: @G11 = dso_local global i32 0, align 4
+// HOST-DAG: @_ZL3G12 = internal global i32 0, align 4
Index: clang/test/OpenMP/declare_target_messages.cpp
===================================================================
--- clang/test/OpenMP/declare_target_messages.cpp
+++ clang/test/OpenMP/declare_target_messages.cpp
@@ -17,13 +17,16 @@
void f();
#pragma omp end declare target shared(a) // expected-warning {{extra tokens at the end of '#pragma omp end declare target' are ignored}}
-#pragma omp declare target map(a) // omp45-error {{unexpected 'map' clause, only 'to' or 'link' clauses expected}} omp5-error {{unexpected 'map' clause, only 'to', 'link' or 'device_type' clauses expected}}
+#pragma omp declare target map(a) // expected-error {{expected at least one 'to' or 'link' clause}} omp45-error {{unexpected 'map' clause, only 'to' or 'link' clauses expected}} omp5-error {{unexpected 'map' clause, only 'to', 'link' or 'device_type' clauses expected}}
#pragma omp declare target to(foo1) // expected-error {{use of undeclared identifier 'foo1'}}
#pragma omp declare target link(foo2) // expected-error {{use of undeclared identifier 'foo2'}}
-#pragma omp declare target to(f) device_type(any) device_type(any) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-warning 2 {{more than one 'device_type' clause is specified}} omp5-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}}
+#pragma omp declare target to(f) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} dev5-note {{marked as 'device_type(host)' here}}
+
+void q();
+#pragma omp declare target to(q) device_type(any) device_type(any) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-warning {{more than one 'device_type' clause is specified}}
void c();
@@ -118,7 +121,8 @@
g = object.method();
g += object.method1();
g += object1.method() + p;
- f();
+ f(); // dev5-error {{function with 'device_type(host)' is not available on device}}
+ q();
c();
}
#pragma omp declare target
@@ -150,10 +154,10 @@
}
namespace {
-#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}}
- int x;
-} // expected-error {{expected '#pragma omp end declare target'}}
-#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+#pragma omp declare target
+int x;
+} // namespace
+#pragma omp end declare target
#pragma omp declare target link(S) // expected-error {{'S' used in declare target directive is not a variable or a function name}}
@@ -187,4 +191,10 @@
void any7() {device();} // host5-error {{function with 'device_type(nohost)' is not available on host}}
void any8() {any2();}
-#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}}
+int MultiDevTy;
+#pragma omp declare target to(MultiDevTy) device_type(any) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}}
+#pragma omp declare target to(MultiDevTy) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}}
+#pragma omp declare target to(MultiDevTy) device_type(nohost) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(nohost)' does not match previously specified 'device_type(any)' for the same declaration}}
+
+// TODO: Issue an error message error {{expected '#pragma omp end declare target'}} note {{to match this '#pragma omp declare target'}}
+#pragma omp declare target
Index: clang/test/OpenMP/declare_target_device_only_compilation.cpp
===================================================================
--- clang/test/OpenMP/declare_target_device_only_compilation.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s
-
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-pc-linux-gnu -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-i386-host.bc
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-i386-host.bc -o - | FileCheck %s
-
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -fopenmp-targets=x86_64-unknown-linux-gnu -emit-llvm-bc %s -o %t-x86_64-host.bc
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86_64-host.bc -o - | FileCheck %s
-
-// expected-no-diagnostics
-
-#pragma omp declare target
-#pragma omp begin declare variant match(device={kind(nohost)})
-int G1;
-#pragma omp end declare variant
-#pragma omp end declare target
-
-// CHECK: @[[G:.+]] = hidden {{.*}}global i32 0, align 4
-// CHECK: !omp_offload.info = !{!0}
-// CHECK: !0 = !{i32 1, !"[[G]]", i32 0, i32 0}
Index: clang/test/OpenMP/declare_target_codegen_globalization.cpp
===================================================================
--- clang/test/OpenMP/declare_target_codegen_globalization.cpp
+++ clang/test/OpenMP/declare_target_codegen_globalization.cpp
@@ -37,11 +37,13 @@
// CHECK: define {{.*}}[[BAR]]()
// CHECK: alloca i32,
// CHECK: [[A_LOCAL_ADDR:%.+]] = alloca i32,
+// CHECK: [[IS_IN_PAR:%.+]] = icmp eq i16 {{.*}}, 0
// CHECK: [[RES:%.+]] = call i8 @__kmpc_is_spmd_exec_mode()
// CHECK: [[IS_SPMD:%.+]] = icmp ne i8 [[RES]], 0
// CHECK: br i1 [[IS_SPMD]], label
// CHECK: br label
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_data_sharing_coalesced_push_stack(i64 128, i16 0)
+// CHECK: [[STACK_SIZE:%.+]] = select i1 [[IS_IN_PAR]], i64 4, i64 128
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_data_sharing_coalesced_push_stack(i64 [[STACK_SIZE]], i16 0)
// CHECK: [[GLOBALS:%.+]] = bitcast i8* [[RES]] to [[GLOBAL_ST:%.+]]*
// CHECK: br label
// CHECK: [[ITEMS:%.+]] = phi [[GLOBAL_ST]]* [ null, {{.+}} ], [ [[GLOBALS]], {{.+}} ]
@@ -49,7 +51,9 @@
// CHECK: [[TID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
// CHECK: [[LID:%.+]] = and i32 [[TID]], 31
// CHECK: [[A_GLOBAL_ADDR:%.+]] = getelementptr inbounds [32 x i32], [32 x i32]* [[A_ADDR]], i32 0, i32 [[LID]]
-// CHECK: [[A_ADDR:%.+]] = select i1 [[IS_SPMD]], i32* [[A_LOCAL_ADDR]], i32* [[A_GLOBAL_ADDR]]
+// CHECK: [[A_GLOBAL_ADDR_SINGLE:%.+]] = getelementptr inbounds %struct._globalized_locals_ty.0, %struct._globalized_locals_ty.0* %{{.*}}, i32 0, i32 0
+// CHECK: [[A_GLOBAL_ADDR_SEL:%.+]] = select i1 [[IS_IN_PAR]], i32* [[A_GLOBAL_ADDR_SINGLE]], i32* [[A_GLOBAL_ADDR]]
+// CHECK: [[A_ADDR:%.+]] = select i1 [[IS_SPMD]], i32* [[A_LOCAL_ADDR]], i32* [[A_GLOBAL_ADDR_SEL]]
// CHECK: call {{.*}}[[FOO]](i32* nonnull align {{[0-9]+}} dereferenceable{{.*}} [[A_ADDR]])
// CHECK: br i1 [[IS_SPMD]], label
// CHECK: [[BC:%.+]] = bitcast [[GLOBAL_ST]]* [[ITEMS]] to i8*
Index: clang/test/OpenMP/declare_target_codegen.cpp
===================================================================
--- clang/test/OpenMP/declare_target_codegen.cpp
+++ clang/test/OpenMP/declare_target_codegen.cpp
@@ -40,7 +40,6 @@
// CHECK-DAG: @pair = {{.*}}addrspace(3) global %struct.PAIR undef
// CHECK-DAG: @b ={{ hidden | }}global i32 15,
// CHECK-DAG: @d ={{ hidden | }}global i32 0,
-// CHECK-DAG: @c = external global i32,
// CHECK-DAG: @globals ={{ hidden | }}global %struct.S zeroinitializer,
// CHECK-DAG: [[STAT:@.+stat]] = internal global %struct.S zeroinitializer,
// CHECK-DAG: [[STAT_REF:@.+]] = internal constant %struct.S* [[STAT]]
@@ -252,17 +251,41 @@
// CHECK-DAG: !{{{.+}}virtual_foo
#ifdef OMP5
-void host_fun() {}
-#pragma omp declare target to(host_fun) device_type(host)
-void device_fun() {}
-#pragma omp declare target to(device_fun) device_type(nohost)
-// HOST5-NOT: define {{.*}}void {{.*}}device_fun{{.*}}
-// HOST5: define {{.*}}void {{.*}}host_fun{{.*}}
-// HOST5-NOT: define {{.*}}void {{.*}}device_fun{{.*}}
-
-// DEV5-NOT: define {{.*}}void {{.*}}host_fun{{.*}}
-// DEV5: define {{.*}}void {{.*}}device_fun{{.*}}
-// DEV5-NOT: define {{.*}}void {{.*}}host_fun{{.*}}
+void host_fun1() {}
+#pragma omp declare target to(host_fun1) device_type(host)
+void device_fun1() {}
+#pragma omp declare target to(device_fun1) device_type(nohost)
+// HOST5-NOT: define {{.*}}void {{.*}}device_fun1{{.*}}
+// HOST5: define {{.*}}void {{.*}}host_fun1{{.*}}
+// HOST5-NOT: define {{.*}}void {{.*}}device_fun1{{.*}}
+
+// DEV5-NOT: define {{.*}}void {{.*}}host_fun1{{.*}}
+// DEV5: define {{.*}}void {{.*}}device_fun1{{.*}}
+// DEV5-NOT: define {{.*}}void {{.*}}host_fun1{{.*}}
+
+// Implicit declaration with the "wrong" device type first,
+// explicit declaration afterwards.
+#pragma omp begin declare target device_type(nohost)
+void host_fun2() {}
+#pragma omp end declare target
+#pragma omp begin declare target device_type(host)
+void device_fun2() {}
+#pragma omp end declare target
+
+// TODO: According to OpenMP 5.1 this is an OK use, arguably this
+// is not really useful and makes it hard/costly to implement.
+// We should remove the non-begin/end forms in OpenMP 6.0.
+#pragma omp declare target to(host_fun2) device_type(host)
+#pragma omp declare target to(device_fun2) device_type(nohost)
+
+// HOST5-NOT: define {{.*}}void {{.*}}device_fun2{{.*}}
+// HOST5: define {{.*}}void {{.*}}host_fun2{{.*}}
+// HOST5-NOT: define {{.*}}void {{.*}}device_fun2{{.*}}
+
+// DEV5-NOT: define {{.*}}void {{.*}}host_fun2{{.*}}
+// DEV5: define {{.*}}void {{.*}}device_fun2{{.*}}
+// DEV5-NOT: define {{.*}}void {{.*}}host_fun2{{.*}}
+
#endif // OMP5
struct PAIR {
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -2477,8 +2477,8 @@
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl());
// Ignore host functions during device analyzis.
- if (LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ if (LangOpts.OpenMPIsDevice &&
+ (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host))
return;
// Ignore nohost functions during host analyzis.
if (!LangOpts.OpenMPIsDevice && DevTy &&
@@ -19968,7 +19968,8 @@
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
}
-bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
+bool Sema::ActOnStartOpenMPDeclareTargetContext(
+ DeclareTargetContextInfo &DTCI) {
DeclContext *CurLexicalContext = getCurLexicalContext();
if (!CurLexicalContext->isFileContext() &&
!CurLexicalContext->isExternCContext() &&
@@ -19977,23 +19978,28 @@
!isa<ClassTemplateDecl>(CurLexicalContext) &&
!isa<ClassTemplatePartialSpecializationDecl>(CurLexicalContext) &&
!isa<ClassTemplateSpecializationDecl>(CurLexicalContext)) {
- Diag(Loc, diag::err_omp_region_not_file_context);
+ Diag(DTCI.Loc, diag::err_omp_region_not_file_context);
return false;
}
- DeclareTargetNesting.push_back(Loc);
+ DeclareTargetNesting.push_back(DTCI);
return true;
}
-void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
- assert(!DeclareTargetNesting.empty() &&
- "Unexpected ActOnFinishOpenMPDeclareTargetDirective");
- DeclareTargetNesting.pop_back();
+const Sema::DeclareTargetContextInfo Sema::ActOnOpenMPEndDeclareTargetDirective() {
+ assert(!DeclareTargetNesting.empty() && "check isInOpenMPDeclareTargetContext() first!");
+ return DeclareTargetNesting.pop_back_val();
+}
+
+void Sema::ActOnFinishedOpenMPDeclareTargetContext(
+ DeclareTargetContextInfo &DTCI) {
+ for (auto &It : DTCI.ExplicitlyMapped)
+ ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT,
+ DTCI.DT);
}
-NamedDecl *
-Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
- NamedDeclSetType &SameDirectiveDecls) {
+NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
@@ -20022,8 +20028,6 @@
Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
return nullptr;
}
- if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
- Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
return ND;
}
@@ -20040,32 +20044,35 @@
(ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced()))
Diag(Loc, diag::warn_omp_declare_target_after_first_use);
+ // Explicit declare target lists have precedence.
+ const unsigned Level = -1;
+
auto *VD = cast<ValueDecl>(ND);
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(VD);
- Optional<SourceLocation> AttrLoc = OMPDeclareTargetDeclAttr::getLocation(VD);
- if (DevTy.hasValue() && *DevTy != DT &&
- (DeclareTargetNesting.empty() ||
- *AttrLoc != DeclareTargetNesting.back())) {
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ OMPDeclareTargetDeclAttr::getActiveAttr(VD);
+ if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DT &&
+ ActiveAttr.getValue()->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT)
- << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy);
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
+ ActiveAttr.getValue()->getDevType());
return;
}
- Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res || (!DeclareTargetNesting.empty() &&
- *AttrLoc == DeclareTargetNesting.back())) {
- auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, MT, DT, DeclareTargetNesting.size() + 1,
- SourceRange(Loc, Loc));
- ND->addAttr(A);
- if (ASTMutationListener *ML = Context.getASTMutationListener())
- ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
- checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc);
- } else if (*Res != MT) {
+ if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getMapType() != MT &&
+ ActiveAttr.getValue()->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
+ return;
}
+
+ if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() == Level)
+ return;
+
+ auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT, Level,
+ SourceRange(Loc, Loc));
+ ND->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc);
}
static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
@@ -20079,8 +20086,6 @@
(SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
VD->hasGlobalStorage()) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
// OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
// If a lambda declaration and definition appears between a
@@ -20144,15 +20149,19 @@
if ((E || !VD->getType()->isIncompleteType()) &&
!checkValueDeclInTarget(SL, SR, *this, DSAStack, VD))
return;
- if (!E && !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
+ if (!E && isInOpenMPDeclareTargetContext()) {
// Checking declaration inside declare target region.
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ OMPDeclareTargetDeclAttr::getActiveAttr(VD);
+ unsigned Level = DeclareTargetNesting.size();
+ if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() >= Level)
+ return;
+ DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To,
- OMPDeclareTargetDeclAttr::DT_Any, DeclareTargetNesting.size(),
- SourceRange(DeclareTargetNesting.back(),
- DeclareTargetNesting.back()));
+ Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, Level,
+ SourceRange(DTCI.Loc, DTCI.Loc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -18435,7 +18435,7 @@
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
// DevTy may be changed later by
// #pragma omp declare target to(*) device_type(*).
- // Therefore DevTyhaving no value does not imply host. The emission status
+ // Therefore DevTy having no value does not imply host. The emission status
// will be checked again at the end of compilation unit with Final = true.
if (DevTy.hasValue())
if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
Index: clang/lib/Parse/ParseOpenMP.cpp
===================================================================
--- clang/lib/Parse/ParseOpenMP.cpp
+++ clang/lib/Parse/ParseOpenMP.cpp
@@ -131,6 +131,7 @@
{OMPD_declare, OMPD_simd, OMPD_declare_simd},
{OMPD_declare, OMPD_target, OMPD_declare_target},
{OMPD_declare, OMPD_variant, OMPD_declare_variant},
+ {OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target},
{OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},
{OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},
{OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
@@ -1664,30 +1665,41 @@
return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);
}
-Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
- // OpenMP 4.5 syntax with list of entities.
- Sema::NamedDeclSetType SameDirectiveDecls;
- SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation,
- NamedDecl *>,
- 4>
- DeclareTargetDecls;
- OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any;
+void Parser::ParseOMPDeclareTargetClauses(
+ Sema::DeclareTargetContextInfo &DTCI) {
SourceLocation DeviceTypeLoc;
+ bool RequiresToOrLinkClause = false;
+ bool HasToOrLinkClause = false;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;
- if (Tok.is(tok::identifier)) {
+ bool HasIdentifier = Tok.is(tok::identifier);
+ if (HasIdentifier) {
+ // If we see any clause we need a to or link clause.
+ RequiresToOrLinkClause = true;
IdentifierInfo *II = Tok.getIdentifierInfo();
StringRef ClauseName = II->getName();
bool IsDeviceTypeClause =
getLangOpts().OpenMP >= 50 &&
getOpenMPClauseKind(ClauseName) == OMPC_device_type;
- // Parse 'to|link|device_type' clauses.
- if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) &&
- !IsDeviceTypeClause) {
+
+ bool IsToOrLinkClause =
+ OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);
+ assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!");
+
+ if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) {
Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
- << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0);
+ << ClauseName << 0;
break;
}
+ if (!IsDeviceTypeClause && !IsToOrLinkClause) {
+ Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
+ << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1);
+ break;
+ }
+
+ if (IsToOrLinkClause)
+ HasToOrLinkClause = true;
+
// Parse 'device_type' clause and go to next clause if any.
if (IsDeviceTypeClause) {
Optional<SimpleClauseData> DevTypeData =
@@ -1697,16 +1709,17 @@
// We already saw another device_type clause, diagnose it.
Diag(DevTypeData.getValue().Loc,
diag::warn_omp_more_one_device_type_clause);
+ break;
}
switch (static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) {
case OMPC_DEVICE_TYPE_any:
- DT = OMPDeclareTargetDeclAttr::DT_Any;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;
break;
case OMPC_DEVICE_TYPE_host:
- DT = OMPDeclareTargetDeclAttr::DT_Host;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host;
break;
case OMPC_DEVICE_TYPE_nohost:
- DT = OMPDeclareTargetDeclAttr::DT_NoHost;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost;
break;
case OMPC_DEVICE_TYPE_unknown:
llvm_unreachable("Unexpected device_type");
@@ -1717,37 +1730,47 @@
}
ConsumeToken();
}
- auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls](
- CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
- NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName(
- getCurScope(), SS, NameInfo, SameDirectiveDecls);
- if (ND)
- DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND);
- };
- if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
- /*AllowScopeSpecifier=*/true))
+
+ if (DTCI.Kind == OMPD_declare_target || HasIdentifier) {
+ auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS,
+ DeclarationNameInfo NameInfo) {
+ NamedDecl *ND =
+ Actions.lookupOpenMPDeclareTargetName(getCurScope(), SS, NameInfo);
+ if (!ND)
+ return;
+ Sema::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()};
+ bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second;
+ if (!FirstMapping)
+ Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple)
+ << NameInfo.getName();
+ };
+ if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
+ /*AllowScopeSpecifier=*/true))
+ break;
+ }
+
+ if (Tok.is(tok::l_paren)) {
+ Diag(Tok,
+ diag::err_omp_begin_declare_target_unexpected_implicit_to_clause);
+ break;
+ }
+ if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok,
+ diag::err_omp_declare_target_unexpected_clause_after_implicit_to);
break;
+ }
// Consume optional ','.
if (Tok.is(tok::comma))
ConsumeToken();
}
+
+ // For declare target require at least 'to' or 'link' to be present.
+ if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause &&
+ !HasToOrLinkClause)
+ Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause);
+
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
- ConsumeAnyToken();
- for (auto &MTLocDecl : DeclareTargetDecls) {
- OMPDeclareTargetDeclAttr::MapTypeTy MT;
- SourceLocation Loc;
- NamedDecl *ND;
- std::tie(MT, Loc, ND) = MTLocDecl;
- // device_type clause is applied only to functions.
- Actions.ActOnOpenMPDeclareTargetName(
- ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT);
- }
- SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(),
- SameDirectiveDecls.end());
- if (Decls.empty())
- return DeclGroupPtrTy();
- return Actions.BuildDeclaratorGroup(Decls);
}
void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) {
@@ -1784,10 +1807,11 @@
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
-void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
+void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,
+ OpenMPDirectiveKind EndDKind,
SourceLocation DKLoc) {
- parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind,
- DKLoc, Tok.getLocation(),
+ parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc,
+ Tok.getLocation(),
/* SkipUntilOpenMPEnd */ false);
// Skip the last annot_pragma_openmp_end.
if (Tok.is(tok::annot_pragma_openmp_end))
@@ -2101,53 +2125,41 @@
ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);
return Ptr;
}
+ case OMPD_begin_declare_target:
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
- if (Tok.isNot(tok::annot_pragma_openmp_end)) {
- return ParseOMPDeclareTargetClauses();
- }
+ bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
+ bool HasImplicitMappings =
+ DKind == OMPD_begin_declare_target || !HasClauses;
+ Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc);
+ if (HasClauses)
+ ParseOMPDeclareTargetClauses(DTCI);
// Skip the last annot_pragma_openmp_end.
ConsumeAnyToken();
- if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc))
- return DeclGroupPtrTy();
-
- ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
- llvm::SmallVector<Decl *, 4> Decls;
- while (Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) {
- if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
- TentativeParsingAction TPA(*this);
- ConsumeAnnotationToken();
- DKind = parseOpenMPDirectiveKind(*this);
- if (DKind != OMPD_end_declare_target)
- TPA.Revert();
- else
- TPA.Commit();
- }
- if (DKind == OMPD_end_declare_target)
- break;
- DeclGroupPtrTy Ptr;
- // Here we expect to see some function declaration.
- if (AS == AS_none) {
- assert(TagType == DeclSpec::TST_unspecified);
- MaybeParseCXX11Attributes(Attrs);
- ParsingDeclSpec PDS(*this);
- Ptr = ParseExternalDeclaration(Attrs, &PDS);
- } else {
- Ptr =
- ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
- }
- if (Ptr) {
- DeclGroupRef Ref = Ptr.get();
- Decls.append(Ref.begin(), Ref.end());
- }
+ if (HasImplicitMappings) {
+ Actions.ActOnStartOpenMPDeclareTargetContext(DTCI);
+ return nullptr;
}
- ParseOMPEndDeclareTargetDirective(DKind, DTLoc);
- Actions.ActOnFinishOpenMPDeclareTargetDirective();
+ Actions.ActOnFinishedOpenMPDeclareTargetContext(DTCI);
+ llvm::SmallVector<Decl *, 4> Decls;
+ for (auto &It : DTCI.ExplicitlyMapped)
+ Decls.push_back(It.first);
return Actions.BuildDeclaratorGroup(Decls);
}
+ case OMPD_end_declare_target: {
+ if (!Actions.isInOpenMPDeclareTargetContext()) {
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << 1 << getOpenMPDirectiveName(DKind);
+ break;
+ }
+ const Sema::DeclareTargetContextInfo &DTCI =
+ Actions.ActOnOpenMPEndDeclareTargetDirective();
+ ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);
+ return nullptr;
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@@ -2191,7 +2203,6 @@
case OMPD_parallel_master_taskloop:
case OMPD_parallel_master_taskloop_simd:
case OMPD_distribute:
- case OMPD_end_declare_target:
case OMPD_target_update:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
@@ -2570,6 +2581,7 @@
}
case OMPD_declare_simd:
case OMPD_declare_target:
+ case OMPD_begin_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
case OMPD_begin_declare_variant:
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1356,6 +1356,10 @@
/// \param D Requires declaration
void EmitOMPRequiresDecl(const OMPRequiresDecl *D);
+ /// Emit a code for the allocate directive.
+ /// \param D The allocate declaration
+ void EmitOMPAllocateDecl(const OMPAllocateDecl *D);
+
/// Returns whether the given record has hidden LTO visibility and therefore
/// may participate in (single-module) CFI and whole-program vtable
/// optimization.
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2669,19 +2669,24 @@
}
bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
+ // In OpenMP 5.0 variables and function may be marked as
+ // device_type(host/nohost) and we should not emit them eagerly unless we sure
+ // that they must be emitted on the host/device. To be sure we need to have
+ // seen a declare target with an explicit mentioning of the function, we know
+ // we have if the level of the declare target attribute is -1. Note that we
+ // check somewhere else if we should emit this at all.
+ if (LangOpts.OpenMP >= 50 && !LangOpts.OpenMPSimd) {
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ OMPDeclareTargetDeclAttr::getActiveAttr(Global);
+ if (!ActiveAttr || (*ActiveAttr)->getLevel() != (unsigned)-1)
+ return false;
+ }
+
if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
// Implicit template instantiations may change linkage if they are later
// explicitly instantiated, so they should not be emitted eagerly.
return false;
- // In OpenMP 5.0 function may be marked as device_type(nohost) and we should
- // not emit them eagerly unless we sure that the function must be emitted on
- // the host.
- if (LangOpts.OpenMP >= 50 && !LangOpts.OpenMPSimd &&
- !LangOpts.OpenMPIsDevice &&
- !OMPDeclareTargetDeclAttr::getDeviceType(FD) &&
- !FD->isUsed(/*CheckUsedAttr=*/false) && !FD->isReferenced())
- return false;
}
if (const auto *VD = dyn_cast<VarDecl>(Global))
if (Context.getInlineVariableDefinitionKind(VD) ==
@@ -4357,7 +4362,8 @@
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, Entry->getType());
+ llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV,
+ Entry->getType());
Entry->replaceAllUsesWith(NewPtrForOldDecl);
// Erase the old global, since it is no longer used.
@@ -5868,6 +5874,7 @@
break;
case Decl::OMPAllocate:
+ EmitOMPAllocateDecl(cast<OMPAllocateDecl>(D));
break;
case Decl::OMPDeclareReduction:
Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -15,6 +15,7 @@
#include "CGCleanup.h"
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
+#include "clang/AST/APValue.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/OpenMPClause.h"
@@ -2996,8 +2997,7 @@
if (CGM.getLangOpts().OpenMPIsDevice) {
// This could happen if the device compilation is invoked standalone.
if (!hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum))
- initializeTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum,
- OffloadingEntriesNum);
+ return;
auto &Entry =
OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum];
Entry.setAddress(Addr);
@@ -3068,10 +3068,8 @@
if (CGM.getLangOpts().OpenMPIsDevice) {
// This could happen if the device compilation is invoked standalone.
if (!hasDeviceGlobalVarEntryInfo(VarName))
- initializeDeviceGlobalVarEntryInfo(VarName, Flags, OffloadingEntriesNum);
+ return;
auto &Entry = OffloadEntriesDeviceGlobalVar[VarName];
- assert((!Entry.getAddress() || Entry.getAddress() == Addr) &&
- "Resetting with the new address.");
if (Entry.getAddress() && hasDeviceGlobalVarEntryInfo(VarName)) {
if (Entry.getVarSize().isZero()) {
Entry.setVarSize(VarSize);
@@ -3087,8 +3085,6 @@
auto &Entry = OffloadEntriesDeviceGlobalVar[VarName];
assert(Entry.isValid() && Entry.getFlags() == Flags &&
"Entry not initialized!");
- assert((!Entry.getAddress() || Entry.getAddress() == Addr) &&
- "Resetting with the new address.");
if (Entry.getVarSize().isZero()) {
Entry.setVarSize(VarSize);
Entry.setLinkage(Linkage);
@@ -10516,17 +10512,28 @@
scanForTargetRegionsFunctions(II, ParentName);
}
+static bool isAssumedToBeNotEmitted(const ValueDecl *VD, bool IsDevice) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(VD);
+ if (!DevTy)
+ return false;
+ // Do not emit device_type(nohost) functions for the host.
+ if (!IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ return true;
+ // Do not emit device_type(host) functions for the device.
+ if (IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return true;
+ return false;
+}
+
bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
// If emitting code for the host, we do not process FD here. Instead we do
// the normal code generation.
if (!CGM.getLangOpts().OpenMPIsDevice) {
- if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl())) {
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- // Do not emit device_type(nohost) functions for the host.
- if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl()))
+ if (isAssumedToBeNotEmitted(cast<ValueDecl>(FD),
+ CGM.getLangOpts().OpenMPIsDevice))
return true;
- }
return false;
}
@@ -10535,10 +10542,8 @@
if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
StringRef Name = CGM.getMangledName(GD);
scanForTargetRegionsFunctions(FD->getBody(), Name);
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- // Do not emit device_type(nohost) functions for the host.
- if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ if (isAssumedToBeNotEmitted(cast<ValueDecl>(FD),
+ CGM.getLangOpts().OpenMPIsDevice))
return true;
}
@@ -10548,6 +10553,10 @@
}
bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
+ if (isAssumedToBeNotEmitted(cast<ValueDecl>(GD.getDecl()),
+ CGM.getLangOpts().OpenMPIsDevice))
+ return true;
+
if (!CGM.getLangOpts().OpenMPIsDevice)
return false;
@@ -10620,6 +10629,13 @@
if (CGM.getLangOpts().OMPTargetTriples.empty() &&
!CGM.getLangOpts().OpenMPIsDevice)
return;
+
+ // If we have host/nohost variables, they do not need to be registered.
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(VD);
+ if (DevTy && DevTy.getValue() != OMPDeclareTargetDeclAttr::DT_Any)
+ return;
+
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res) {
@@ -10650,6 +10666,10 @@
Linkage = CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false);
// Temp solution to prevent optimizations of the internal variables.
if (CGM.getLangOpts().OpenMPIsDevice && !VD->isExternallyVisible()) {
+ // Do not create a "ref-variable" if the original is not also available
+ // on the host.
+ if (!OffloadEntriesInfoManager.hasDeviceGlobalVarEntryInfo(VarName))
+ return;
std::string RefName = getName({VarName, "ref"});
if (!CGM.GetGlobalValue(RefName)) {
llvm::Constant *AddrRef =
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -2612,3 +2612,12 @@
void CodeGenModule::EmitOMPRequiresDecl(const OMPRequiresDecl *D) {
getOpenMPRuntime().processRequiresDirective(D);
}
+
+void CodeGenModule::EmitOMPAllocateDecl(const OMPAllocateDecl *D) {
+ for (const Expr *E : D->varlists()) {
+ auto *DE = cast<DeclRefExpr>(E);
+ auto *VD = cast<VarDecl>(DE->getDecl());
+ if (VD->hasGlobalStorage())
+ EmitGlobalVarDefinition(VD);
+ }
+}
Index: clang/lib/AST/AttrImpl.cpp
===================================================================
--- clang/lib/AST/AttrImpl.cpp
+++ clang/lib/AST/AttrImpl.cpp
@@ -141,57 +141,44 @@
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
}
-llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
-OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
+llvm::Optional<OMPDeclareTargetDeclAttr *>
+OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
if (!VD->hasAttrs())
return llvm::None;
unsigned Level = 0;
- const OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
- for (const auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
- if (Level < Attr->getLevel()) {
+ OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
+ for (auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
+ if (Level <= Attr->getLevel()) {
Level = Attr->getLevel();
FoundAttr = Attr;
}
}
if (FoundAttr)
- return FoundAttr->getMapType();
+ return FoundAttr;
+ return llvm::None;
+}
+llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
+OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ if (ActiveAttr.hasValue())
+ return ActiveAttr.getValue()->getMapType();
return llvm::None;
}
llvm::Optional<OMPDeclareTargetDeclAttr::DevTypeTy>
OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
- if (!VD->hasAttrs())
- return llvm::None;
- unsigned Level = 0;
- const OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
- for (const auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
- if (Level < Attr->getLevel()) {
- Level = Attr->getLevel();
- FoundAttr = Attr;
- }
- }
- if (FoundAttr)
- return FoundAttr->getDevType();
-
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ if (ActiveAttr.hasValue())
+ return ActiveAttr.getValue()->getDevType();
return llvm::None;
}
llvm::Optional<SourceLocation>
OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
- if (!VD->hasAttrs())
- return llvm::None;
- unsigned Level = 0;
- const OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
- for (const auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
- if (Level < Attr->getLevel()) {
- Level = Attr->getLevel();
- FoundAttr = Attr;
- }
- }
- if (FoundAttr)
- return FoundAttr->getRange().getBegin();
-
+ llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ if (ActiveAttr.hasValue())
+ return ActiveAttr.getValue()->getRange().getBegin();
return llvm::None;
}
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10202,8 +10202,31 @@
//
private:
void *VarDataSharingAttributesStack;
+
+ struct DeclareTargetContextInfo {
+ struct MapInfo {
+ OMPDeclareTargetDeclAttr::MapTypeTy MT;
+ SourceLocation Loc;
+ };
+ /// Explicitly listed variables and functions in a 'to' or 'link' clause.
+ llvm::DenseMap<NamedDecl *, MapInfo> ExplicitlyMapped;
+
+ /// The 'device_type' as parsed from the clause.
+ OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any;
+
+ /// The directive kind, `begin declare target` or `declare target`.
+ OpenMPDirectiveKind Kind;
+
+ /// The directive location.
+ SourceLocation Loc;
+
+ DeclareTargetContextInfo(OpenMPDirectiveKind Kind, SourceLocation Loc)
+ : Kind(Kind), Loc(Loc) {}
+ };
+
/// Number of nested '#pragma omp declare target' directives.
- SmallVector<SourceLocation, 4> DeclareTargetNesting;
+ SmallVector<DeclareTargetContextInfo, 4> DeclareTargetNesting;
+
/// Initialization of data-sharing attributes stack.
void InitDataSharingAttributesStack();
void DestroyDataSharingAttributesStack();
@@ -10469,19 +10492,28 @@
const ValueDecl *getOpenMPDeclareMapperVarName() const;
/// Called on the start of target region i.e. '#pragma omp declare target'.
- bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc);
- /// Called at the end of target region i.e. '#pragme omp end declare target'.
- void ActOnFinishOpenMPDeclareTargetDirective();
+ bool ActOnStartOpenMPDeclareTargetContext(DeclareTargetContextInfo &DTCI);
+
+ /// Called at the end of target region i.e. '#pragma omp end declare target'.
+ const DeclareTargetContextInfo ActOnOpenMPEndDeclareTargetDirective();
+
+ /// Called once a target context is completed, that can be when a
+ /// '#pragma omp end declare target' was encountered or when a
+ /// '#pragma omp declare target' without declaration-definition-seq was
+ /// encountered.
+ void ActOnFinishedOpenMPDeclareTargetContext(DeclareTargetContextInfo &DTCI);
+
/// Searches for the provided declaration name for OpenMP declare target
/// directive.
- NamedDecl *
- lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
- NamedDeclSetType &SameDirectiveDecls);
+ NamedDecl *lookupOpenMPDeclareTargetName(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id);
+
/// Called on correct id-expression from the '#pragma omp declare target'.
void ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
OMPDeclareTargetDeclAttr::MapTypeTy MT,
OMPDeclareTargetDeclAttr::DevTypeTy DT);
+
/// Check declaration inside target region.
void
checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -3181,10 +3181,12 @@
/// Parse 'omp end assumes' directive.
void ParseOpenMPEndAssumesDirective(SourceLocation Loc);
- /// Parse clauses for '#pragma omp declare target'.
- DeclGroupPtrTy ParseOMPDeclareTargetClauses();
+ /// Parse clauses for '#pragma omp [begin] declare target'.
+ void ParseOMPDeclareTargetClauses(Sema::DeclareTargetContextInfo &DTCI);
+
/// Parse '#pragma omp end declare target'.
- void ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
+ void ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,
+ OpenMPDirectiveKind EndDKind,
SourceLocation Loc);
/// Skip tokens until a `annot_pragma_openmp_end` was found. Emit a warning if
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10220,8 +10220,6 @@
InGroup<OpenMPClauses>;
def err_omp_invalid_target_decl : Error<
"%0 used in declare target directive is not a variable or a function name">;
-def err_omp_declare_target_multiple : Error<
- "%0 appears multiple times in clauses on the same declare target directive">;
def err_omp_declare_target_to_and_link : Error<
"%0 must not appear in both clauses 'to' and 'link'">;
def warn_omp_not_in_target_context : Warning<
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1313,7 +1313,15 @@
def note_omp_assumption_clause_continue_here
: Note<"the ignored tokens spans until here">;
def err_omp_declare_target_unexpected_clause: Error<
- "unexpected '%0' clause, only %select{'to' or 'link'|'to', 'link' or 'device_type'}1 clauses expected">;
+ "unexpected '%0' clause, only %select{'device_type'|'to' or 'link'|'to', 'link' or 'device_type'}1 clauses expected">;
+def err_omp_begin_declare_target_unexpected_implicit_to_clause: Error<
+ "unexpected '(', only 'to', 'link' or 'device_type' clauses expected for 'begin declare target' directive">;
+def err_omp_declare_target_unexpected_clause_after_implicit_to: Error<
+ "unexpected clause after an implicit 'to' clause">;
+def err_omp_declare_target_missing_to_or_link_clause: Error<
+ "expected at least one 'to' or 'link' clause">;
+def err_omp_declare_target_multiple : Error<
+ "%0 appears multiple times in clauses on the same declare target directive">;
def err_omp_expected_clause: Error<
"expected at least one clause on '#pragma omp %0' directive">;
def err_omp_mapper_illegal_identifier : Error<
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3597,6 +3597,7 @@
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const;
static llvm::Optional<MapTypeTy>
isDeclareTargetDeclaration(const ValueDecl *VD);
+ static llvm::Optional<OMPDeclareTargetDeclAttr*> getActiveAttr(const ValueDecl *VD);
static llvm::Optional<DevTypeTy> getDeviceType(const ValueDecl *VD);
static llvm::Optional<SourceLocation> getLocation(const ValueDecl *VD);
}];
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits