[Flang][OpenMP] Lower allocatable or pointer in private clause

This patch lowers allocatables and pointers named in "private" OpenMP clause.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D148570
This commit is contained in:
Dmitriy Smirnov 2023-07-03 16:31:20 +00:00 committed by Kiran Chandramohan
parent ce2d44b0ab
commit bc4586da6e
6 changed files with 385 additions and 57 deletions

View File

@ -101,6 +101,9 @@ public:
virtual bool
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym) = 0;
virtual void
createHostAssociateVarCloneDealloc(const Fortran::semantics::Symbol &sym) = 0;
virtual void copyHostAssociateVar(
const Fortran::semantics::Symbol &sym,
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) = 0;

View File

@ -1158,7 +1158,7 @@ std::optional<Expr<SomeType>> DataConstantConversionExtension(
bool IsAllocatableOrPointerObject(
const Expr<SomeType> &expr, FoldingContext &context) {
const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
return (sym && semantics::IsAllocatableOrPointer(*sym)) ||
return (sym && semantics::IsAllocatableOrPointer(sym->GetUltimate())) ||
evaluate::IsObjectPointer(expr, context);
}

View File

@ -569,18 +569,23 @@ public:
const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
assert(details && "No host-association found");
const Fortran::semantics::Symbol &hsym = details->symbol();
mlir::Type hSymType = genType(hsym);
Fortran::lower::SymbolBox hsb = lookupSymbol(hsym);
auto allocate = [&](llvm::ArrayRef<mlir::Value> shape,
llvm::ArrayRef<mlir::Value> typeParams) -> mlir::Value {
mlir::Value allocVal = builder->allocateLocal(
loc, symType, mangleName(sym), toStringRef(sym.GetUltimate().name()),
loc,
Fortran::semantics::IsAllocatableOrPointer(hsym.GetUltimate())
? hSymType
: symType,
mangleName(sym), toStringRef(sym.GetUltimate().name()),
/*pinned=*/true, shape, typeParams,
sym.GetUltimate().attrs().test(Fortran::semantics::Attr::TARGET));
return allocVal;
};
fir::ExtendedValue hexv = getExtendedValue(hsb);
fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
fir::ExtendedValue exv = hexv.match(
[&](const fir::BoxValue &box) -> fir::ExtendedValue {
const Fortran::semantics::DeclTypeSpec *type = sym.GetType();
@ -602,8 +607,7 @@ public:
[&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
// Allocate storage for a pointer/allocatble descriptor.
// No shape/lengths to be passed to the alloca.
return fir::MutableBoxValue(allocate({}, {}),
box.nonDeferredLenParams(), {});
return fir::MutableBoxValue(allocate({}, {}), {}, {});
},
[&](const auto &) -> fir::ExtendedValue {
mlir::Value temp =
@ -612,9 +616,84 @@ public:
return fir::substBase(hexv, temp);
});
// Initialise cloned allocatable
hexv.match(
[&](const fir::MutableBoxValue &box) -> void {
// Do not process pointers
if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
return;
}
// Allocate storage for a pointer/allocatble descriptor.
// No shape/lengths to be passed to the alloca.
const auto new_box = exv.getBoxOf<fir::MutableBoxValue>();
// allocate if allocated
mlir::Value isAllocated =
fir::factory::genIsAllocatedOrAssociatedTest(*builder, loc, box);
auto if_builder = builder->genIfThenElse(loc, isAllocated);
if_builder.genThen([&]() {
std::string name = mangleName(sym) + ".alloc";
if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
fir::ExtendedValue read = fir::factory::genMutableBoxRead(
*builder, loc, box, /*mayBePolymorphic=*/false);
auto read_box = read.getBoxOf<fir::ArrayBoxValue>();
fir::factory::genInlinedAllocation(
*builder, loc, *new_box, read_box->getLBounds(),
read_box->getExtents(),
/*lenParams=*/std::nullopt, name,
/*mustBeHeap=*/true);
} else {
fir::factory::genInlinedAllocation(
*builder, loc, *new_box,
new_box->getMutableProperties().lbounds,
new_box->getMutableProperties().extents,
/*lenParams=*/std::nullopt, name,
/*mustBeHeap=*/true);
}
});
if_builder.genElse([&]() {
// nullify box
auto empty = fir::factory::createUnallocatedBox(
*builder, loc, new_box->getBoxTy(),
new_box->nonDeferredLenParams(), {});
builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
});
if_builder.end();
},
[&](const auto &) -> void {
// Do nothing
});
return bindIfNewSymbol(sym, exv);
}
void createHostAssociateVarCloneDealloc(
const Fortran::semantics::Symbol &sym) override final {
mlir::Location loc = genLocation(sym.name());
Fortran::lower::SymbolBox hsb = lookupSymbol(sym);
fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
hexv.match(
[&](const fir::MutableBoxValue &new_box) -> void {
// Do not process pointers
if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
return;
}
// deallocate allocated in createHostAssociateVarClone value
mlir::Value needs_dealloc =
fir::factory::genIsAllocatedOrAssociatedTest(*builder, loc,
new_box);
builder->genIfThen(loc, needs_dealloc)
.genThen([&]() {
Fortran::lower::genDeallocateBox(*this, new_box, loc);
})
.end();
},
[&](const auto &) -> void {
// Do nothing
});
}
void copyHostAssociateVar(
const Fortran::semantics::Symbol &sym,
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) override final {
@ -624,14 +703,14 @@ public:
const Fortran::semantics::Symbol &hsym = sym.GetUltimate();
Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym);
assert(hsb && "Host symbol box not found");
fir::ExtendedValue hexv = getExtendedValue(hsb);
fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
// 2) Fetch the copied one that will mask the original.
Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym);
assert(sb && "Host-associated symbol box not found");
assert(hsb.getAddr() != sb.getAddr() &&
"Host and associated symbol boxes are the same");
fir::ExtendedValue exv = getExtendedValue(sb);
fir::ExtendedValue exv = symBoxToExtendedValue(sb);
// 3) Perform the assignment.
mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
@ -653,6 +732,7 @@ public:
mlir::Location loc = genLocation(sym.name());
mlir::Type symType = genType(sym);
if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
Fortran::lower::StatementContext stmtCtx;
Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
@ -660,16 +740,15 @@ public:
stmtCtx.finalizeAndReset();
} else if (hexv.getBoxOf<fir::CharBoxValue>()) {
fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
} else if (hexv.getBoxOf<fir::MutableBoxValue>()) {
TODO(loc, "firstprivatisation of allocatable variables");
} else {
auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
}
if (copyAssignIP && copyAssignIP->isSet() &&
sym.test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
sym.test(Fortran::semantics::Symbol::Flag::OmpLastPrivate)) {
builder->restoreInsertionPoint(insPt);
}
}
//===--------------------------------------------------------------------===//
@ -918,15 +997,6 @@ private:
return true;
}
fir::ExtendedValue getExtendedValue(Fortran::lower::SymbolBox sb) {
fir::ExtendedValue exv = symBoxToExtendedValue(sb);
// Dereference pointers and allocatables.
if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
return fir::factory::genMutableBoxRead(*builder, getCurrentLocation(),
*box);
return exv;
}
/// Generate the address of loop variable \p sym.
/// If \p sym is not mapped yet, allocate local storage for it.
mlir::Value genLoopVariableAddress(mlir::Location loc,

View File

@ -99,6 +99,7 @@ class DataSharingProcessor {
void copyFirstPrivateSymbol(const Fortran::semantics::Symbol *sym);
void copyLastPrivateSymbol(const Fortran::semantics::Symbol *sym,
mlir::OpBuilder::InsertPoint *lastPrivIP);
void insertDeallocs();
public:
DataSharingProcessor(Fortran::lower::AbstractConverter &converter,
@ -114,20 +115,14 @@ public:
// construct, for looping constructs this is just before the Operation. The
// split into two steps was performed basically to be able to call
// privatisation for looping constructs before the operation is created since
// the bounds of the MLIR OpenMP operation can be privatised. Step2 performs
// the copying for lastprivates. Step2 requires knowledge of the MLIR
// operation to insert the last private update.
bool process(mlir::Operation *op);
// the bounds of the MLIR OpenMP operation can be privatised.
// Step2 performs the copying for lastprivates and requires knowledge of the
// MLIR operation to insert the last private update. Step2 adds
// dealocation code as well.
void processStep1();
bool processStep2(mlir::Operation *op);
void processStep2(mlir::Operation *op, bool is_loop);
};
bool DataSharingProcessor::process(mlir::Operation *op) {
processStep1();
assert(op && "Current MLIR operation not set");
return processStep2(op);
}
void DataSharingProcessor::processStep1() {
collectSymbolsForPrivatization();
collectDefaultSymbols();
@ -136,11 +131,29 @@ void DataSharingProcessor::processStep1() {
insertBarrier();
}
bool DataSharingProcessor::processStep2(mlir::Operation *op) {
void DataSharingProcessor::processStep2(mlir::Operation *op, bool is_loop) {
insPt = firOpBuilder.saveInsertionPoint();
copyLastPrivatize(op);
firOpBuilder.restoreInsertionPoint(insPt);
return hasLastPrivateOp;
if (is_loop) {
// push deallocs out of the loop
firOpBuilder.setInsertionPointAfter(op);
insertDeallocs();
} else {
// insert dummy instruction to mark the insertion position
mlir::Value undefMarker = firOpBuilder.create<fir::UndefOp>(
op->getLoc(), firOpBuilder.getIndexType());
insertDeallocs();
firOpBuilder.setInsertionPointAfter(undefMarker.getDefiningOp());
}
}
void DataSharingProcessor::insertDeallocs() {
for (auto sym : privatizedSymbols)
if (Fortran::semantics::IsAllocatable(sym->GetUltimate())) {
converter.createHostAssociateVarCloneDealloc(*sym);
}
}
void DataSharingProcessor::cloneSymbol(const Fortran::semantics::Symbol *sym) {
@ -694,26 +707,23 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
} else {
firOpBuilder.create<mlir::omp::TerminatorOp>(loc);
}
// Reset the insert point to before the terminator.
resetBeforeTerminator(firOpBuilder, storeOp, block);
// Handle privatization. Do not privatize if this is the outer operation.
if (clauses && !outerCombined) {
bool lastPrivateOp = false;
constexpr bool is_loop = std::is_same_v<Op, omp::WsLoopOp> ||
std::is_same_v<Op, omp::SimdLoopOp>;
if (!dsp) {
dsp = new DataSharingProcessor(converter, *clauses, eval);
lastPrivateOp = dsp->process(op);
delete dsp;
DataSharingProcessor proc(converter, *clauses, eval);
proc.processStep1();
proc.processStep2(op, is_loop);
} else {
lastPrivateOp = dsp->processStep2(op);
dsp->processStep2(op, is_loop);
}
// LastPrivatization, due to introduction of
// new control flow, changes the insertion point,
// thus restore it.
// TODO: Clean up later a bit to avoid this many sets and resets.
if (lastPrivateOp && !std::is_same_v<Op, omp::SectionOp>)
resetBeforeTerminator(firOpBuilder, storeOp, block);
if (storeOp)
firOpBuilder.setInsertionPointAfter(storeOp);
}
if constexpr (std::is_same_v<Op, omp::ParallelOp>) {

View File

@ -1062,7 +1062,7 @@ static void CheckAssociated(evaluate::ActualArguments &arguments,
if (const auto &pointerArg{arguments[0]}) {
if (const auto *pointerExpr{pointerArg->UnwrapExpr()}) {
const Symbol *pointerSymbol{GetLastSymbol(*pointerExpr)};
if (pointerSymbol && !IsPointer(*pointerSymbol)) {
if (pointerSymbol && !IsPointer(pointerSymbol->GetUltimate())) {
evaluate::AttachDeclaration(
context.messages().Say(pointerArg->sourceLocation(),
"POINTER= argument of ASSOCIATED() must be a POINTER"_err_en_US),

View File

@ -106,20 +106,23 @@ end subroutine
!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x2", uniq_name = "{{.*}}Ex2"}
!FIRDialect-DAG: {{.*}} = fir.alloca !fir.heap<!fir.array<?xi32>> {uniq_name = "{{.*}}Ex2.addr"}
!FIRDialect-DAG: {{.*}} = fir.address_of(@{{.*}}Ex3) : !fir.ref<!fir.box<!fir.heap<i32>>>
!FIRDialect-DAG: [[TMP9:%.*]] = fir.address_of(@{{.*}}Ex4) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!FIRDialect-DAG: [[TMP8:%.*]] = fir.address_of(@{{.*}}Ex4) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!FIRDialect: omp.parallel {
!FIRDialect-DAG: [[TMP37:%.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "{{.*}}Ex"}
!FIRDialect-DAG: [[TMP40:%.*]] = fir.alloca !fir.array<?xi32>, {{.*}} {bindc_name = "x2", pinned, uniq_name = "{{.*}}Ex2"}
!FIRDialect-DAG: [[TMP41:%.*]] = fir.alloca i32 {bindc_name = "x3", pinned, uniq_name = "{{.*}}Ex3"}
!FIRDialect-DAG: [[TMP42:%.*]] = fir.load [[TMP9]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!FIRDialect-DAG: [[TMP43:%.*]]:3 = fir.box_dims [[TMP42]], {{.*}} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
!FIRDialect-DAG: [[TMP44:%.*]] = fir.alloca !fir.array<?xi32>, [[TMP43]]#1 {bindc_name = "x4", pinned, uniq_name = "{{.*}}Ex4"}
!FIRDialect-DAG: [[TMP52:%.*]] = fir.embox [[TMP40]]({{.*}}) : (!fir.ref<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
!FIRDialect-DAG: {{.*}} = fir.convert [[TMP52]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
!FIRDialect-DAG: [[TMP58:%.*]] = fir.shape_shift [[TMP43]]#0, [[TMP43]]#1 : (index, index) -> !fir.shapeshift<1>
!FIRDialect-DAG: [[TMP59:%.*]] = fir.embox [[TMP44]]([[TMP58]]) : (!fir.ref<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
!FIRDialect-DAG: {{.*}} = fir.convert [[TMP59]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
!FIRDialect-DAG: [[TMP35:%.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x", pinned, uniq_name = "{{.*}}Ex"}
!FIRDialect-DAG: [[TMP39:%.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x2", pinned, uniq_name = "{{.*}}Ex2"}
!FIRDialect-DAG: [[TMP45:%.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x3", pinned, uniq_name = "{{.*}}Ex3"}
!FIRDialect-DAG: [[TMP51:%.*]] = fir.load [[TMP8]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!FIRDialect-DAG: [[TMP97:%.*]] = fir.load [[TMP8]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!FIRDialect-DAG: [[TMP98:%.*]]:3 = fir.box_dims [[TMP97]], {{.*}} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
!FIRDialect-DAG: [[TMP50:%.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x4", pinned, uniq_name = "{{.*}}Ex4"}
! FIRDialect-DAG: [[TMP101:%.*]] = fir.allocmem !fir.array<?xi32>, {{.*}} {fir.must_be_heap = true, uniq_name = "{{.*}}Ex4.alloc"}
! FIRDialect-DAG: [[TMP102:%.*]] = fir.shape_shift {{.*}}#0, {{.*}} : (index, index) -> !fir.shapeshift<1>
! FIRDialect-DAG: [[TMP103:%.*]] = fir.embox [[TMP101]]([[TMP102]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
! FIRDialect-DAG: fir.store [[TMP103]] to [[TMP50]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
subroutine private_clause_allocatable()
@ -133,3 +136,245 @@ subroutine private_clause_allocatable()
!$OMP END PARALLEL
end subroutine
!FIRDialect: func @_QPprivate_clause_real_call_allocatable() {
!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "x5", uniq_name = "{{.*}}Ex5"}
!FIRDialect-DAG: {{.*}} = fir.zero_bits !fir.heap<f32>
!FIRDialect-DAG: {{.*}} = fir.embox %1 : (!fir.heap<f32>) -> !fir.box<!fir.heap<f32>>
!FIRDialect-DAG: fir.store %2 to %0 : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: omp.parallel {
!FIRDialect-DAG: [[TMP203:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "x5", pinned, uniq_name = "{{.*}}Ex5"}
!FIRDialect-DAG: fir.if %7 {
!FIRDialect-DAG: fir.store %13 to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: } else {
!FIRDialect-DAG: fir.store %13 to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: }
!FIRDialect-DAG: fir.call @_QFprivate_clause_real_call_allocatablePhelper_private_clause_real_call_allocatable([[TMP203]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> ()
!FIRDialect-DAG: %8 = fir.load [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: fir.if %11 {
!FIRDialect-DAG: %12 = fir.load [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: fir.store %15 to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!FIRDialect-DAG: }
!FIRDialect-DAG: omp.terminator
!FIRDialect-DAG: }
!FIRDialect-DAG: return
!FIRDialect-DAG: }
subroutine private_clause_real_call_allocatable
real, allocatable :: x5
!$omp parallel private(x5)
call helper_private_clause_real_call_allocatable(x5)
!$omp end parallel
contains
subroutine helper_private_clause_real_call_allocatable(x6)
real, allocatable :: x6
print *, allocated(x6)
end subroutine
end subroutine
!FIRDialect: func.func @_QPincrement_list_items(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>>> {fir.bindc_name = "head"}) {
!FIRDialect: {{%.*}} = fir.alloca !fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>> {bindc_name = "p", uniq_name = "_QFincrement_list_itemsEp"}
!FIRDialect: omp.parallel {
!FIRDialect: {{%.*}} = fir.alloca !fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>> {bindc_name = "p", pinned, uniq_name = "_QFincrement_list_itemsEp"}
!FIRDialect: omp.single {
!FIRDialect: omp.terminator
!FIRDialect: omp.terminator
!FIRDialect: return
subroutine increment_list_items (head)
type node
integer :: payload
type (node), pointer :: next
end type node
type (node), pointer :: head
type (node), pointer :: p
!$omp parallel private(p)
!$omp single
p => head
do
p => p%next
if ( associated (p) .eqv. .false. ) exit
end do
!$omp end single
!$omp end parallel
end subroutine increment_list_items
!FIRDialect: func.func @_QPparallel_pointer() {
!FIRDialect-DAG: [[PP0:%.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "y1", uniq_name = "{{.*}}Ey1"}
!FIRDialect-DAG: [[PP1:%.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "{{.*}}Ey1.addr"}
!FIRDialect-DAG: [[PP2:%.*]] = fir.zero_bits !fir.ptr<i32>
!FIRDialect: fir.store [[PP2]] to [[PP1]] : !fir.ref<!fir.ptr<i32>>
!FIRDialect-DAG: [[PP3:%.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "y2", uniq_name = "{{.*}}Ey2"}
!FIRDialect: fir.store %6 to %3 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
!FIRDialect-DAG: [[PP7:%.*]] = fir.alloca i32 {bindc_name = "z1", fir.target, uniq_name = "{{.*}}Ez1"}
!FIRDialect-DAG: [[PP8:%.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "z2", fir.target, uniq_name = "{{.*}}Ez2"}
!FIRDialect: omp.parallel {
!FIRDialect-DAG: [[PP9:%.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "y1", pinned, uniq_name = "{{.*}}Ey1"}
!FIRDialect-DAG: [[PP10:%.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "y2", pinned, uniq_name = "{{.*}}Ey2"}
!FIRDialect-DAG: [[PP11:%.*]] = fir.embox [[PP7]] : (!fir.ref<i32>) -> !fir.box<!fir.ptr<i32>>
!FIRDialect: fir.store [[PP11]] to [[PP9]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
!FIRDialect-DAG: [[PP12:%.*]] = fir.shape %c{{.*}} : (index) -> !fir.shape<1>
!FIRDialect-DAG: [[PP13:%.*]] = fir.embox [[PP8]]([[PP12]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
!FIRDialect: fir.store %13 to [[PP10]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
!FIRDialect: omp.terminator
!FIRDialect: }
!FIRDialect: return
!FIRDialect: }
subroutine parallel_pointer()
integer, pointer :: y1, y2(:)
integer, target :: z1, z2(10)
!$omp parallel private(y1, y2)
y1=>z1
y2=>z2
!$omp end parallel
end subroutine parallel_pointer
!FIRDialect-LABEL: func @_QPsimple_loop_1()
subroutine simple_loop_1
integer :: i
real, allocatable :: r;
! FIRDialect: omp.parallel
!$OMP PARALLEL PRIVATE(r)
! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned}
! FIRDialect: [[R:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32
! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32
! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32
! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]])
!$OMP DO
do i=1, 9
! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref<i32>
! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
print*, i
end do
! FIRDialect: omp.yield
! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.if {{%.*}} {
! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!$OMP END DO
! FIRDialect: omp.terminator
!$OMP END PARALLEL
end subroutine
!FIRDialect-LABEL: func @_QPsimple_loop_2()
subroutine simple_loop_2
integer :: i
real, allocatable :: r;
! FIRDialect: omp.parallel
!$OMP PARALLEL
! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned}
! FIRDialect: [[R:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32
! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32
! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32
! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]])
!$OMP DO PRIVATE(r)
do i=1, 9
! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref<i32>
! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
print*, i
end do
! FIRDialect: omp.yield
! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.if {{%.*}} {
! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!$OMP END DO
! FIRDialect: omp.terminator
!$OMP END PARALLEL
end subroutine
!FIRDialect-LABEL: func @_QPsimple_loop_3()
subroutine simple_loop_3
integer :: i
real, allocatable :: r;
! FIRDialect: omp.parallel
! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned}
! FIRDialect: [[R:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32
! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32
! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32
! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]])
!$OMP PARALLEL DO PRIVATE(r)
do i=1, 9
! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref<i32>
! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
print*, i
end do
! FIRDialect: omp.yield
! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.if {{%.*}} {
! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
!$OMP END PARALLEL DO
! FIRDialect: omp.terminator
end subroutine
!CHECK-LABEL: func @_QPsimd_loop_1()
subroutine simd_loop_1
integer :: i
real, allocatable :: r;
! IRDialect: [[R:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
! IRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! IRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: %[[LB:.*]] = arith.constant 1 : i32
! FIRDialect: %[[UB:.*]] = arith.constant 9 : i32
! FIRDialect: %[[STEP:.*]] = arith.constant 1 : i32
! FIRDialect: omp.simdloop for (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) {
!$OMP SIMD PRIVATE(r)
do i=1, 9
! FIRDialect: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref<i32>
! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[LOCAL]] : !fir.ref<i32>
! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
print*, i
end do
!$OMP END SIMD
! FIRDialect: omp.yield
! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: fir.if {{%.*}} {
! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
end subroutine