| // RUN: %clang_cc1 -verify -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu \ |
| // RUN: -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s |
| |
| // RUN %clang_cc1 -verify -fopenmp -fopenmp-targets=i386-pc-linux-gnu \ |
| // RUN -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s |
| |
| // expected-no-diagnostics |
| |
| // Tests that const-qualified aggregates without mutable members are implicitly |
| // mapped as 'to' instead of 'tofrom' under defaultmap(tofrom:aggregate) and |
| // explicit map clauses. Structs that have mutable members, or that are |
| // non-const, must continue to be mapped 'tofrom'. |
| |
| struct foo { |
| foo(int j) : i(j) {}; |
| int i; |
| }; |
| |
| struct foo_mutable { |
| foo_mutable(int j) : i(j), m(0) {}; |
| int i; |
| mutable int m; |
| }; |
| |
| // TODO: A const foo_mutable should ideally only copy back its mutable |
| // member 'm' and ignore non-mutable member 'i' on a 'from' mapping, per |
| // OpenMP 6.0 p299 lines 3-4. This requires per-member mapper generation |
| // and is left for a follow-up patch. |
| struct foo_nested { |
| foo_nested(int j) : inner(j), z(j) {}; |
| foo inner; |
| const int z; |
| }; |
| |
| struct foo_nested_mutable { |
| foo_nested_mutable(int j) : inner(j), z(j) {}; |
| foo_mutable inner; // has mutable member buried inside |
| const int z; |
| }; |
| |
| // CHECK: @.offload_maptypes = private unnamed_addr constant [2 x i64] [i64 545, i64 288] |
| // CHECK: @.offload_maptypes.2 = private unnamed_addr constant [2 x i64] [i64 547, i64 288] |
| // CHECK: @.offload_maptypes.4 = private unnamed_addr constant [2 x i64] [i64 547, i64 288] |
| // CHECK: @.offload_maptypes.6 = private unnamed_addr constant [2 x i64] [i64 545, i64 288] |
| // CHECK: @.offload_maptypes.8 = private unnamed_addr constant [2 x i64] [i64 547, i64 288] |
| // CHECK: @.offload_maptypes.10 = private unnamed_addr constant [2 x i64] [i64 545, i64 288] |
| // CHECK: @.offload_maptypes.12 = private unnamed_addr constant [2 x i64] [i64 33, i64 288] |
| // CHECK: @.offload_maptypes.14 = private unnamed_addr constant [2 x i64] [i64 32, i64 288] |
| // CHECK: @.offload_maptypes.16 = private unnamed_addr constant [2 x i64] [i64 33, i64 288] |
| // CHECK: @.offload_maptypes.18 = private unnamed_addr constant [1 x i64] [i64 2] |
| // CHECK: @.offload_maptypes.20 = private unnamed_addr constant [1 x i64] [i64 2] |
| // CHECK: @.offload_maptypes.22 = private unnamed_addr constant [1 x i64] [i64 2] |
| // CHECK: @.offload_maptypes.24 = private unnamed_addr constant [3 x i64] [i64 545, i64 547, i64 288] |
| // CHECK: @.offload_maptypes.26 = private unnamed_addr constant [2 x i64] [i64 545, i64 288] |
| // CHECK: @.offload_maptypes.28 = private unnamed_addr constant [1 x i64] [i64 2] |
| |
| // --------------------------------------------------------------------------- |
| // Implicit mapping tests (no explicit map clause, defaultmap governs) |
| // --------------------------------------------------------------------------- |
| |
| // Const struct with no mutable members. Mapped as TO|TARGET_PARAM|IMPLICIT = 545. |
| // LABEL: test_const_no_mutable |
| // CHECK: store ptr @.offload_maptypes, ptr {{.*}}, align 8 |
| void test_const_no_mutable() { |
| const foo a(2); |
| #pragma omp target |
| { |
| int x = a.i; |
| } |
| } |
| |
| // Non-const struct. Mapped as TO|FROM|TARGET_PARAM|IMPLICIT = 547. |
| // LABEL: define dso_local void @_Z13test_nonconstv |
| // CHECK: store ptr @.offload_maptypes.2, ptr {{.*}}, align 8 |
| void test_nonconst() { |
| foo a(2); |
| #pragma omp target |
| { |
| int x = a.i; |
| } |
| } |
| |
| // Const struct with a mutable member. Mapped as TO|FROM|TARGET_PARAM|IMPLICIT = 547. |
| // LABEL: define dso_local void @_Z23test_const_with_mutablev |
| // CHECK: store ptr @.offload_maptypes.4, ptr {{.*}}, align 8 |
| void test_const_with_mutable() { |
| const foo_mutable a(2); |
| #pragma omp target |
| { |
| a.m = 1; |
| } |
| } |
| |
| // Const struct whose members are themselves all const and free of mutable |
| // fields. Mapped as TO|TARGET_PARAM|IMPLICIT = 545. |
| // LABEL: define dso_local void @_Z17test_const_nestedv() #0 { |
| // CHECK: store ptr @.offload_maptypes.6, ptr {{.*}}, align 8 |
| void test_const_nested() { |
| const foo_nested a(2); |
| #pragma omp target |
| { |
| int x = a.inner.i; |
| } |
| } |
| |
| // Const array of a const-qualified struct type. |
| // Mapped as TO|FROM|TARGET_PARAM|IMPLICIT = 547. |
| // LABEL: define dso_local void @_Z30test_const_nested_with_mutablev |
| // CHECK: store ptr @.offload_maptypes.8, ptr {{.*}}, align 8 |
| void test_const_nested_with_mutable() { |
| const foo_nested_mutable a(2); |
| #pragma omp target |
| { |
| a.inner.m = 1; |
| } |
| } |
| |
| // Const array of a const-qualified struct type. |
| // Mapped as TO|TARGET_PARAM|IMPLICIT = 545. |
| // LABEL: define dso_local void @_Z16test_const_arrayv |
| // CHECK: store ptr @.offload_maptypes.10, ptr {{.*}}, align 8 |
| void test_const_array() { |
| const foo arr[4] = {1, 2, 3, 4}; |
| #pragma omp target |
| { |
| int x = arr[0].i; |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Explicit map clause tests |
| // --------------------------------------------------------------------------- |
| |
| // Explicit map(tofrom:) on a const struct. Mapped as TO|TARGET_PARAM = 33. |
| // LABEL: define dso_local void @_Z27test_explicit_tofrom_const |
| // CHECK: store ptr @.offload_maptypes.12, ptr {{.*}}, align 8 |
| void test_explicit_tofrom_const() { |
| const foo a(2); |
| #pragma omp target map(tofrom:a) |
| { |
| int x = a.i; |
| } |
| } |
| |
| // Explicit map(from:) on a const struct. The FROM clause is ignored. |
| // Mapped as TARGET_PARAM = 32. |
| // LABEL: define dso_local void @_Z24test_explicit_from_constv |
| // CHECK: store ptr @.offload_maptypes.14, ptr {{.*}}, align 8 |
| void test_explicit_from_const() { |
| const foo a(2); |
| #pragma omp target map(from:a) |
| { |
| int x = a.i; |
| } |
| } |
| |
| // Explicit map(to:) on a const struct. Mapped as TO|TARGET_PARAM = 33. |
| // LABEL: define dso_local void @_Z22test_explicit_to_constv() |
| // CHECK: store ptr @.offload_maptypes.16, ptr {{.*}}, align 8 |
| void test_explicit_to_const() { |
| const foo a(2); |
| #pragma omp target map(to:a) |
| { |
| int x = a.i; |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // target update from tests |
| // --------------------------------------------------------------------------- |
| |
| // target update from on a const struct with no mutable members. The FROM clause |
| // is ignored. Mapped as FROM = 2. |
| // LABEL: define dso_local void @_Z29test_target_update_from_constv |
| // CHECK: call void @__tgt_target_data_update_mapper(ptr @1, i64 -1, i32 1, ptr %3, ptr %4, ptr @.offload_sizes.17, ptr @.offload_maptypes.18, ptr null, ptr null) |
| void test_target_update_from_const() { |
| const foo a(2); |
| #pragma omp target update from(a) |
| } |
| |
| // target update from on a non-const struct. Mapped as FROM = 2. |
| // LABEL: define dso_local void @_Z32test_target_update_from_nonconstv |
| // CHECK: call void @__tgt_target_data_update_mapper(ptr @1, i64 -1, i32 1, ptr %3, ptr %4, ptr @.offload_sizes.19, ptr @.offload_maptypes.20, ptr null, ptr null) |
| void test_target_update_from_nonconst() { |
| foo a(2); |
| #pragma omp target update from(a) |
| } |
| |
| // target update from on a const struct that has a mutable member. Mapped as FROM = 2. |
| // LABEL: define dso_local void @_Z37test_target_update_from_const_mutablev |
| // CHECK: call void @__tgt_target_data_update_mapper(ptr @1, i64 -1, i32 1, ptr %3, ptr %4, ptr @.offload_sizes.21, ptr @.offload_maptypes.22, ptr null, ptr null) |
| void test_target_update_from_const_mutable() { |
| const foo_mutable a(2); |
| #pragma omp target update from(a) |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Combined tests |
| // --------------------------------------------------------------------------- |
| |
| // Mixed region with one const and one non-const variable of the same struct |
| // type. Each variable gets its own map type: const maps as |
| // TO|TARGET_PARAM|IMPLICIT = 545, non-const maps as |
| // TO|FROM|TARGET_PARAM|IMPLICIT = 547. |
| // LABEL: define dso_local void @_Z10test_mixedv |
| // CHECK: store ptr @.offload_maptypes.24, ptr {{.*}}, align 8 |
| void test_mixed() { |
| const foo ca(2); |
| foo ma(3); |
| #pragma omp target |
| { |
| int x = ca.i; |
| ma.i = 99; |
| } |
| } |
| |
| // Explicit defaultmap(tofrom:aggregate) directive on a const struct. |
| // Mapped as TO|TARGET_PARAM|IMPLICIT = 545. |
| // LABEL: define dso_local void @_Z31test_defaultmap_tofrom_explicitv |
| // CHECK: store ptr @.offload_maptypes.26, ptr {{.*}}, align 8 |
| void test_defaultmap_tofrom_explicit() { |
| const foo a(2); |
| #pragma omp target defaultmap(tofrom:aggregate) |
| { |
| int x = a.i; |
| } |
| } |
| |
| // User-defined mapper on const struct — FROM must NOT be suppressed because the |
| // mapper accesses non-const pointee data py[0:10]. |
| // Mapped as FROM = 2. |
| // LABEL: define dso_local void @_Z30test_user_defined_mapper_constv |
| // CHECK: call void @__tgt_target_data_update_mapper(ptr @1, i64 -1, i32 1, ptr {{.*}}, ptr {{.*}}, ptr @.offload_sizes.27, ptr @.offload_maptypes.28, ptr null, ptr {{.*}}) |
| int y[10]; |
| struct S { |
| int x; |
| int *py; |
| }; |
| |
| #pragma omp declare mapper(m1: const S s) map(alloc: s.x, s.py) map(from: s.py[0:10]) |
| |
| void test_user_defined_mapper_const() { |
| int data[10] = {0}; |
| const S s1 = {1, data}; |
| #pragma omp target update from(mapper(m1): s1) |
| } |