blob: 326bc812d7d3340765e85b59f2bae7825d529f77 [file] [log] [blame] [edit]
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
/// ========================================================================
/// Test: Firstprivate pointer handling in OpenMP target regions
/// ========================================================================
///
/// This test verifies that pointers with firstprivate semantics get the
/// OMP_MAP_LITERAL flag, enabling the runtime to pass pointer values directly
/// without performing present table lookups.
///
/// Map type values:
/// 288 = OMP_MAP_TARGET_PARAM (32) + OMP_MAP_LITERAL (256)
/// Used for explicit firstprivate(ptr)
///
/// 800 = OMP_MAP_TARGET_PARAM (32) + OMP_MAP_LITERAL (256) + OMP_MAP_IS_PTR (512)
/// Used for implicit firstprivate pointers (e.g., from defaultmap clauses)
/// Note: 512 is OMP_MAP_IS_PTR, not IMPLICIT. Implicitness is tracked separately.
///
/// 544 = OMP_MAP_TARGET_PARAM (32) + OMP_MAP_IS_PTR (512)
/// Incorrect behavior - missing LITERAL flag, causes runtime present table lookup
///
///==========================================================================
/// Test 1: Explicit firstprivate(pointer) → map type 288
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{[^.]*}} = private unnamed_addr constant [1 x i64] [i64 288]
// CHECK-DAG: @.offload_sizes{{[^.]*}} = private unnamed_addr constant [1 x i64] zeroinitializer
void test1_explicit_firstprivate() {
double *ptr = nullptr;
// Explicit firstprivate should generate map type 288
// (TARGET_PARAM | LITERAL, no IS_PTR flag for explicit clauses)
#pragma omp target firstprivate(ptr)
{
if (ptr) ptr[0] = 1.0;
}
}
///==========================================================================
/// Test 2: defaultmap(firstprivate:pointer) → map type 800
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 800]
// CHECK-DAG: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] zeroinitializer
void test2_defaultmap_firstprivate_pointer() {
double *ptr = nullptr;
// defaultmap(firstprivate:pointer) creates implicit firstprivate
// Should generate map type 800 (TARGET_PARAM | LITERAL | IS_PTR)
#pragma omp target defaultmap(firstprivate:pointer)
{
if (ptr) ptr[0] = 2.0;
}
}
///==========================================================================
/// Test 3: defaultmap(firstprivate:scalar) with double → map type 800
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 800]
void test3_defaultmap_scalar_double() {
double d = 3.0;
// OpenMP's "scalar" category excludes pointers but includes arithmetic types
// Double gets implicit firstprivate → map type 800
#pragma omp target defaultmap(firstprivate:scalar)
{
d += 1.0;
}
}
///==========================================================================
/// Test 4: Pointer with defaultmap(firstprivate:scalar) → map type 800
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 800]
// CHECK-DAG: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] zeroinitializer
void test4_pointer_with_scalar_defaultmap() {
double *ptr = nullptr;
// Note: defaultmap(firstprivate:scalar) does NOT apply to pointers (scalar excludes pointers).
// However, the pointer still gets 800 because in OpenMP 5.0+, pointers without explicit
// data-sharing attributes are implicitly firstprivate and lowered as IS_PTR|LITERAL|TARGET_PARAM.
// This is the default pointer behavior, NOT due to the scalar defaultmap.
#pragma omp target defaultmap(firstprivate:scalar)
{
if (ptr) ptr[0] = 4.0;
}
}
///==========================================================================
/// Test 5: Multiple pointers with explicit firstprivate → all get 288
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 288, i64 288, i64 288]
// CHECK-DAG: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] zeroinitializer
void test5_multiple_firstprivate() {
int *a = nullptr;
float *b = nullptr;
double *c = nullptr;
// All explicit firstprivate pointers get map type 288
#pragma omp target firstprivate(a, b, c)
{
if (a) a[0] = 6;
if (b) b[0] = 7.0f;
if (c) c[0] = 8.0;
}
}
///==========================================================================
/// Test 6: Pointer to const with firstprivate → map type 288
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 288]
// CHECK-DAG: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] zeroinitializer
void test6_const_pointer() {
const double *const_ptr = nullptr;
// Const pointer with explicit firstprivate → 288
#pragma omp target firstprivate(const_ptr)
{
if (const_ptr) {
double val = const_ptr[0];
(void)val;
}
}
}
///==========================================================================
/// Test 7: Pointer-to-pointer with firstprivate → map type 288
///==========================================================================
// CHECK-DAG: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 288]
// CHECK-DAG: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] zeroinitializer
void test7_pointer_to_pointer() {
int **pp = nullptr;
// Pointer-to-pointer with explicit firstprivate → 288
#pragma omp target firstprivate(pp)
{
if (pp && *pp) (*pp)[0] = 9;
}
}
///==========================================================================
/// Verification: The key fix is that firstprivate pointers now include
/// the LITERAL flag (256), which tells the runtime to pass the pointer
/// value directly instead of performing a present table lookup.
///
/// Before fix: Pointers got 544 (TARGET_PARAM | IS_PTR) → runtime lookup
/// After fix: Pointers get 288 or 800 (includes LITERAL) → direct pass
///==========================================================================
#endif // HEADER