16 changes: 8 additions & 8 deletions clang/test/OpenMP/nvptx_throw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
* target region but emit a warning instead.
*/

// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -verify=with -Wopenmp-target-exception -analyze

/**
* The following four lines test that no warning is emitted when providing
* -Wno-openmp-target-exception no matter the combination of -fexceptions and
* -fcxx-exceptions.
*/

// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -verify=without -Wno-openmp-target-exception -analyze

/**
* Finally we should test that we only ignore exceptions in the OpenMP
Expand Down
16 changes: 8 additions & 8 deletions clang/test/OpenMP/nvptx_try_catch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
* target region but emit a warning instead.
*/

// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -verify=with -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -verify=with -Wopenmp-target-exception -analyze

/**
* The following four lines test that no warning is emitted when providing
* -Wno-openmp-target-exception no matter the combination of -fexceptions and
* -fcxx-exceptions.
*/

// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fexceptions %s -verify=without -Wno-openmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -verify=without -Wno-openmp-target-exception -analyze

/**
* Finally we should test that we only ignore exceptions in the OpenMP
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/x86_target_exceptions.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// REQUIRES: x86-registered-target, staticanalyzer

// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify -Wopenmp-target-exception -analyze
#pragma omp declare target
int foo(void) {
int error = -1;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/x86_target_throw.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// REQUIRES: x86-registered-target, staticanalyzer

// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify -Wopenmp-target-exception -analyze
#pragma omp declare target
void foo(void) {
throw 404;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/x86_target_try_catch.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// REQUIRES: x86-registered-target, staticanalyzer

// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -verify -Wopenmp-target-exception -analyze
// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -verify -Wopenmp-target-exception -analyze
#pragma omp declare target
int foo(void) {
int error = -1;
Expand Down
20 changes: 12 additions & 8 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,26 +548,30 @@ void VarListClauses() {
#pragma acc serial present(s.array[s.value : 5], s.value), seq
for(;;){}

// expected-error@+3{{expected ','}}
// expected-warning@+2{{OpenACC clause 'deviceptr' not yet implemented, clause ignored}}

void *IsPointer;
// expected-error@+5{{expected ','}}
// expected-error@+4{{expected pointer in 'deviceptr' clause, type is 'char'}}
// expected-error@+3{{OpenACC sub-array is not allowed here}}
// expected-note@+2{{expected variable of pointer type}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial deviceptr(s.array[s.value] s.array[s.value :5] ), seq
for(;;){}

// expected-warning@+2{{OpenACC clause 'deviceptr' not yet implemented, clause ignored}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial deviceptr(s.array[s.value : 5], s.value), seq
#pragma acc serial deviceptr(IsPointer), seq
for(;;){}

// expected-error@+3{{expected ','}}
// expected-warning@+2{{OpenACC clause 'attach' not yet implemented, clause ignored}}
// expected-error@+5{{expected ','}}
// expected-error@+4{{expected pointer in 'attach' clause, type is 'char'}}
// expected-error@+3{{OpenACC sub-array is not allowed here}}
// expected-note@+2{{expected variable of pointer type}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial attach(s.array[s.value] s.array[s.value :5] ), seq
for(;;){}

// expected-warning@+2{{OpenACC clause 'attach' not yet implemented, clause ignored}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial attach(s.array[s.value : 5], s.value), seq
#pragma acc serial attach(IsPointer), seq
for(;;){}

// expected-error@+3{{expected ','}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Rewriter/rewrite-super-message.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp
// RUN: %clang_cc1 -Wno-address-of-temporary -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp

void *sel_registerName(const char *);

Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/cxx2b-deducing-this-constexpr.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++2b %s -verify
// RUN: %clang_cc1 -fsyntax-only -std=c++2b %s -verify -fexperimental-new-constant-interpreter
// expected-no-diagnostics

template <typename Base>
Expand Down
61 changes: 61 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-attach-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct S {
int IntMem;
int *PtrMem;
};

void uses() {
int LocalInt;
int *LocalPtr;
int Array[5];
int *PtrArray[5];
struct S s;

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(LocalInt)
while (1);

// expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, or composite variable member}}
#pragma acc parallel attach(&LocalInt)
while (1);

#pragma acc serial attach(LocalPtr)
while (1);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int[5]'}}
#pragma acc kernels attach(Array)
while (1);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(Array[0])
while (1);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(Array[0:1])
while (1);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int *[5]'}}
#pragma acc parallel attach(PtrArray)
while (1);

#pragma acc parallel attach(PtrArray[0])
while (1);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(PtrArray[0:1])
while (1);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'struct S'}}
#pragma acc parallel attach(s)
while (1);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(s.IntMem)
while (1);

#pragma acc parallel attach(s.PtrMem)
while (1);
}
120 changes: 120 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-attach-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct S {
int IntMem;
int *PtrMem;
operator int*();
};

void uses() {
int LocalInt;
int *LocalPtr;
int Array[5];
int *PtrArray[5];
struct S s;

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(LocalInt)
while (true);

#pragma acc parallel attach(LocalPtr)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int[5]'}}
#pragma acc parallel attach(Array)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(Array[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(Array[0:1])
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int *[5]'}}
#pragma acc parallel attach(PtrArray)
while (true);

#pragma acc parallel attach(PtrArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(PtrArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'struct S'}}
#pragma acc parallel attach(s)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(s.IntMem)
while (true);

#pragma acc parallel attach(s.PtrMem)
while (true);
}

template<typename T, typename TPtr, typename TStruct, auto &R1>
void Templ() {
T SomeInt;
TPtr SomePtr;
T SomeIntArray[5];
TPtr SomeIntPtrArray[5];
TStruct SomeStruct;

// expected-error@+2{{expected pointer in 'attach' clause, type is 'int'}}
// expected-note@#INST{{in instantiation of function template specialization}}
#pragma acc parallel attach(SomeInt)
while (true);

#pragma acc parallel attach(SomePtr)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int[5]'}}
#pragma acc parallel attach(SomeIntArray)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(SomeIntArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(SomeIntArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int *[5]'}}
#pragma acc parallel attach(SomeIntPtrArray)
while (true);

#pragma acc parallel attach(SomeIntPtrArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel attach(SomeIntPtrArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'S'}}
#pragma acc parallel attach(SomeStruct)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(SomeStruct.IntMem)
while (true);

#pragma acc parallel attach(SomeStruct.PtrMem)
while (true);

// expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}}
#pragma acc parallel attach(R1)
while (true);
}

void inst() {
static constexpr int CEVar = 1;
Templ<int, int*, S, CEVar>(); // #INST
}
61 changes: 61 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-deviceptr-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct S {
int IntMem;
int *PtrMem;
};

void uses() {
int LocalInt;
int *LocalPtr;
int Array[5];
int *PtrArray[5];
struct S s;

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(LocalInt)
while (1);

// expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, or composite variable member}}
#pragma acc parallel deviceptr(&LocalInt)
while (1);

#pragma acc serial deviceptr(LocalPtr)
while (1);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int[5]'}}
#pragma acc kernels deviceptr(Array)
while (1);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(Array[0])
while (1);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(Array[0:1])
while (1);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int *[5]'}}
#pragma acc parallel deviceptr(PtrArray)
while (1);

#pragma acc parallel deviceptr(PtrArray[0])
while (1);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(PtrArray[0:1])
while (1);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'struct S'}}
#pragma acc parallel deviceptr(s)
while (1);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(s.IntMem)
while (1);

#pragma acc parallel deviceptr(s.PtrMem)
while (1);
}
120 changes: 120 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-deviceptr-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct S {
int IntMem;
int *PtrMem;
operator int*();
};

void uses() {
int LocalInt;
int *LocalPtr;
int Array[5];
int *PtrArray[5];
struct S s;

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(LocalInt)
while (true);

#pragma acc parallel deviceptr(LocalPtr)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int[5]'}}
#pragma acc parallel deviceptr(Array)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(Array[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(Array[0:1])
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int *[5]'}}
#pragma acc parallel deviceptr(PtrArray)
while (true);

#pragma acc parallel deviceptr(PtrArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(PtrArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'struct S'}}
#pragma acc parallel deviceptr(s)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(s.IntMem)
while (true);

#pragma acc parallel deviceptr(s.PtrMem)
while (true);
}

template<typename T, typename TPtr, typename TStruct, auto &R1>
void Templ() {
T SomeInt;
TPtr SomePtr;
T SomeIntArray[5];
TPtr SomeIntPtrArray[5];
TStruct SomeStruct;

// expected-error@+2{{expected pointer in 'deviceptr' clause, type is 'int'}}
// expected-note@#INST{{in instantiation of function template specialization}}
#pragma acc parallel deviceptr(SomeInt)
while (true);

#pragma acc parallel deviceptr(SomePtr)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int[5]'}}
#pragma acc parallel deviceptr(SomeIntArray)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(SomeIntArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(SomeIntArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int *[5]'}}
#pragma acc parallel deviceptr(SomeIntPtrArray)
while (true);

#pragma acc parallel deviceptr(SomeIntPtrArray[0])
while (true);

// expected-error@+2{{OpenACC sub-array is not allowed here}}
// expected-note@+1{{expected variable of pointer type}}
#pragma acc parallel deviceptr(SomeIntPtrArray[0:1])
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'S'}}
#pragma acc parallel deviceptr(SomeStruct)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(SomeStruct.IntMem)
while (true);

#pragma acc parallel deviceptr(SomeStruct.PtrMem)
while (true);

// expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}}
#pragma acc parallel deviceptr(R1)
while (true);
}

void inst() {
static constexpr int CEVar = 1;
Templ<int, int*, S, CEVar>(); // #INST
}
77 changes: 73 additions & 4 deletions clang/test/SemaOpenACC/compute-construct-varlist-ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ void NormalUses(float *PointerParam) {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc parallel attach(PointerParam) deviceptr(PointerParam)
while (true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}} parallel
// CHECK-NEXT: attach clause
// CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}} 'PointerParam' 'float *'
// CHECK-NEXT: deviceptr clause
// CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}} 'PointerParam' 'float *'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt
}

// This example is an error typically, but we want to make sure we're properly
Expand Down Expand Up @@ -402,6 +413,17 @@ void TemplUses(T t, U u, T*PointerParam) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc parallel attach(PointerParam) deviceptr(PointerParam)
while (true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}} parallel
// CHECK-NEXT: attach clause
// CHECK-NEXT: DeclRefExpr{{.*}}'T *' lvalue ParmVar{{.*}} 'PointerParam' 'T *'
// CHECK-NEXT: deviceptr clause
// CHECK-NEXT: DeclRefExpr{{.*}}'T *' lvalue ParmVar{{.*}} 'PointerParam' 'T *'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
int EndMarker;
Expand Down Expand Up @@ -604,6 +626,16 @@ void TemplUses(T t, U u, T*PointerParam) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

//#pragma acc parallel attach(PointerParam) deviceptr(PointerParam)
// CHECK-NEXT: OpenACCComputeConstruct{{.*}} parallel
// CHECK-NEXT: attach clause
// CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'PointerParam' 'int *'
// CHECK-NEXT: deviceptr clause
// CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'PointerParam' 'int *'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
}
Expand All @@ -613,17 +645,20 @@ struct S {
// CHECK: CXXRecordDecl{{.*}} implicit struct S
int ThisMember;
// CHECK-NEXT: FieldDecl{{.*}} ThisMember 'int'
int *ThisMemberPtr;
// CHECK-NEXT: FieldDecl{{.*}} ThisMemberPtr 'int *'
int ThisMemberArray[5];
// CHECK-NEXT: FieldDecl{{.*}} ThisMemberArray 'int[5]'

void foo();
// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void ()'

template<typename T>
void bar() {
void bar(T *PointerParam) {
// CHECK-NEXT: FunctionTemplateDecl{{.*}}bar
// CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T
// CHECK-NEXT: CXXMethodDecl{{.*}} bar 'void ()' implicit-inline
// CHECK-NEXT: CXXMethodDecl{{.*}} bar 'void (T *)' implicit-inline
// CHECK-NEXT: ParmVarDecl{{.*}} PointerParam 'T *'
// CHECK-NEXT: CompoundStmt

#pragma acc parallel private(ThisMember, this->ThisMemberArray[1])
Expand Down Expand Up @@ -664,10 +699,28 @@ struct S {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc parallel attach(PointerParam, this, this->ThisMemberPtr) deviceptr(PointerParam, this, ThisMemberPtr)
while (true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}} parallel
// CHECK-NEXT: attach clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'T *' lvalue ParmVar{{.*}} 'PointerParam' 'T *'
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: MemberExpr{{.*}} 'int *' lvalue ->ThisMemberPtr
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: deviceptr clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'T *' lvalue ParmVar{{.*}} 'PointerParam' 'T *'
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: MemberExpr{{.*}} 'int *' lvalue ->ThisMemberPtr
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' implicit this
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// Check Instantiations:
// CHECK-NEXT: CXXMethodDecl{{.*}} used bar 'void ()' implicit_instantiation implicit-inline
// CHECK-NEXT: CXXMethodDecl{{.*}} used bar 'void (int *)' implicit_instantiation implicit-inline
// CHECK-NEXT: TemplateArgument type 'int'
// CHECK-NEXT: BuiltinType{{.*}} 'int'
// CHECK-NEXT: ParmVarDecl{{.*}} PointerParam 'int *'
// CHECK-NEXT: CompoundStmt

// #pragma acc parallel private(ThisMember, this->ThisMemberArray[1])
Expand Down Expand Up @@ -704,6 +757,22 @@ struct S {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

//#pragma acc parallel attach(PointerParam, this, this->ThisMemberPtr) deviceptr(PointerParam, this, ThisMemberPtr)
// CHECK-NEXT: OpenACCComputeConstruct{{.*}} parallel
// CHECK-NEXT: attach clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'int *' lvalue ParmVar{{.*}} 'PointerParam' 'int *'
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: MemberExpr{{.*}} 'int *' lvalue ->ThisMemberPtr
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: deviceptr clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'int *' lvalue ParmVar{{.*}} 'PointerParam' 'int *'
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' this
// CHECK-NEXT: MemberExpr{{.*}} 'int *' lvalue ->ThisMemberPtr
// CHECK-NEXT: CXXThisExpr{{.*}} 'S *' implicit this
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt
}
};

Expand Down Expand Up @@ -906,7 +975,7 @@ void Inst() {
TemplUses<CEVar, int, int[1]>({}, {}, &i);

S s;
s.bar<int>();
s.bar<int>(&i);
STempl<int> stempl;
stempl.bar<int>();
}
7 changes: 7 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2840,6 +2840,13 @@ void OpenACCClauseEnqueue::VisitCopyOutClause(const OpenACCCopyOutClause &C) {
void OpenACCClauseEnqueue::VisitCreateClause(const OpenACCCreateClause &C) {
VisitVarList(C);
}
void OpenACCClauseEnqueue::VisitAttachClause(const OpenACCAttachClause &C) {
VisitVarList(C);
}
void OpenACCClauseEnqueue::VisitDevicePtrClause(
const OpenACCDevicePtrClause &C) {
VisitVarList(C);
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down
127 changes: 125 additions & 2 deletions clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2228,7 +2228,7 @@ TEST(TransferTest, AssignmentOperator) {
A Foo = { 1 };
A Bar = { 2 };
// [[p1]]
Foo = Bar;
A &Rval = (Foo = Bar);
// [[p2]]
Foo.Baz = 3;
// [[p3]]
Expand Down Expand Up @@ -2274,6 +2274,7 @@ TEST(TransferTest, AssignmentOperator) {
cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl));

EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2));
EXPECT_EQ(&getLocForDecl(ASTCtx, Env2, "Rval"), FooLoc2);

const auto *FooBazVal2 =
cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2));
Expand Down Expand Up @@ -2441,7 +2442,75 @@ TEST(TransferTest, AssignmentOperatorReturnsByValue) {
// This is a crash repro.
std::string Code = R"(
struct S {
S operator=(S&& other);
S operator=(const S&);
int i;
};
void target() {
S S1 = { 1 };
S S2 = { 2 };
S S3 = { 3 };
// [[before]]
// Test that the returned value is modeled by assigning to another value.
S1 = (S2 = S3);
(void)0;
// [[after]]
}
)";
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
const ValueDecl *S1Decl = findValueDecl(ASTCtx, "S1");
const ValueDecl *S2Decl = findValueDecl(ASTCtx, "S2");
const ValueDecl *S3Decl = findValueDecl(ASTCtx, "S3");

const Environment &EnvBefore =
getEnvironmentAtAnnotation(Results, "before");

EXPECT_FALSE(recordsEqual(
*EnvBefore.get<RecordStorageLocation>(*S1Decl),
*EnvBefore.get<RecordStorageLocation>(*S2Decl), EnvBefore));
EXPECT_FALSE(recordsEqual(
*EnvBefore.get<RecordStorageLocation>(*S2Decl),
*EnvBefore.get<RecordStorageLocation>(*S3Decl), EnvBefore));

const Environment &EnvAfter =
getEnvironmentAtAnnotation(Results, "after");

EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S1Decl),
*EnvAfter.get<RecordStorageLocation>(*S2Decl),
EnvAfter));
EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S2Decl),
*EnvAfter.get<RecordStorageLocation>(*S3Decl),
EnvAfter));
});
}

TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByRef) {
// This is a crash repro.
std::string Code = R"(
struct DifferentType {};
struct S {
DifferentType& operator=(const S&);
};
void target() {
S s;
s = S();
// [[p]]
}
)";
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {});
}

TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByValue) {
// This is a crash repro.
std::string Code = R"(
struct DifferentType {};
struct S {
DifferentType operator=(const S&);
};
void target() {
S s;
Expand Down Expand Up @@ -3331,6 +3400,60 @@ TEST(TransferTest, ResultObjectLocationDontVisitNestedRecordDecl) {
ASTContext &ASTCtx) {});
}

TEST(TransferTest, ResultObjectLocationDontVisitUnevaluatedContexts) {
// This is a crash repro.
// We used to crash because when propagating result objects, we would visit
// unevaluated contexts, but we don't model fields used only in these.

auto testFunction = [](llvm::StringRef Code, llvm::StringRef TargetFun) {
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {},
LangStandard::lang_gnucxx17,
/* ApplyBuiltinTransfer= */ true, TargetFun);
};

std::string Code = R"cc(
// Definitions needed for `typeid`.
namespace std {
class type_info {};
class bad_typeid {};
} // namespace std
struct S1 {};
struct S2 { S1 s1; };
// We test each type of unevaluated context from a different target
// function. Some types of unevaluated contexts may actually cause the
// field `s1` to be modeled, and we don't want this to "pollute" the tests
// for the other unevaluated contexts.
void decltypeTarget() {
decltype(S2{}) Dummy;
}
void typeofTarget() {
typeof(S2{}) Dummy;
}
void typeidTarget() {
#if __has_feature(cxx_rtti)
typeid(S2{});
#endif
}
void sizeofTarget() {
sizeof(S2{});
}
void noexceptTarget() {
noexcept(S2{});
}
)cc";

testFunction(Code, "decltypeTarget");
testFunction(Code, "typeofTarget");
testFunction(Code, "typeidTarget");
testFunction(Code, "sizeofTarget");
testFunction(Code, "noexceptTarget");
}

TEST(TransferTest, StaticCast) {
std::string Code = R"(
void target(int Foo) {
Expand Down
9 changes: 9 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27204,15 +27204,24 @@ TEST_F(FormatTest, RemoveParentheses) {
"if ((({ a; })))\n"
" b;",
Style);
verifyFormat("static_assert((std::is_constructible_v<T, Args &&> && ...));",
"static_assert(((std::is_constructible_v<T, Args &&> && ...)));",
Style);
verifyFormat("return (0);", "return (((0)));", Style);
verifyFormat("return (({ 0; }));", "return ((({ 0; })));", Style);
verifyFormat("return ((... && std::is_convertible_v<TArgsLocal, TArgs>));",
"return (((... && std::is_convertible_v<TArgsLocal, TArgs>)));",
Style);

Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement;
verifyFormat("#define Return0 return (0);", Style);
verifyFormat("return 0;", "return (0);", Style);
verifyFormat("co_return 0;", "co_return ((0));", Style);
verifyFormat("return 0;", "return (((0)));", Style);
verifyFormat("return ({ 0; });", "return ((({ 0; })));", Style);
verifyFormat("return (... && std::is_convertible_v<TArgsLocal, TArgs>);",
"return (((... && std::is_convertible_v<TArgsLocal, TArgs>)));",
Style);
verifyFormat("inline decltype(auto) f() {\n"
" if (a) {\n"
" return (a);\n"
Expand Down
4 changes: 4 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,10 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) {
EXPECT_TOKEN(Tokens[24], tok::amp, TT_UnaryOperator);
EXPECT_TOKEN(Tokens[27], tok::l_square, TT_ArraySubscriptLSquare);
EXPECT_TOKEN(Tokens[32], tok::r_brace, TT_StructRBrace);

Tokens = annotate("template <typename T, enum E e> struct S {};");
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
EXPECT_TOKEN(Tokens[11], tok::l_brace, TT_StructLBrace);
}

TEST_F(TokenAnnotatorTest, UnderstandsUnions) {
Expand Down
12 changes: 7 additions & 5 deletions clang/unittests/Serialization/SourceLocationEncodingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ using LocSeq = SourceLocationSequence;
// Loc is the raw (in-memory) form of SourceLocation.
void roundTrip(SourceLocation::UIntTy Loc,
std::optional<uint64_t> ExpectedEncoded = std::nullopt) {
uint64_t ActualEncoded =
SourceLocationEncoding::encode(SourceLocation::getFromRawEncoding(Loc));
uint64_t ActualEncoded = SourceLocationEncoding::encode(
SourceLocation::getFromRawEncoding(Loc), /*BaseOffset=*/0,
/*BaseModuleFileIndex=*/0);
if (ExpectedEncoded) {
ASSERT_EQ(ActualEncoded, *ExpectedEncoded) << "Encoding " << Loc;
}
SourceLocation::UIntTy DecodedEncoded =
SourceLocationEncoding::decode(ActualEncoded).getRawEncoding();
SourceLocationEncoding::decode(ActualEncoded).first.getRawEncoding();
ASSERT_EQ(DecodedEncoded, Loc) << "Decoding " << ActualEncoded;
}

Expand All @@ -41,7 +42,8 @@ void roundTrip(std::vector<SourceLocation::UIntTy> Locs,
LocSeq::State Seq;
for (auto L : Locs)
ActualEncoded.push_back(SourceLocationEncoding::encode(
SourceLocation::getFromRawEncoding(L), Seq));
SourceLocation::getFromRawEncoding(L), /*BaseOffset=*/0,
/*BaseModuleFileIndex=*/0, Seq));
if (!ExpectedEncoded.empty()) {
ASSERT_EQ(ActualEncoded, ExpectedEncoded)
<< "Encoding " << testing::PrintToString(Locs);
Expand All @@ -51,7 +53,7 @@ void roundTrip(std::vector<SourceLocation::UIntTy> Locs,
{
LocSeq::State Seq;
for (auto L : ActualEncoded) {
SourceLocation Loc = SourceLocationEncoding::decode(L, Seq);
SourceLocation Loc = SourceLocationEncoding::decode(L, Seq).first;
DecodedEncoded.push_back(Loc.getRawEncoding());
}
ASSERT_EQ(DecodedEncoded, Locs)
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,8 @@ class Symbol {
OmpCommonBlock, OmpReduction, OmpAligned, OmpNontemporal, OmpAllocate,
OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective,
OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction,
OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined);
OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined,
OmpImplicit);
using Flags = common::EnumSet<Flag, Flag_enumSize>;

const Scope &owner() const { return *owner_; }
Expand Down
210 changes: 117 additions & 93 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@ void DataSharingProcessor::processStep1(
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
collectSymbolsForPrivatization();
collectDefaultSymbols();
collectImplicitSymbols();
privatize(clauseOps, privateSyms);
defaultPrivatize(clauseOps, privateSyms);
implicitPrivatize(clauseOps, privateSyms);
insertBarrier();
}

void DataSharingProcessor::processStep2(mlir::Operation *op, bool isLoop) {
insPt = firOpBuilder.saveInsertionPoint();
copyLastPrivatize(op);
firOpBuilder.restoreInsertionPoint(insPt);
// 'sections' lastprivate is handled by genOMP()
if (!mlir::isa<mlir::omp::SectionsOp>(op)) {
insPt = firOpBuilder.saveInsertionPoint();
copyLastPrivatize(op);
firOpBuilder.restoreInsertionPoint(insPt);
}

if (isLoop) {
// push deallocs out of the loop
Expand Down Expand Up @@ -141,6 +146,10 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
}

bool DataSharingProcessor::needBarrier() {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of lastprivate
// variables.
// Emit implicit barrier for linear clause. Maybe on somewhere else.
for (const Fortran::semantics::Symbol *sym : privatizedSymbols) {
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate) &&
sym->test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
Expand All @@ -150,13 +159,6 @@ bool DataSharingProcessor::needBarrier() {
}

void DataSharingProcessor::insertBarrier() {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of lastprivate
// variables.
// FIXME: Emit barrier for lastprivate clause when 'sections' directive has
// 'nowait' clause. Otherwise, emit barrier when 'sections' directive has
// both firstprivate and lastprivate clause.
// Emit implicit barrier for linear clause. Maybe on somewhere else.
if (needBarrier())
firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation());
}
Expand All @@ -174,76 +176,7 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
if (clause.id != llvm::omp::OMPC_lastprivate)
continue;
// TODO: Add lastprivate support for simd construct
if (mlir::isa<mlir::omp::SectionOp>(op)) {
if (&eval == &eval.parentConstruct->getLastNestedEvaluation()) {
// For `omp.sections`, lastprivatized variables occur in
// lexically final `omp.section` operation. The following FIR
// shall be generated for the same:
//
// omp.sections lastprivate(...) {
// omp.section {...}
// omp.section {...}
// omp.section {
// fir.allocate for `private`/`firstprivate`
// <More operations here>
// fir.if %true {
// ^%lpv_update_blk
// }
// }
// }
//
// To keep code consistency while handling privatization
// through this control flow, add a `fir.if` operation
// that always evaluates to true, in order to create
// a dedicated sub-region in `omp.section` where
// lastprivate FIR can reside. Later canonicalizations
// will optimize away this operation.
if (!eval.lowerAsUnstructured()) {
auto ifOp = firOpBuilder.create<fir::IfOp>(
op->getLoc(),
firOpBuilder.createIntegerConstant(
op->getLoc(), firOpBuilder.getIntegerType(1), 0x1),
/*else*/ false);
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());

const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
eval.parentConstruct->getIf<Fortran::parser::OpenMPConstruct>();
assert(parentOmpConstruct &&
"Expected a valid enclosing OpenMP construct");
const Fortran::parser::OpenMPSectionsConstruct *sectionsConstruct =
std::get_if<Fortran::parser::OpenMPSectionsConstruct>(
&parentOmpConstruct->u);
assert(sectionsConstruct &&
"Expected an enclosing omp.sections construct");
const Fortran::parser::OmpClauseList &sectionsEndClauseList =
std::get<Fortran::parser::OmpClauseList>(
std::get<Fortran::parser::OmpEndSectionsDirective>(
sectionsConstruct->t)
.t);
for (const Fortran::parser::OmpClause &otherClause :
sectionsEndClauseList.v)
if (std::get_if<Fortran::parser::OmpClause::Nowait>(&otherClause.u))
// Emit implicit barrier to synchronize threads and avoid data
// races on post-update of lastprivate variables when `nowait`
// clause is present.
firOpBuilder.create<mlir::omp::BarrierOp>(
converter.getCurrentLocation());
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
lastPrivIP = firOpBuilder.saveInsertionPoint();
firOpBuilder.setInsertionPoint(ifOp);
insPt = firOpBuilder.saveInsertionPoint();
} else {
// Lastprivate operation is inserted at the end
// of the lexically last section in the sections
// construct
mlir::OpBuilder::InsertionGuard unstructuredSectionsGuard(
firOpBuilder);
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
firOpBuilder.setInsertionPoint(lastOper);
lastPrivIP = firOpBuilder.saveInsertionPoint();
}
}
} else if (mlir::isa<mlir::omp::WsloopOp>(op)) {
if (mlir::isa<mlir::omp::WsloopOp>(op)) {
// Update the original variable just before exiting the worksharing
// loop. Conversion as follows:
//
Expand Down Expand Up @@ -295,6 +228,8 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
assert(loopIV && "loopIV was not set");
firOpBuilder.create<fir::StoreOp>(loopOp.getLoc(), v, loopIV);
lastPrivIP = firOpBuilder.saveInsertionPoint();
} else if (mlir::isa<mlir::omp::SectionsOp>(op)) {
// Already handled by genOMP()
} else {
TODO(converter.getCurrentLocation(),
"lastprivate clause in constructs other than "
Expand All @@ -303,6 +238,48 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
}
}

static const Fortran::parser::CharBlock *
getSource(const Fortran::semantics::SemanticsContext &semaCtx,
const Fortran::lower::pft::Evaluation &eval) {
const Fortran::parser::CharBlock *source = nullptr;

auto ompConsVisit = [&](const Fortran::parser::OpenMPConstruct &x) {
std::visit(Fortran::common::visitors{
[&](const Fortran::parser::OpenMPSectionsConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPLoopConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPBlockConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPCriticalConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPAtomicConstruct &x) {
std::visit([&](const auto &x) { source = &x.source; },
x.u);
},
[&](const auto &x) { source = &x.source; },
},
x.u);
};

eval.visit(Fortran::common::visitors{
[&](const Fortran::parser::OpenMPConstruct &x) { ompConsVisit(x); },
[&](const Fortran::parser::OpenMPDeclarativeConstruct &x) {
source = &x.source;
},
[&](const Fortran::parser::OmpEndLoopDirective &x) {
source = &x.source;
},
[&](const auto &x) {},
});

return source;
}

void DataSharingProcessor::collectSymbolsInNestedRegions(
Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::Symbol::Flag flag,
Expand Down Expand Up @@ -330,11 +307,49 @@ void DataSharingProcessor::collectSymbolsInNestedRegions(
// Later, in current context, all symbols in the set
// `defaultSymbols` - `symbolsInNestedRegions` will be privatized.
void DataSharingProcessor::collectSymbols(
Fortran::semantics::Symbol::Flag flag) {
converter.collectSymbolSet(eval, defaultSymbols, flag,
Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbols) {
// Collect all scopes associated with 'eval'.
llvm::SetVector<const Fortran::semantics::Scope *> clauseScopes;
std::function<void(const Fortran::semantics::Scope *)> collectScopes =
[&](const Fortran::semantics::Scope *scope) {
clauseScopes.insert(scope);
for (const Fortran::semantics::Scope &child : scope->children())
collectScopes(&child);
};
const Fortran::parser::CharBlock *source =
clauses.empty() ? getSource(semaCtx, eval) : &clauses.front().source;
const Fortran::semantics::Scope *curScope = nullptr;
if (source && !source->empty()) {
curScope = &semaCtx.FindScope(*source);
collectScopes(curScope);
}
// Collect all symbols referenced in the evaluation being processed,
// that matches 'flag'.
llvm::SetVector<const Fortran::semantics::Symbol *> allSymbols;
converter.collectSymbolSet(eval, allSymbols, flag,
/*collectSymbols=*/true,
/*collectHostAssociatedSymbols=*/true);
llvm::SetVector<const Fortran::semantics::Symbol *> symbolsInNestedRegions;
collectSymbolsInNestedRegions(eval, flag, symbolsInNestedRegions);
// Filter-out symbols that must not be privatized.
bool collectImplicit = flag == Fortran::semantics::Symbol::Flag::OmpImplicit;
auto isPrivatizable = [](const Fortran::semantics::Symbol &sym) -> bool {
return !Fortran::semantics::IsProcedure(sym) &&
!sym.GetUltimate().has<Fortran::semantics::DerivedTypeDetails>() &&
!sym.GetUltimate().has<Fortran::semantics::NamelistDetails>() &&
!Fortran::semantics::IsImpliedDoIndex(sym.GetUltimate());
};
for (const auto *sym : allSymbols) {
assert(curScope && "couldn't find current scope");
if (isPrivatizable(*sym) && !symbolsInNestedRegions.contains(sym) &&
!privatizedSymbols.contains(sym) &&
!sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined) &&
(collectImplicit ||
!sym->test(Fortran::semantics::Symbol::Flag::OmpImplicit)) &&
clauseScopes.contains(&sym->owner()))
symbols.insert(sym);
}
}

void DataSharingProcessor::collectDefaultSymbols() {
Expand All @@ -343,13 +358,22 @@ void DataSharingProcessor::collectDefaultSymbols() {
if (const auto *defaultClause =
std::get_if<omp::clause::Default>(&clause.u)) {
if (defaultClause->v == DataSharingAttribute::Private)
collectSymbols(Fortran::semantics::Symbol::Flag::OmpPrivate);
collectSymbols(Fortran::semantics::Symbol::Flag::OmpPrivate,
defaultSymbols);
else if (defaultClause->v == DataSharingAttribute::Firstprivate)
collectSymbols(Fortran::semantics::Symbol::Flag::OmpFirstPrivate);
collectSymbols(Fortran::semantics::Symbol::Flag::OmpFirstPrivate,
defaultSymbols);
}
}
}

void DataSharingProcessor::collectImplicitSymbols() {
// There will be no implicit symbols when a default clause is present.
if (defaultSymbols.empty())
collectSymbols(Fortran::semantics::Symbol::Flag::OmpImplicit,
implicitSymbols);
}

void DataSharingProcessor::privatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
Expand Down Expand Up @@ -379,15 +403,15 @@ void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
void DataSharingProcessor::defaultPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
for (const Fortran::semantics::Symbol *sym : defaultSymbols) {
if (!Fortran::semantics::IsProcedure(*sym) &&
!sym->GetUltimate().has<Fortran::semantics::DerivedTypeDetails>() &&
!sym->GetUltimate().has<Fortran::semantics::NamelistDetails>() &&
!Fortran::semantics::IsImpliedDoIndex(sym->GetUltimate()) &&
!symbolsInNestedRegions.contains(sym) &&
!privatizedSymbols.contains(sym))
doPrivatize(sym, clauseOps, privateSyms);
}
for (const Fortran::semantics::Symbol *sym : defaultSymbols)
doPrivatize(sym, clauseOps, privateSyms);
}

void DataSharingProcessor::implicitPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
for (const Fortran::semantics::Symbol *sym : implicitSymbols)
doPrivatize(sym, clauseOps, privateSyms);
}

void DataSharingProcessor::doPrivatize(
Expand Down
13 changes: 10 additions & 3 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,21 @@ class DataSharingProcessor {
// Symbols in private, firstprivate, and/or lastprivate clauses.
llvm::SetVector<const Fortran::semantics::Symbol *> privatizedSymbols;
llvm::SetVector<const Fortran::semantics::Symbol *> defaultSymbols;
llvm::SetVector<const Fortran::semantics::Symbol *> symbolsInNestedRegions;
llvm::SetVector<const Fortran::semantics::Symbol *> implicitSymbols;
llvm::DenseMap<const Fortran::semantics::Symbol *, mlir::omp::PrivateClauseOp>
symToPrivatizer;
Fortran::lower::AbstractConverter &converter;
Fortran::semantics::SemanticsContext &semaCtx;
fir::FirOpBuilder &firOpBuilder;
omp::List<omp::Clause> clauses;
Fortran::lower::pft::Evaluation &eval;
bool useDelayedPrivatization;
Fortran::lower::SymMap *symTable;

bool needBarrier();
void collectSymbols(Fortran::semantics::Symbol::Flag flag);
void
collectSymbols(Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbols);
void collectSymbolsInNestedRegions(
Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::Symbol::Flag flag,
Expand All @@ -62,12 +65,16 @@ class DataSharingProcessor {
void collectSymbolsForPrivatization();
void insertBarrier();
void collectDefaultSymbols();
void collectImplicitSymbols();
void privatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
void defaultPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
void implicitPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
void doPrivatize(
const Fortran::semantics::Symbol *sym,
mlir::omp::PrivateClauseOps *clauseOps,
Expand All @@ -89,7 +96,7 @@ class DataSharingProcessor {
Fortran::lower::pft::Evaluation &eval,
bool useDelayedPrivatization = false,
Fortran::lower::SymMap *symTable = nullptr)
: hasLastPrivateOp(false), converter(converter),
: hasLastPrivateOp(false), converter(converter), semaCtx(semaCtx),
firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),
useDelayedPrivatization(useDelayedPrivatization), symTable(symTable) {}

Expand Down
51 changes: 43 additions & 8 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1460,14 +1460,11 @@ genSectionOp(Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symTable,
Fortran::semantics::SemanticsContext &semaCtx,
Fortran::lower::pft::Evaluation &eval, bool genNested,
mlir::Location loc, const List<Clause> &clauses) {
// Currently only private/firstprivate clause is handled, and
// all privatization is done within `omp.section` operations.
mlir::Location loc) {
return genOpWithBody<mlir::omp::SectionOp>(
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
llvm::omp::Directive::OMPD_section)
.setGenNested(genNested)
.setClauses(&clauses));
.setGenNested(genNested));
}

static mlir::omp::SectionsOp
Expand Down Expand Up @@ -2478,22 +2475,60 @@ genOMP(Fortran::lower::AbstractConverter &converter,
/*outerCombined=*/true);
}

// Insert privatizations before SECTIONS
symTable.pushScope();
DataSharingProcessor dsp(converter, semaCtx, clauses, eval);
dsp.processStep1();

// SECTIONS construct.
genSectionsOp(converter, symTable, semaCtx, eval, currentLocation, clauseOps);
mlir::omp::SectionsOp sectionsOp = genSectionsOp(
converter, symTable, semaCtx, eval, currentLocation, clauseOps);

// Generate nested SECTION operations recursively.
const auto &sectionBlocks =
std::get<Fortran::parser::OmpSectionBlocks>(sectionsConstruct.t);
auto &firOpBuilder = converter.getFirOpBuilder();
auto ip = firOpBuilder.saveInsertionPoint();
mlir::omp::SectionOp lastSectionOp;
for (const auto &[nblock, neval] :
llvm::zip(sectionBlocks.v, eval.getNestedEvaluations())) {
symTable.pushScope();
genSectionOp(converter, symTable, semaCtx, neval, /*genNested=*/true,
currentLocation, clauses);
lastSectionOp = genSectionOp(converter, symTable, semaCtx, neval,
/*genNested=*/true, currentLocation);
symTable.popScope();
firOpBuilder.restoreInsertionPoint(ip);
}

// For `omp.sections`, lastprivatized variables occur in
// lexically final `omp.section` operation.
bool hasLastPrivate = false;
if (lastSectionOp) {
for (const Clause &clause : clauses) {
if (const auto *lastPrivate =
std::get_if<clause::Lastprivate>(&clause.u)) {
hasLastPrivate = true;
firOpBuilder.setInsertionPoint(
lastSectionOp.getRegion().back().getTerminator());
mlir::OpBuilder::InsertPoint lastPrivIP =
converter.getFirOpBuilder().saveInsertionPoint();
const auto &objList = std::get<1>(lastPrivate->t);
for (const Object &obj : objList) {
Fortran::semantics::Symbol *sym = obj.id();
converter.copyHostAssociateVar(*sym, &lastPrivIP);
}
}
}
}

// Perform DataSharingProcessor's step2 out of SECTIONS
firOpBuilder.setInsertionPointAfter(sectionsOp.getOperation());
dsp.processStep2(sectionsOp, false);
// Emit implicit barrier to synchronize threads and avoid data
// races on post-update of lastprivate variables when `nowait`
// clause is present.
if (clauseOps.nowaitAttr && hasLastPrivate)
firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation());
symTable.popScope();
}

static void genOMP(Fortran::lower::AbstractConverter &converter,
Expand Down
108 changes: 92 additions & 16 deletions flang/lib/Semantics/resolve-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) {
case llvm::omp::Directive::OMPD_parallel_sections:
case llvm::omp::Directive::OMPD_sections:
PushContext(beginDir.source, beginDir.v);
GetContext().withinConstruct = true;
break;
default:
break;
Expand All @@ -1825,6 +1826,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) {
const auto &beginCriticalDir{std::get<parser::OmpCriticalDirective>(x.t)};
const auto &endCriticalDir{std::get<parser::OmpEndCriticalDirective>(x.t)};
PushContext(beginCriticalDir.source, llvm::omp::Directive::OMPD_critical);
GetContext().withinConstruct = true;
if (const auto &criticalName{
std::get<std::optional<parser::Name>>(beginCriticalDir.t)}) {
ResolveOmpName(*criticalName, Symbol::Flag::OmpCriticalLock);
Expand Down Expand Up @@ -2028,34 +2030,108 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
if (found->test(semantics::Symbol::Flag::OmpThreadprivate))
return;
}
std::vector<Symbol *> defaultDSASymbols;

// Implicitly determined DSAs
// OMP 5.2 5.1.1 - Variables Referenced in a Construct
Symbol *lastDeclSymbol = nullptr;
std::optional<Symbol::Flag> prevDSA;
for (int dirDepth{0}; dirDepth < (int)dirContext_.size(); ++dirDepth) {
DirContext &dirContext = dirContext_[dirDepth];
bool hasDataSharingAttr{false};
std::optional<Symbol::Flag> dsa;

for (auto symMap : dirContext.objectWithDSA) {
// if the `symbol` already has a data-sharing attribute
if (symMap.first->name() == name.symbol->name()) {
hasDataSharingAttr = true;
dsa = symMap.second;
break;
}
}
if (hasDataSharingAttr) {
if (defaultDSASymbols.size())
symbol = &MakeAssocSymbol(symbol->name(), *defaultDSASymbols.back(),

// When handling each implicit rule, either a new private symbol is
// declared or the last declared symbol is used.
// In the latter case, it's necessary to insert a new symbol in the scope
// being processed, associated with the last declared symbol.
// This captures the fact that, although we are using the last declared
// symbol, its DSA could be different in this scope.
// Also, because of how symbols are collected in lowering, not inserting
// a new symbol in this scope could lead to the conclusion that the
// symbol was declared in this construct, which would result in wrong
// privatization code being generated.
// Consider the following example:
//
// !$omp parallel default(private) ! p1
// !$omp parallel default(private) shared(x) ! p2
// x = 10
// !$omp end parallel
// !$omp end parallel
//
// If a new x symbol was not inserted in the inner parallel construct
// (p2), it would use the x symbol definition from the enclosing scope.
// Then, when p2's default symbols were collected in lowering, the x
// symbol from the outer parallel construct (p1) would be collected, as
// it would have the private flag set (note that symbols that don't have
// any private flag are considered as shared).
// This would make x appear to be defined in p2, causing it to be
// privatized in p2 and its privatization in p1 to be skipped.
auto declNewSymbol = [&](Symbol::Flag flag) {
Symbol *hostSymbol =
lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate();
lastDeclSymbol = DeclarePrivateAccessEntity(
*hostSymbol, flag, context_.FindScope(dirContext.directiveSource));
return lastDeclSymbol;
};
auto useLastDeclSymbol = [&]() {
if (lastDeclSymbol)
MakeAssocSymbol(symbol->name(), *lastDeclSymbol,
context_.FindScope(dirContext.directiveSource));
};

if (dsa.has_value()) {
useLastDeclSymbol();
prevDSA = dsa;
continue;
}

if (dirContext.defaultDSA == semantics::Symbol::Flag::OmpPrivate ||
dirContext.defaultDSA == semantics::Symbol::Flag::OmpFirstPrivate) {
Symbol *hostSymbol = defaultDSASymbols.size() ? defaultDSASymbols.back()
: &symbol->GetUltimate();
defaultDSASymbols.push_back(
DeclarePrivateAccessEntity(*hostSymbol, dirContext.defaultDSA,
context_.FindScope(dirContext.directiveSource)));
} else if (defaultDSASymbols.size())
symbol = &MakeAssocSymbol(symbol->name(), *defaultDSASymbols.back(),
context_.FindScope(dirContext.directiveSource));
bool taskGenDir = llvm::omp::taskGeneratingSet.test(dirContext.directive);
bool targetDir = llvm::omp::allTargetSet.test(dirContext.directive);
bool parallelDir = llvm::omp::allParallelSet.test(dirContext.directive);

if (dirContext.defaultDSA == Symbol::Flag::OmpPrivate ||
dirContext.defaultDSA == Symbol::Flag::OmpFirstPrivate ||
dirContext.defaultDSA == Symbol::Flag::OmpShared) {
// 1) default
// Allowed only with parallel, teams and task generating constructs.
assert(parallelDir || taskGenDir ||
llvm::omp::allTeamsSet.test(dirContext.directive));
if (dirContext.defaultDSA != Symbol::Flag::OmpShared)
declNewSymbol(dirContext.defaultDSA);
else
useLastDeclSymbol();
dsa = dirContext.defaultDSA;
} else if (parallelDir) {
// 2) parallel -> shared
useLastDeclSymbol();
dsa = Symbol::Flag::OmpShared;
} else if (!taskGenDir && !targetDir) {
// 3) enclosing context
useLastDeclSymbol();
dsa = prevDSA;
} else if (targetDir) {
// TODO 4) not mapped target variable -> firstprivate
dsa = prevDSA;
} else if (taskGenDir) {
// TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
if (prevDSA == Symbol::Flag::OmpShared) {
// 6) shared in enclosing context -> shared
useLastDeclSymbol();
dsa = Symbol::Flag::OmpShared;
} else {
// 7) firstprivate
dsa = Symbol::Flag::OmpFirstPrivate;
declNewSymbol(*dsa)->set(Symbol::Flag::OmpImplicit);
}
}
prevDSA = dsa;
}
} // within OpenMP construct
}
Expand Down
4 changes: 1 addition & 3 deletions flang/test/Lower/OpenMP/default-clause-byref.f90
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,12 @@ subroutine nested_default_clause_tests
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.parallel {
!CHECK: %[[PRIVATE_INNER_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_testsEz"}
!CHECK: %[[PRIVATE_INNER_Z_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_Z]] {uniq_name = "_QFnested_default_clause_testsEz"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_INNER_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"}
!CHECK: %[[PRIVATE_INNER_W_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_W]] {uniq_name = "_QFnested_default_clause_testsEw"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"}
!CHECK: %[[PRIVATE_INNER_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_X]] {uniq_name = "_QFnested_default_clause_testsEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP_1:.*]] = fir.load %[[PRIVATE_INNER_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[TEMP_2:.*]] = fir.load %[[PRIVATE_INNER_Z_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[TEMP_2:.*]] = fir.load %[[PRIVATE_Z_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[RESULT:.*]] = arith.addi %{{.*}}, %{{.*}} : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_INNER_W_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: omp.terminator
Expand Down
4 changes: 1 addition & 3 deletions flang/test/Lower/OpenMP/default-clause.f90
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,12 @@ subroutine nested_default_clause_test1
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.parallel {
!CHECK: %[[PRIVATE_INNER_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_test2Ez"}
!CHECK: %[[PRIVATE_INNER_Z_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_Z]] {uniq_name = "_QFnested_default_clause_test2Ez"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_INNER_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_test2Ew"}
!CHECK: %[[PRIVATE_INNER_W_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_W]] {uniq_name = "_QFnested_default_clause_test2Ew"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_test2Ex"}
!CHECK: %[[PRIVATE_INNER_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_INNER_X]] {uniq_name = "_QFnested_default_clause_test2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP_1:.*]] = fir.load %[[PRIVATE_INNER_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[TEMP_2:.*]] = fir.load %[[PRIVATE_INNER_Z_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[TEMP_2:.*]] = fir.load %[[PRIVATE_Z_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[RESULT:.*]] = arith.addi %{{.*}}, %{{.*}} : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_INNER_W_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: omp.terminator
Expand Down
275 changes: 275 additions & 0 deletions flang/test/Lower/OpenMP/implicit-dsa.f90

Large diffs are not rendered by default.

104 changes: 51 additions & 53 deletions flang/test/Lower/OpenMP/sections.f90
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
!CHECK: %[[COUNT_DECL:.*]]:2 = hlfir.declare %[[COUNT]] {uniq_name = "_QFEcount"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[ETA:.*]] = fir.alloca f32 {bindc_name = "eta", uniq_name = "_QFEeta"}
!CHECK: %[[CONST_1:.*]] = arith.constant 4 : i64
!CHECK: %[[PRIVATE_ETA:.*]] = fir.alloca f32 {bindc_name = "eta", pinned, uniq_name = "_QFEeta"}
!CHECK: %[[PRIVATE_ETA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ETA]] {uniq_name = "_QFEeta"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[PRIVATE_DOUBLE_COUNT:.*]] = fir.alloca i32 {bindc_name = "double_count", pinned, uniq_name = "_QFEdouble_count"}
!CHECK: %[[PRIVATE_DOUBLE_COUNT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_DOUBLE_COUNT]] {uniq_name = "_QFEdouble_count"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.sections allocate(%[[CONST_1]] : i64 -> %[[COUNT_DECL]]#1 : !fir.ref<i32>) {
!CHECK: omp.section {
!CHECK: %[[PRIVATE_ETA:.*]] = fir.alloca f32 {bindc_name = "eta", pinned, uniq_name = "_QFEeta"}
!CHECK: %[[PRIVATE_ETA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ETA]] {uniq_name = "_QFEeta"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[PRIVATE_DOUBLE_COUNT:.*]] = fir.alloca i32 {bindc_name = "double_count", pinned, uniq_name = "_QFEdouble_count"}
!CHECK: %[[PRIVATE_DOUBLE_COUNT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_DOUBLE_COUNT]] {uniq_name = "_QFEdouble_count"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[CONST5:.*]] = arith.constant 5 : i32
!CHECK: hlfir.assign %[[CONST5]] to %[[COUNT_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: %[[TEMP_COUNT:.*]] = fir.load %[[COUNT_DECL]]#0 : !fir.ref<i32>
Expand All @@ -26,21 +26,13 @@
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.section {
!CHECK: %[[PRIVATE_ETA:.*]] = fir.alloca f32 {bindc_name = "eta", pinned, uniq_name = "_QFEeta"}
!CHECK: %[[PRIVATE_ETA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ETA]] {uniq_name = "_QFEeta"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[PRIVATE_DOUBLE_COUNT:.*]] = fir.alloca i32 {bindc_name = "double_count", pinned, uniq_name = "_QFEdouble_count"}
!CHECK: %[[PRIVATE_DOUBLE_COUNT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_DOUBLE_COUNT]] {uniq_name = "_QFEdouble_count"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_DOUBLE_COUNT_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[CONST:.*]] = arith.constant 1 : i32
!CHECK: %[[RESULT:.*]] = arith.addi %[[TEMP]], %[[CONST]] : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_DOUBLE_COUNT_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.section {
!CHECK: %[[PRIVATE_ETA:.*]] = fir.alloca f32 {bindc_name = "eta", pinned, uniq_name = "_QFEeta"}
!CHECK: %[[PRIVATE_ETA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ETA]] {uniq_name = "_QFEeta"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[PRIVATE_DOUBLE_COUNT:.*]] = fir.alloca i32 {bindc_name = "double_count", pinned, uniq_name = "_QFEdouble_count"}
!CHECK: %[[PRIVATE_DOUBLE_COUNT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_DOUBLE_COUNT]] {uniq_name = "_QFEdouble_count"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_ETA_DECL]]#0 : !fir.ref<f32>
!CHECK: %[[CONST:.*]] = arith.constant 7.000000e+00 : f32
!CHECK: %[[RESULT:.*]] = arith.subf %[[TEMP]], %[[CONST]] {{.*}}: f32
Expand Down Expand Up @@ -88,12 +80,12 @@ end program sample

!CHECK: func @_QPfirstprivate(%[[ARG:.*]]: !fir.ref<f32> {fir.bindc_name = "alpha"}) {
!CHECK: %[[ARG_DECL:.*]]:2 = hlfir.declare %[[ARG]] {uniq_name = "_QFfirstprivateEalpha"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[PRIVATE_ALPHA:.*]] = fir.alloca f32 {bindc_name = "alpha", pinned, uniq_name = "_QFfirstprivateEalpha"}
!CHECK: %[[PRIVATE_ALPHA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ALPHA]] {uniq_name = "_QFfirstprivateEalpha"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[ARG_DECL]]#0 : !fir.ref<f32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_ALPHA_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: %[[PRIVATE_ALPHA:.*]] = fir.alloca f32 {bindc_name = "alpha", pinned, uniq_name = "_QFfirstprivateEalpha"}
!CHECK: %[[PRIVATE_ALPHA_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ALPHA]] {uniq_name = "_QFfirstprivateEalpha"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[ARG_DECL]]#0 : !fir.ref<f32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_ALPHA_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.terminator
Expand Down Expand Up @@ -126,11 +118,11 @@ subroutine lastprivate()
integer :: x
!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlastprivateEx"}
!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.sections {
!$omp sections lastprivate(x)
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[CONST10:.*]] = arith.constant 10 : i32
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[RESULT:.*]] = arith.muli %[[CONST10]], %[[TEMP]] : i32
Expand All @@ -141,17 +133,12 @@ subroutine lastprivate()
x = x * 10

!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[CONST:.*]] = arith.constant 1 : i32
!CHECK: %[[RESULT:.*]] = arith.addi %[[TEMP]], %[[CONST]] : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_X_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: %[[TRUE:.*]] = arith.constant true
!CHECK: fir.if %[[TRUE]] {
!CHECK: %[[TEMP1:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP1]] to %[[X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: }
!CHECK: omp.terminator
!CHECK: }
!$omp section
Expand All @@ -160,14 +147,14 @@ subroutine lastprivate()
!CHECK: }
!$omp end sections

!CHECK: omp.sections {
!$omp sections firstprivate(x) lastprivate(x)
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.barrier
!CHECK: omp.sections {
!$omp sections firstprivate(x) lastprivate(x)
!CHECK: omp.section {
!CHECK: %[[CONST:.*]] = arith.constant 10 : i32
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[RESULT:.*]] = arith.muli %[[CONST]], %[[TEMP]] : i32
Expand All @@ -177,20 +164,12 @@ subroutine lastprivate()
!$omp section
x = x * 10
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.barrier
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[CONST:.*]] = arith.constant 1 : i32
!CHECK: %[[RESULT:.*]] = arith.addi %[[TEMP]], %[[CONST]] : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_X_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: %[[TRUE:.*]] = arith.constant true
!CHECK: fir.if %[[TRUE]] {
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: }
!CHECK: omp.terminator
!CHECK: }
!$omp section
Expand All @@ -199,14 +178,14 @@ subroutine lastprivate()
!CHECK: }
!$omp end sections

!CHECK: omp.sections nowait {
!$omp sections firstprivate(x) lastprivate(x)
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.barrier
!CHECK: omp.sections nowait {
!$omp sections firstprivate(x) lastprivate(x)
!CHECK: omp.section {
!CHECK: %[[CONST:.*]] = arith.constant 10 : i32
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[RESULT:.*]] = arith.muli %[[CONST]], %[[TEMP]] : i32
Expand All @@ -216,33 +195,25 @@ subroutine lastprivate()
!$omp section
x = x * 10
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.barrier
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: %[[CONST:.*]] = arith.constant 1 : i32
!CHECK: %[[RESULT:.*]] = arith.addi %[[TEMP]], %[[CONST]] : i32
!CHECK: hlfir.assign %[[RESULT]] to %[[PRIVATE_X_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: %[[TRUE:.*]] = arith.constant true
!CHECK: fir.if %[[TRUE]] {
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.barrier
!CHECK: }
!CHECK: omp.terminator
!CHECK: }
!$omp section
x = x + 1
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.barrier
!$omp end sections nowait

!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivateEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: cf.br ^bb1
!CHECK: ^bb1: // pred: ^bb0
!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
Expand All @@ -257,22 +228,49 @@ subroutine lastprivate()
!CHECK: }
!CHECK: return
!CHECK: }

!$omp sections lastprivate(x)
!$omp section
goto 30
30 x = x + 1
!$omp end sections
end subroutine

!CHECK-LABEL: func @_QPlastprivate2
!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlastprivate2Ex"}
!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFlastprivate2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFlastprivate2Ey"}
!CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]] {uniq_name = "_QFlastprivate2Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivate2Ex"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFlastprivate2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFlastprivate2Ey"}
!CHECK: %[[PRIVATE_Y_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_Y]] {uniq_name = "_QFlastprivate2Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: %[[TEMP:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP]] to %[[X_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: %[[TEMP2:.*]] = fir.load %[[PRIVATE_Y_DECL]]#0 : !fir.ref<i32>
!CHECK: hlfir.assign %[[TEMP2]] to %[[Y_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
!CHECK: omp.terminator
!CHECK: }
!CHECK: omp.terminator
!CHECK: }
subroutine lastprivate2()
integer :: x, y

!$omp sections lastprivate(x) lastprivate(y)
!$omp section
x = y + 1
!$omp end sections
end subroutine

!CHECK-LABEL: func @_QPunstructured_sections_privatization
subroutine unstructured_sections_privatization()
!CHECK: %[[X:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFunstructured_sections_privatizationEx"}
!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFunstructured_sections_privatizationEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca f32 {bindc_name = "x", pinned, uniq_name = "_QFunstructured_sections_privatizationEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFunstructured_sections_privatizationEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: cf.br ^bb1
!CHECK: ^bb1: // pred: ^bb0
!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<f32>
Expand All @@ -288,12 +286,12 @@ subroutine unstructured_sections_privatization()
goto 40
40 x = x + 1
!$omp end sections
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: %[[PRIVATE_X:.*]] = fir.alloca f32 {bindc_name = "x", pinned, uniq_name = "_QFunstructured_sections_privatizationEx"}
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X]] {uniq_name = "_QFunstructured_sections_privatizationEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<f32>
!CHECK: hlfir.assign %[[TEMP]] to %[[PRIVATE_X_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
!CHECK: omp.sections {
!CHECK: omp.section {
!CHECK: cf.br ^bb1
!CHECK: ^bb1:
!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<f32>
Expand Down
158 changes: 158 additions & 0 deletions flang/test/Semantics/OpenMP/implicit-dsa.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
! RUN: %python %S/../test_symbols.py %s %flang_fc1 -fopenmp

! Test symbols generated in block constructs that have implicitly
! determined DSAs.

! Basic cases.
!DEF: /implicit_dsa_test1 (Subroutine) Subprogram
subroutine implicit_dsa_test1
!DEF: /implicit_dsa_test1/i ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test1/x ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test1/y ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test1/z ObjectEntity INTEGER(4)
integer i, x, y, z

!$omp task private(y) shared(z)
!DEF: /implicit_dsa_test1/OtherConstruct1/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
!DEF: /implicit_dsa_test1/OtherConstruct1/y (OmpPrivate) HostAssoc INTEGER(4)
!REF: /implicit_dsa_test1/z
x = y + z
!$omp end task

!$omp task default(shared)
!REF: /implicit_dsa_test1/x
!REF: /implicit_dsa_test1/y
!REF: /implicit_dsa_test1/z
x = y + z
!$omp end task

!$omp taskloop
!DEF: /implicit_dsa_test1/OtherConstruct3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i = 0, 10
!DEF: /implicit_dsa_test1/OtherConstruct3/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
!DEF: /implicit_dsa_test1/OtherConstruct3/y (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
!REF: /implicit_dsa_test1/OtherConstruct3/i
x = y + i
end do
!$omp end taskloop
end subroutine

! Nested task with implicit firstprivate DSA variable.
!DEF: /implicit_dsa_test2 (Subroutine) Subprogram
subroutine implicit_dsa_test2
!DEF: /implicit_dsa_test2/x ObjectEntity INTEGER(4)
integer x

!$omp task
!$omp task
!DEF: /implicit_dsa_test2/OtherConstruct1/OtherConstruct1/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
x = 1
!$omp end task
!$omp end task
end subroutine

! Nested tasks with implicit shared DSA variables.
!DEF: /implicit_dsa_test3 (Subroutine) Subprogram
subroutine implicit_dsa_test3
!DEF: /implicit_dsa_test3/x ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test3/y ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test3/z ObjectEntity INTEGER(4)
integer x, y, z

!$omp parallel
!$omp task
!REF: /implicit_dsa_test3/x
x = 1
!REF: /implicit_dsa_test3/y
y = 1
!$omp end task

!$omp task firstprivate(x)
!DEF: /implicit_dsa_test3/OtherConstruct1/OtherConstruct2/x (OmpFirstPrivate) HostAssoc INTEGER(4)
x = 1
!REF: /implicit_dsa_test3/z
z = 1
!$omp end task
!$omp end parallel
end subroutine

! Task with implicit firstprivate DSA variables, enclosed in private context.
!DEF: /implicit_dsa_test4 (Subroutine) Subprogram
subroutine implicit_dsa_test4
!DEF: /implicit_dsa_test4/x ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test4/y ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test4/z ObjectEntity INTEGER(4)
integer x, y, z

!$omp parallel default(private)
!$omp task
!DEF: /implicit_dsa_test4/OtherConstruct1/OtherConstruct1/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
x = 0
!DEF: /implicit_dsa_test4/OtherConstruct1/OtherConstruct1/z (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
z = 1
!$omp end task

!$omp task
!DEF: /implicit_dsa_test4/OtherConstruct1/OtherConstruct2/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
x = 1
!DEF: /implicit_dsa_test4/OtherConstruct1/OtherConstruct2/y (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
y = 0
!$omp end task
!$omp end parallel
end subroutine

! Inner parallel using implicit firstprivate symbol.
!DEF: /implicit_dsa_test5 (Subroutine) Subprogram
subroutine implicit_dsa_test5
!DEF: /implicit_dsa_test5/x ObjectEntity INTEGER(4)
integer x

!$omp parallel default(private)
!$omp task
!$omp parallel
!DEF: /implicit_dsa_test5/OtherConstruct1/OtherConstruct1/OtherConstruct1/x HostAssoc INTEGER(4)
x = 1
!$omp end parallel
!$omp end task
!$omp end parallel
end subroutine

! Constructs nested inside a task with implicit DSA variables.
!DEF: /implicit_dsa_test6 (Subroutine) Subprogram
subroutine implicit_dsa_test6
!DEF: /implicit_dsa_test6/x ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test6/y ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test6/z ObjectEntity INTEGER(4)
integer x, y, z

!$omp task
!$omp parallel default(private)
!DEF: /implicit_dsa_test6/OtherConstruct1/OtherConstruct1/x (OmpPrivate) HostAssoc INTEGER(4)
!DEF: /implicit_dsa_test6/OtherConstruct1/OtherConstruct1/y (OmpPrivate) HostAssoc INTEGER(4)
x = y
!$omp end parallel

!$omp parallel default(firstprivate) shared(y)
!DEF: /implicit_dsa_test6/OtherConstruct1/OtherConstruct2/y HostAssoc INTEGER(4)
!DEF: /implicit_dsa_test6/OtherConstruct1/OtherConstruct2/x (OmpFirstPrivate) HostAssocINTEGER(4)
!DEF: /implicit_dsa_test6/OtherConstruct1/OtherConstruct2/z (OmpFirstPrivate) HostAssocINTEGER(4)
y = x + z
!$omp end parallel
!$omp end task
end subroutine

! Test taskgroup - it uses the same scope as task.
!DEF: /implicit_dsa_test7 (Subroutine) Subprogram
subroutine implicit_dsa_test7
!DEF: /implicit_dsa_test7/x ObjectEntity INTEGER(4)
!DEF: /implicit_dsa_test7/y ObjectEntity INTEGER(4)
integer x, y

!$omp task
!$omp taskgroup
!DEF: /implicit_dsa_test7/OtherConstruct1/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
!DEF: /implicit_dsa_test7/OtherConstruct1/y (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4)
x = y
!$omp end taskgroup
!$omp end task
end subroutine
18 changes: 18 additions & 0 deletions flang/test/Semantics/OpenMP/parallel-critical-do.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
! RUN: %python %S/../test_symbols.py %s %flang_fc1 -fopenmp

! Check that loop iteration variables are private and predetermined, even when
! nested inside parallel/critical constructs.

!DEF: /test1 (Subroutine) Subprogram
subroutine test1
!DEF: /test1/i ObjectEntity INTEGER(4)
integer i

!$omp parallel default(none)
!$omp critical
!DEF: /test1/OtherConstruct1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i = 1, 10
end do
!$omp end critical
!$omp end parallel
end subroutine
19 changes: 19 additions & 0 deletions flang/test/Semantics/OpenMP/parallel-sections-do.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
! RUN: %python %S/../test_symbols.py %s %flang_fc1 -fopenmp

! Check that loop iteration variables are private and predetermined, even when
! nested inside parallel/sections constructs.

!DEF: /test1 (Subroutine) Subprogram
subroutine test1
!DEF: /test1/i ObjectEntity INTEGER(4)
integer i

!$omp parallel default(none)
!$omp sections
!$omp section
!DEF: /test1/OtherConstruct1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i = 1, 10
end do
!$omp end sections
!$omp end parallel
end subroutine
2 changes: 1 addition & 1 deletion flang/test/Semantics/OpenMP/symbol08.f90
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ subroutine test_taskloop
!DEF: /test_taskloop/OtherConstruct1/j (OmpPrivate) HostAssoc INTEGER(4)
!REF: /test_taskloop/OtherConstruct1/i
do j=1,i
!REF: /test_taskloop/a
!DEF: /test_taskloop/OtherConstruct1/a (OmpFirstPrivate, OmpImplicit) HostAssoc REAL(4)
!REF: /test_taskloop/OtherConstruct1/j
!REF: /test_taskloop/OtherConstruct1/i
a(j,i) = 3.14
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Semantics/cuf13.cuf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
! RUN: %flang -fc1 -x cuda -fdebug-unparse %s | FileCheck %s
! RUN: %flang_fc1 -x cuda -fdebug-unparse %s | FileCheck %s

module matching
interface sub
Expand Down
26 changes: 8 additions & 18 deletions libc/test/UnitTest/FPMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,43 +159,33 @@ template <typename T> struct FPTest : public Test {
#define EXPECT_FP_EXCEPTION(expected) \
do { \
if (math_errhandling & MATH_ERREXCEPT) { \
EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
(expected), \
expected); \
EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
((expected) ? (expected) : FE_ALL_EXCEPT), \
(expected)); \
} \
} while (0)

#define ASSERT_FP_EXCEPTION(expected) \
do { \
if (math_errhandling & MATH_ERREXCEPT) { \
ASSERT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
(expected), \
expected); \
ASSERT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
((expected) ? (expected) : FE_ALL_EXCEPT), \
(expected)); \
} \
} while (0)

#define EXPECT_FP_EQ_WITH_EXCEPTION(expected_val, actual_val, expected_except) \
do { \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
EXPECT_FP_EQ(expected_val, actual_val); \
if (math_errhandling & MATH_ERREXCEPT) { \
EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
(expected_except), \
expected_except); \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
} \
EXPECT_FP_EXCEPTION(expected_except); \
} while (0)

#define EXPECT_FP_IS_NAN_WITH_EXCEPTION(actual_val, expected_except) \
do { \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
EXPECT_FP_IS_NAN(actual_val); \
if (math_errhandling & MATH_ERREXCEPT) { \
EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
(expected_except), \
expected_except); \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
} \
EXPECT_FP_EXCEPTION(expected_except); \
} while (0)

#define EXPECT_FP_EQ_ALL_ROUNDING(expected, actual) \
Expand Down
7 changes: 4 additions & 3 deletions libc/test/src/math/RoundToIntegerTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ class RoundToIntegerTestTemplate

ASSERT_EQ(func(input), expected);

// TODO: Handle the !expectError case. It used to expect
// 0 for errno and exceptions, but this doesn't hold for
// all math functions using RoundToInteger test:
// https://github.com/llvm/llvm-project/pull/88816
if (expectError) {
ASSERT_FP_EXCEPTION(FE_INVALID);
ASSERT_MATH_ERRNO(EDOM);
} else {
ASSERT_FP_EXCEPTION(0);
ASSERT_MATH_ERRNO(0);
}
}

Expand Down
14 changes: 11 additions & 3 deletions libc/test/src/math/atanf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,29 @@ using LlvmLibcAtanfTest = LIBC_NAMESPACE::testing::FPTest<float>;

namespace mpfr = LIBC_NAMESPACE::testing::mpfr;

// TODO: This test needs to have its checks for exceptions, errno
// tightened
TEST_F(LlvmLibcAtanfTest, SpecialNumbers) {
LIBC_NAMESPACE::libc_errno = 0;
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanf(aNaN));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanf(0.0f));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanf(-0.0f));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);
}

Expand Down
34 changes: 23 additions & 11 deletions libc/test/src/math/atanhf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,66 +21,78 @@ using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>;

namespace mpfr = LIBC_NAMESPACE::testing::mpfr;

// TODO: This test needs to have its checks for exceptions, errno
// tightened https://github.com/llvm/llvm-project/issues/88819.
TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {

LIBC_NAMESPACE::libc_errno = 0;
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanhf(0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanhf(-0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::atanhf(1.0f));
EXPECT_FP_EXCEPTION(FE_DIVBYZERO);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_DIVBYZERO);
EXPECT_MATH_ERRNO(ERANGE);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, LIBC_NAMESPACE::atanhf(-1.0f));
EXPECT_FP_EXCEPTION(FE_DIVBYZERO);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_DIVBYZERO);
EXPECT_MATH_ERRNO(ERANGE);

auto bt = FPBits(1.0f);
bt.set_uintval(bt.uintval() + 1);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val()));
EXPECT_FP_EXCEPTION(FE_INVALID);
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
bt.set_sign(Sign::NEG);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val()));
EXPECT_FP_EXCEPTION(FE_INVALID);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(2.0f));
EXPECT_FP_EXCEPTION(FE_INVALID);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(-2.0f));
EXPECT_FP_EXCEPTION(FE_INVALID);
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(inf));
EXPECT_FP_EXCEPTION(FE_INVALID);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

bt.set_sign(Sign::NEG);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(neg_inf));
EXPECT_FP_EXCEPTION(FE_INVALID);
// See above TODO
// EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
}

Expand Down
2 changes: 2 additions & 0 deletions libc/test/src/math/smoke/NextAfterTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"

// TODO: Strengthen errno,exception checks and remove these assert macros
// after new matchers/test fixtures are added
#define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception) \
ASSERT_FP_EQ(result, expected); \
ASSERT_FP_EXCEPTION(expected_exception); \
Expand Down
2 changes: 2 additions & 0 deletions libc/test/src/math/smoke/NextTowardTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"

// TODO: Strengthen errno,exception checks and remove these assert macros
// after new matchers/test fixtures are added
#define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception) \
ASSERT_FP_EQ(result, expected); \
ASSERT_FP_EXCEPTION(expected_exception); \
Expand Down
18 changes: 6 additions & 12 deletions libc/test/src/math/smoke/RoundToIntegerTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,7 @@ class RoundToIntegerTestTemplate
typedef I (*RoundToIntegerFunc)(F);

private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<F>;
using StorageType = typename FPBits::StorageType;

const F zero = FPBits::zero(Sign::POS).get_val();
const F neg_zero = FPBits::zero(Sign::NEG).get_val();
const F inf = FPBits::inf(Sign::POS).get_val();
const F neg_inf = FPBits::inf(Sign::NEG).get_val();
const F nan = FPBits::quiet_nan().get_val();
DECLARE_SPECIAL_CONSTANTS(F)

static constexpr StorageType MAX_SUBNORMAL =
FPBits::max_subnormal().uintval();
Expand All @@ -52,12 +45,13 @@ class RoundToIntegerTestTemplate

ASSERT_EQ(func(input), expected);

// TODO: Handle the !expectError case. It used to expect
// 0 for errno and exceptions, but this doesn't hold for
// all math functions using RoundToInteger test:
// https://github.com/llvm/llvm-project/pull/88816
if (expectError) {
ASSERT_FP_EXCEPTION(FE_INVALID);
ASSERT_MATH_ERRNO(EDOM);
} else {
ASSERT_FP_EXCEPTION(0);
ASSERT_MATH_ERRNO(0);
}
}

Expand All @@ -81,7 +75,7 @@ class RoundToIntegerTestTemplate
// libc/CMakeLists.txt is not forwarded to C++.
#if LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR
// Result is not well-defined, we always returns INTEGER_MAX
test_one_input(func, nan, INTEGER_MAX, true);
test_one_input(func, aNaN, INTEGER_MAX, true);
#endif // LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR
}

Expand Down
22 changes: 16 additions & 6 deletions libc/test/src/math/smoke/atan2f_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,43 @@ using LlvmLibcAtan2fTest = LIBC_NAMESPACE::testing::FPTest<float>;
TEST_F(LlvmLibcAtan2fTest, SpecialNumbers) {
LIBC_NAMESPACE::libc_errno = 0;

// TODO: Strengthen errno,exception checks and remove these assert macros
// after new matchers/test fixtures are added see:
// https://github.com/llvm/llvm-project/issues/90653.
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atan2f(aNaN, zero));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atan2f(1.0f, aNaN));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atan2f(zero, zero));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atan2f(-0.0f, zero));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atan2f(1.0f, inf));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atan2f(-1.0f, inf));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);
}
13 changes: 10 additions & 3 deletions libc/test/src/math/smoke/atanf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,25 @@ using LlvmLibcAtanfTest = LIBC_NAMESPACE::testing::FPTest<float>;
TEST_F(LlvmLibcAtanfTest, SpecialNumbers) {
LIBC_NAMESPACE::libc_errno = 0;

// TODO: Strengthen errno,exception checks and remove these assert macros
// after new matchers/test fixtures are added
// https://github.com/llvm/llvm-project/issues/90653
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanf(aNaN));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanf(0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanf(-0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);
}
14 changes: 10 additions & 4 deletions libc/test/src/math/smoke/atanhf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,28 @@
using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>;

TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {

LIBC_NAMESPACE::libc_errno = 0;

// TODO: Strengthen errno,exception checks and remove these assert macros
// after new matchers/test fixtures are added, see:
// https://github.com/llvm/llvm-project/issues/90653
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN));
EXPECT_FP_EXCEPTION(0);
// TODO: Uncomment these checks later, RoundingMode affects running
// tests in this way https://github.com/llvm/llvm-project/issues/90653.
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanhf(0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanhf(-0.0f));
EXPECT_FP_EXCEPTION(0);
// See above TODO
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::atanhf(1.0f), FE_DIVBYZERO);
Expand Down
Loading