Skip to content

Commit ff78cd5

Browse files
authored
[flang] fix private pointers and default initialized variables (#118494)
Both OpenMP privatization and DO CONCURRENT LOCAL lowering was incorrect for pointers and derived type with default initialization. For pointers, the descriptor was not established with the rank/type code/element size, leading to undefined behavior if any inquiry was made to it prior to a pointer assignment (and if/when using the runtime for pointer assignments, the descriptor must have been established). For derived type with default initialization, the copies were not default initialized.
1 parent ffb1c21 commit ff78cd5

File tree

7 files changed

+147
-19
lines changed

7 files changed

+147
-19
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,11 @@ class AbstractConverter {
118118

119119
/// For a given symbol which is host-associated, create a clone using
120120
/// parameters from the host-associated symbol.
121+
/// The clone is default initialized if its type has any default
122+
/// initialization unless `skipDefaultInit` is set.
121123
virtual bool
122-
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym) = 0;
124+
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym,
125+
bool skipDefaultInit) = 0;
123126

124127
virtual void
125128
createHostAssociateVarCloneDealloc(const Fortran::semantics::Symbol &sym) = 0;

flang/lib/Lower/Bridge.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -711,8 +711,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
711711
return bool(shallowLookupSymbol(sym));
712712
}
713713

714-
bool createHostAssociateVarClone(
715-
const Fortran::semantics::Symbol &sym) override final {
714+
bool createHostAssociateVarClone(const Fortran::semantics::Symbol &sym,
715+
bool skipDefaultInit) override final {
716716
mlir::Location loc = genLocation(sym.name());
717717
mlir::Type symType = genType(sym);
718718
const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
@@ -769,13 +769,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
769769
// Initialise cloned allocatable
770770
hexv.match(
771771
[&](const fir::MutableBoxValue &box) -> void {
772-
// Do not process pointers
772+
const auto new_box = exv.getBoxOf<fir::MutableBoxValue>();
773773
if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
774+
// Establish the pointer descriptors. The rank and type code/size
775+
// at least must be set properly for later inquiry of the pointer
776+
// to work, and new pointers are always given disassociated status
777+
// by flang for safety, even if this is not required by the
778+
// language.
779+
auto empty = fir::factory::createUnallocatedBox(
780+
*builder, loc, new_box->getBoxTy(), box.nonDeferredLenParams(),
781+
{});
782+
builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
774783
return;
775784
}
776-
// Allocate storage for a pointer/allocatble descriptor.
777-
// No shape/lengths to be passed to the alloca.
778-
const auto new_box = exv.getBoxOf<fir::MutableBoxValue>();
785+
// Copy allocation status of Allocatables, creating new storage if
786+
// needed.
779787

780788
// allocate if allocated
781789
mlir::Value isAllocated =
@@ -823,7 +831,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
823831
if_builder.end();
824832
},
825833
[&](const auto &) -> void {
826-
// Do nothing
834+
if (skipDefaultInit)
835+
return;
836+
// Initialize local/private derived types with default
837+
// initialization (Fortran 2023 section 11.1.7.5 and OpenMP 5.2
838+
// section 5.3). Pointer and allocatable components, when allowed,
839+
// also need to be established so that flang runtime can later work
840+
// with them.
841+
if (const Fortran::semantics::DeclTypeSpec *declTypeSpec =
842+
sym.GetType())
843+
if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
844+
declTypeSpec->AsDerived())
845+
if (derivedTypeSpec->HasDefaultInitialization(
846+
/*ignoreAllocatable=*/false, /*ignorePointer=*/false)) {
847+
mlir::Value box = builder->createBox(loc, exv);
848+
fir::runtime::genDerivedTypeInitialize(*builder, loc, box);
849+
}
827850
});
828851

829852
return bindIfNewSymbol(sym, exv);
@@ -1966,9 +1989,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
19661989
Fortran::semantics::SemanticsContext &semanticsContext =
19671990
bridge.getSemanticsContext();
19681991
for (const Fortran::semantics::Symbol *sym : info.localSymList)
1969-
createHostAssociateVarClone(*sym);
1992+
createHostAssociateVarClone(*sym, /*skipDefaultInit=*/false);
19701993
for (const Fortran::semantics::Symbol *sym : info.localInitSymList) {
1971-
createHostAssociateVarClone(*sym);
1994+
createHostAssociateVarClone(*sym, /*skipDefaultInit=*/true);
19721995
const auto *hostDetails =
19731996
sym->detailsIf<Fortran::semantics::HostAssocDetails>();
19741997
assert(hostDetails && "missing locality spec host symbol");
@@ -1986,6 +2009,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
19862009
sym->detailsIf<Fortran::semantics::HostAssocDetails>();
19872010
copySymbolBinding(hostDetails->symbol(), *sym);
19882011
}
2012+
// Note that allocatable, types with ultimate components, and type
2013+
// requiring finalization are forbidden in LOCAL/LOCAL_INIT (F2023 C1130),
2014+
// so no clean-up needs to be generated for these entities.
19892015
}
19902016

19912017
/// Generate FIR for a DO construct. There are six variants:

flang/lib/Lower/OpenMP/DataSharingProcessor.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,11 @@ void DataSharingProcessor::insertDeallocs() {
111111
}
112112

113113
void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
114-
bool success = converter.createHostAssociateVarClone(*sym);
114+
bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);
115+
bool success = converter.createHostAssociateVarClone(
116+
*sym, /*skipDefaultInit=*/isFirstPrivate);
115117
(void)success;
116118
assert(success && "Privatization failed due to existing binding");
117-
118-
bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);
119-
if (!isFirstPrivate &&
120-
Fortran::lower::hasDefaultInitialization(sym->GetUltimate()))
121-
Fortran::lower::defaultInitializeAtRuntime(converter, *sym, *symTable);
122119
}
123120

124121
void DataSharingProcessor::copyFirstPrivateSymbol(
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
! Test delayed privatization for derived types with default initialization.
2+
3+
! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --openmp-enable-delayed-privatization \
4+
! RUN: -o - %s 2>&1 | FileCheck %s
5+
! RUN: bbc -emit-hlfir -fopenmp --openmp-enable-delayed-privatization -o - %s 2>&1 |\
6+
! RUN: FileCheck %s
7+
8+
subroutine delayed_privatization_default_init
9+
implicit none
10+
type t
11+
integer :: i = 2
12+
end type
13+
integer :: i, res(4)
14+
type(t) :: a
15+
!$omp parallel private(a)
16+
call do_something(a%i)
17+
!$omp end parallel
18+
end subroutine
19+
20+
subroutine delayed_privatization_default_init_firstprivate
21+
implicit none
22+
type t
23+
integer :: i = 2
24+
end type
25+
integer :: i, res(4)
26+
type(t) :: a
27+
!$omp parallel firstprivate(a)
28+
call do_something(a%i)
29+
!$omp end parallel
30+
end subroutine
31+
32+
! CHECK-LABEL: omp.private {type = firstprivate} @_QFdelayed_privatization_default_init_firstprivateEa_firstprivate_ref_rec__QFdelayed_privatization_default_init_firstprivateTt : !fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>> alloc {
33+
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>>):
34+
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}> {bindc_name = "a", pinned, uniq_name = "_QFdelayed_privatization_default_init_firstprivateEa"}
35+
! CHECK-NEXT: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFdelayed_privatization_default_init_firstprivateEa"} : (!fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>>) -> (!fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>>, !fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>>)
36+
! CHECK: omp.yield(%[[VAL_9]]#0 : !fir.ref<!fir.type<_QFdelayed_privatization_default_init_firstprivateTt{i:i32}>>)
37+
! CHECK: }
38+
39+
! CHECK-LABEL: omp.private {type = private} @_QFdelayed_privatization_default_initEa_private_ref_rec__QFdelayed_privatization_default_initTt : !fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>> alloc {
40+
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>):
41+
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QFdelayed_privatization_default_initTt{i:i32}> {bindc_name = "a", pinned, uniq_name = "_QFdelayed_privatization_default_initEa"}
42+
! CHECK: %[[VAL_2:.*]] = fir.embox %[[VAL_1]] : (!fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>) -> !fir.box<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>
43+
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.box<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>) -> !fir.box<none>
44+
! CHECK: %[[VAL_8:.*]] = fir.call @_FortranAInitialize(%[[VAL_6]],{{.*}}
45+
! CHECK-NEXT: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFdelayed_privatization_default_initEa"} : (!fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>) -> (!fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>, !fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>)
46+
! CHECK: omp.yield(%[[VAL_9]]#0 : !fir.ref<!fir.type<_QFdelayed_privatization_default_initTt{i:i32}>>)
47+
! CHECK: }

flang/test/Lower/OpenMP/delayed-privatization-pointer.f90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ subroutine delayed_privatization_pointer
2020
! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: [[TYPE]]):
2121

2222
! CHECK-NEXT: %[[PRIV_ALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "var1", pinned, uniq_name = "_QFdelayed_privatization_pointerEvar1"}
23+
! CHECK-NEXT: %[[NULL:.*]] = fir.zero_bits !fir.ptr<i32>
24+
! CHECK-NEXT: %[[INIT:.*]] = fir.embox %[[NULL]] : (!fir.ptr<i32>) -> !fir.box<!fir.ptr<i32>>
25+
! CHECK-NEXT: fir.store %[[INIT]] to %[[PRIV_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
2326
! CHECK-NEXT: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[PRIV_ALLOC]]
2427
! CHECK-NEXT: omp.yield(%[[PRIV_DECL]]#0 : [[TYPE]])
2528

flang/test/Lower/OpenMP/private-derived-type.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ end subroutine s4
2828
! CHECK: %[[VAL_15:.*]] = fir.call @_FortranAInitialize(%[[VAL_13]], %[[VAL_14]], %[[VAL_12]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
2929
! CHECK: omp.parallel {
3030
! CHECK: %[[VAL_23:.*]] = fir.alloca !fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}> {bindc_name = "v", pinned, uniq_name = "_QFs4Ev"}
31-
! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFs4Ev"} : (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>)
32-
! CHECK: %[[VAL_25:.*]] = fir.embox %[[VAL_24]]#1 : (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> !fir.box<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>
31+
! CHECK: %[[VAL_25:.*]] = fir.embox %[[VAL_23]] : (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> !fir.box<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>
3332
! CHECK: %[[VAL_26:.*]] = fir.address_of
34-
! CHECK: %[[VAL_27:.*]] = arith.constant 4 : i32
33+
! CHECK: %[[VAL_27:.*]] = arith.constant 8 : i32
3534
! CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_25]] : (!fir.box<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> !fir.box<none>
3635
! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_26]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
3736
! Check we do call FortranAInitialize on the derived type
3837
! CHECK: %[[VAL_30:.*]] = fir.call @_FortranAInitialize(%[[VAL_28]], %[[VAL_29]], %[[VAL_27]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
38+
! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFs4Ev"} : (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>)
3939
! CHECK: omp.wsloop {
4040
! CHECK: }
4141
! CHECK: %[[VAL_39:.*]] = fir.embox %[[VAL_9]]#1 : (!fir.ref<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>) -> !fir.box<!fir.type<_QFs4Ty3{x:!fir.box<!fir.heap<i32>>}>>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
! Test default initialization of DO CONCURRENT LOCAL() entities.
2+
! RUN: bbc -emit-hlfir -I nowhere -o - %s | FileCheck %s
3+
4+
subroutine test_ptr(p)
5+
interface
6+
pure subroutine takes_ptr(p)
7+
character(*), intent(in), pointer :: p(:)
8+
end subroutine
9+
end interface
10+
character(*), pointer :: p(:)
11+
integer :: i
12+
do concurrent (i=1:10) local(p)
13+
call takes_ptr(p)
14+
end do
15+
end subroutine
16+
17+
subroutine test_default_init()
18+
type t
19+
integer :: i = 2
20+
end type
21+
integer :: i, res(4)
22+
type(t) :: a
23+
do concurrent (i=1:4) local(a)
24+
res(i) = a%i
25+
end do
26+
call something(res)
27+
end subroutine
28+
! CHECK-LABEL: func.func @_QPtest_ptr(
29+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>> {fir.bindc_name = "p"}) {
30+
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>
31+
! CHECK: %[[VAL_7:.*]] = fir.box_elesize %[[VAL_6]] : (!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>) -> index
32+
! CHECK: fir.do_loop
33+
! CHECK: %[[VAL_16:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>> {bindc_name = "p", pinned, uniq_name = "_QFtest_ptrEp"}
34+
! CHECK: %[[VAL_17:.*]] = fir.zero_bits !fir.ptr<!fir.array<?x!fir.char<1,?>>>
35+
! CHECK: %[[VAL_18:.*]] = arith.constant 0 : index
36+
! CHECK: %[[VAL_19:.*]] = fir.shape %[[VAL_18]] : (index) -> !fir.shape<1>
37+
! CHECK: %[[VAL_20:.*]] = fir.embox %[[VAL_17]](%[[VAL_19]]) typeparams %[[VAL_7]] : (!fir.ptr<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, index) -> !fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>
38+
! CHECK: fir.store %[[VAL_20]] to %[[VAL_16]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>
39+
! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_16]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtest_ptrEp"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>)
40+
! CHECK: fir.call @_QPtakes_ptr(%[[VAL_21]]#0) proc_attrs<pure> fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>>) -> ()
41+
! CHECK: }
42+
! CHECK: return
43+
! CHECK: }
44+
45+
! CHECK-LABEL: func.func @_QPtest_default_init(
46+
! CHECK: fir.do_loop
47+
! CHECK: %[[VAL_26:.*]] = fir.alloca !fir.type<_QFtest_default_initTt{i:i32}> {bindc_name = "a", pinned, uniq_name = "_QFtest_default_initEa"}
48+
! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_26]] : (!fir.ref<!fir.type<_QFtest_default_initTt{i:i32}>>) -> !fir.box<!fir.type<_QFtest_default_initTt{i:i32}>>
49+
! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_27]] : (!fir.box<!fir.type<_QFtest_default_initTt{i:i32}>>) -> !fir.box<none>
50+
! CHECK: %[[VAL_32:.*]] = fir.call @_FortranAInitialize(%[[VAL_30]], {{.*}}
51+
! CHECK: %[[VAL_33:.*]]:2 = hlfir.declare %[[VAL_26]] {uniq_name = "_QFtest_default_initEa"} : (!fir.ref<!fir.type<_QFtest_default_initTt{i:i32}>>) -> (!fir.ref<!fir.type<_QFtest_default_initTt{i:i32}>>, !fir.ref<!fir.type<_QFtest_default_initTt{i:i32}>>)
52+
! CHECK: }

0 commit comments

Comments
 (0)