[flang-commits] [flang] [llvm] [Flang][OpenMP] Align map clause generation and fix issue with non-shared allocations for assumed shape/size descriptor types (PR #97855)
via flang-commits
flang-commits at lists.llvm.org
Fri Aug 2 06:54:41 PDT 2024
https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/97855
>From 124ea29d4062bf5ff9e826926f8aa4c47cb88bbb Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 5 Jul 2024 14:39:49 -0500
Subject: [PATCH 1/3] [Flang][OpenMP] Align map clause generation and fix
issue with non-shared allocations for assumed shape/size descriptor types
This PR aims to unify the map argument generation behavior across both the implicit capture (captured in a target region) and the explicit capture (process map), currently the varPtr field of the MapInfo for the same variable will be different depending on how it's captured. This PR tries to align that across the generations of MapInfoOp in the OpenMP lowering.
Currently, I have opted to utilise the rawInput (input memref to a HLFIR DeclareInfoOp) as opposed to the addr field which includes more information. The side affect of this is that we have to deal with BoxTypes less often, which will result in simpler maps in these cases. The negative side affect of this is that we don't have access to the bounds information through the resulting value, however, I believe the bounds information we require in our case is still appropriately stored in the map bounds, and this seems to be the case from testing so far.
The other fix is for cases where we end up with a BoxType argument into a function (certain assumed shape and sizes cases do this) that has no fir.ref wrapping it. As we need the Box to be a reference type to actually utilise the operation to access the base address stored inside and create the correct mappings we currently generate an intermediate allocation in these cases, and then store into it, and utilise this as the map argument, as opposed to the original.
However, as we were not sharing the same intermediate allocation across all of the maps for a variable, this resulted in errors in certain cases when detatching/attatching the data e.g. via enter and exit. This PR adjusts this for cases
Currently we only maintain tracking of all intermediate allocations for the current function scope, as opposed to module. Primarily as the only case I am aware of that this is required is in cases where we pass certain types of arguments to functions (so I opted to minimize the overhead of the pass for now). It could likely be extended to module scope if required if we find other cases where it's applicable and causing issues.
---
.../flang/Optimizer/Transforms/Passes.td | 6 +-
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 16 +-
flang/lib/Lower/OpenMP/ClauseProcessor.h | 10 +-
flang/lib/Lower/OpenMP/OpenMP.cpp | 152 +++++++++---------
.../Transforms/OMPMapInfoFinalization.cpp | 44 +++--
flang/test/Lower/OpenMP/array-bounds.f90 | 13 +-
flang/test/Lower/OpenMP/common-block-map.f90 | 2 +-
flang/test/Lower/OpenMP/derived-type-map.f90 | 2 +-
flang/test/Lower/OpenMP/target.f90 | 23 ++-
9 files changed, 141 insertions(+), 127 deletions(-)
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 786083f95e15c..e8a3e5c689a17 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -341,11 +341,11 @@ def LoopVersioning : Pass<"loop-versioning", "mlir::func::FuncOp"> {
}
def OMPMapInfoFinalizationPass
- : Pass<"omp-map-info-finalization"> {
+ : Pass<"omp-map-info-finalization", "mlir::func::FuncOp"> {
let summary = "expands OpenMP MapInfo operations containing descriptors";
let description = [{
- Expands MapInfo operations containing descriptor types into multiple
- MapInfo's for each pointer element in the descriptor that requires
+ Expands MapInfo operations containing descriptor types into multiple
+ MapInfo's for each pointer element in the descriptor that requires
explicit individual mapping by the OpenMP runtime.
}];
let dependentDialects = ["mlir::omp::OpenMPDialect"];
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 310c0b0b5fb63..ecbce5fa1177a 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -978,25 +978,21 @@ bool ClauseProcessor::processMap(
object.ref(), clauseLocation, asFortran, bounds,
treatIndexAsSection);
- auto origSymbol = converter.getSymbolAddress(*object.sym());
- mlir::Value symAddr = info.addr;
- if (origSymbol && fir::isTypeWithDescriptor(origSymbol.getType()))
- symAddr = origSymbol;
-
// Explicit map captures are captured ByRef by default,
// optimisation passes may alter this to ByCopy or other capture
// types to optimise
+ mlir::Value baseOp = info.rawInput;
auto location = mlir::NameLoc::get(
mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()),
- symAddr.getLoc());
+ baseOp.getLoc());
mlir::omp::MapInfoOp mapOp = createMapInfoOp(
- firOpBuilder, location, symAddr,
+ firOpBuilder, location, baseOp,
/*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds,
/*members=*/{}, /*membersIndex=*/mlir::DenseIntElementsAttr{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
mapTypeBits),
- mlir::omp::VariableCaptureKind::ByRef, symAddr.getType());
+ mlir::omp::VariableCaptureKind::ByRef, baseOp.getType());
if (object.sym()->owner().IsDerivedType()) {
addChildIndexAndMapToParent(object, parentMemberIndices, mapOp,
@@ -1005,9 +1001,9 @@ bool ClauseProcessor::processMap(
result.mapVars.push_back(mapOp);
ptrMapSyms->push_back(object.sym());
if (mapSymTypes)
- mapSymTypes->push_back(symAddr.getType());
+ mapSymTypes->push_back(baseOp.getType());
if (mapSymLocs)
- mapSymLocs->push_back(symAddr.getLoc());
+ mapSymLocs->push_back(baseOp.getLoc());
}
}
});
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 2c4b3857fda9f..4bd491832b9f0 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -212,22 +212,18 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
object.ref(), clauseLocation, asFortran, bounds,
treatIndexAsSection);
- auto origSymbol = converter.getSymbolAddress(*object.sym());
- mlir::Value symAddr = info.addr;
- if (origSymbol && fir::isTypeWithDescriptor(origSymbol.getType()))
- symAddr = origSymbol;
-
// Explicit map captures are captured ByRef by default,
// optimisation passes may alter this to ByCopy or other capture
// types to optimise
+ mlir::Value baseOp = info.rawInput;
mlir::omp::MapInfoOp mapOp = createMapInfoOp(
- firOpBuilder, clauseLocation, symAddr,
+ firOpBuilder, clauseLocation, baseOp,
/*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds,
/*members=*/{}, /*membersIndex=*/mlir::DenseIntElementsAttr{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
mapTypeBits),
- mlir::omp::VariableCaptureKind::ByRef, symAddr.getType());
+ mlir::omp::VariableCaptureKind::ByRef, baseOp.getType());
if (object.sym()->owner().IsDerivedType()) {
addChildIndexAndMapToParent(object, parentMemberIndices, mapOp,
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 2b1839b5270d4..e3cba6b765810 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1693,6 +1693,12 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
if (dsp.getAllSymbolsToPrivatize().contains(&sym))
return;
+ // Structure component symbols don't have bindings, and can only be
+ // explicitly mapped individually. If a member is captured implicitly
+ // we map the entirety of the derived type when we find its symbol.
+ if (sym.owner().IsDerivedType())
+ return;
+
// if the symbol is part of an already mapped common block, do not make a
// map for it.
if (const Fortran::semantics::Symbol *common =
@@ -1700,85 +1706,85 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
if (llvm::find(mapSyms, common) != mapSyms.end())
return;
- if (llvm::find(mapSyms, &sym) == mapSyms.end()) {
- mlir::Value baseOp = converter.getSymbolAddress(sym);
- if (!baseOp)
- if (const auto *details =
- sym.template detailsIf<semantics::HostAssocDetails>()) {
- baseOp = converter.getSymbolAddress(details->symbol());
- converter.copySymbolBinding(details->symbol(), sym);
- }
+ // If we come across a symbol without a symbol address, we
+ // return as we cannot process it, this is intended as a
+ // catch all early exit for symbols that do not have a
+ // corresponding extended value. Such as subroutines,
+ // interfaces and named blocks.
+ if (!converter.getSymbolAddress(sym))
+ return;
- if (baseOp) {
- llvm::SmallVector<mlir::Value> bounds;
- std::stringstream name;
- fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(sym);
- name << sym.name().ToString();
-
- lower::AddrAndBoundsInfo info = getDataOperandBaseAddr(
- converter, firOpBuilder, sym, converter.getCurrentLocation());
- if (mlir::isa<fir::BaseBoxType>(
- fir::unwrapRefType(info.addr.getType())))
- bounds = lower::genBoundsOpsFromBox<mlir::omp::MapBoundsOp,
- mlir::omp::MapBoundsType>(
- firOpBuilder, converter.getCurrentLocation(), dataExv, info);
- if (mlir::isa<fir::SequenceType>(
- fir::unwrapRefType(info.addr.getType()))) {
- bool dataExvIsAssumedSize =
- semantics::IsAssumedSizeArray(sym.GetUltimate());
- bounds = lower::genBaseBoundsOps<mlir::omp::MapBoundsOp,
- mlir::omp::MapBoundsType>(
- firOpBuilder, converter.getCurrentLocation(), dataExv,
- dataExvIsAssumedSize);
- }
+ if (llvm::find(mapSyms, &sym) == mapSyms.end()) {
+ if (const auto *details =
+ sym.template detailsIf<semantics::HostAssocDetails>())
+ converter.copySymbolBinding(details->symbol(), sym);
+ llvm::SmallVector<mlir::Value> bounds;
+ std::stringstream name;
+ fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(sym);
+ name << sym.name().ToString();
+
+ lower::AddrAndBoundsInfo info = getDataOperandBaseAddr(
+ converter, firOpBuilder, sym, converter.getCurrentLocation());
+ mlir::Value baseOp = info.rawInput;
+ if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(baseOp.getType())))
+ bounds = lower::genBoundsOpsFromBox<mlir::omp::MapBoundsOp,
+ mlir::omp::MapBoundsType>(
+ firOpBuilder, converter.getCurrentLocation(), dataExv, info);
+ if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(baseOp.getType()))) {
+ bool dataExvIsAssumedSize =
+ semantics::IsAssumedSizeArray(sym.GetUltimate());
+ bounds = lower::genBaseBoundsOps<mlir::omp::MapBoundsOp,
+ mlir::omp::MapBoundsType>(
+ firOpBuilder, converter.getCurrentLocation(), dataExv,
+ dataExvIsAssumedSize);
+ }
- llvm::omp::OpenMPOffloadMappingFlags mapFlag =
- llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
- mlir::omp::VariableCaptureKind captureKind =
- mlir::omp::VariableCaptureKind::ByRef;
-
- mlir::Type eleType = baseOp.getType();
- if (auto refType = mlir::dyn_cast<fir::ReferenceType>(baseOp.getType()))
- eleType = refType.getElementType();
-
- // If a variable is specified in declare target link and if device
- // type is not specified as `nohost`, it needs to be mapped tofrom
- mlir::ModuleOp mod = firOpBuilder.getModule();
- mlir::Operation *op = mod.lookupSymbol(converter.mangleName(sym));
- auto declareTargetOp =
- llvm::dyn_cast_if_present<mlir::omp::DeclareTargetInterface>(op);
- if (declareTargetOp && declareTargetOp.isDeclareTarget()) {
- if (declareTargetOp.getDeclareTargetCaptureClause() ==
- mlir::omp::DeclareTargetCaptureClause::link &&
- declareTargetOp.getDeclareTargetDeviceType() !=
- mlir::omp::DeclareTargetDeviceType::nohost) {
- mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
- mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
- }
- } else if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
- captureKind = mlir::omp::VariableCaptureKind::ByCopy;
- } else if (!fir::isa_builtin_cptr_type(eleType)) {
+ llvm::omp::OpenMPOffloadMappingFlags mapFlag =
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
+ mlir::omp::VariableCaptureKind captureKind =
+ mlir::omp::VariableCaptureKind::ByRef;
+
+ mlir::Type eleType = baseOp.getType();
+ if (auto refType = mlir::dyn_cast<fir::ReferenceType>(baseOp.getType()))
+ eleType = refType.getElementType();
+
+ // If a variable is specified in declare target link and if device
+ // type is not specified as `nohost`, it needs to be mapped tofrom
+ mlir::ModuleOp mod = firOpBuilder.getModule();
+ mlir::Operation *op = mod.lookupSymbol(converter.mangleName(sym));
+ auto declareTargetOp =
+ llvm::dyn_cast_if_present<mlir::omp::DeclareTargetInterface>(op);
+ if (declareTargetOp && declareTargetOp.isDeclareTarget()) {
+ if (declareTargetOp.getDeclareTargetCaptureClause() ==
+ mlir::omp::DeclareTargetCaptureClause::link &&
+ declareTargetOp.getDeclareTargetDeviceType() !=
+ mlir::omp::DeclareTargetDeviceType::nohost) {
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
}
- auto location =
- mlir::NameLoc::get(mlir::StringAttr::get(firOpBuilder.getContext(),
- sym.name().ToString()),
- baseOp.getLoc());
- mlir::Value mapOp = createMapInfoOp(
- firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{},
- name.str(), bounds, /*members=*/{},
- /*membersIndex=*/mlir::DenseIntElementsAttr{},
- static_cast<
- std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
- mapFlag),
- captureKind, baseOp.getType());
-
- clauseOps.mapVars.push_back(mapOp);
- mapSyms.push_back(&sym);
- mapLocs.push_back(baseOp.getLoc());
- mapTypes.push_back(baseOp.getType());
+ } else if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
+ captureKind = mlir::omp::VariableCaptureKind::ByCopy;
+ } else if (!fir::isa_builtin_cptr_type(eleType)) {
+ mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
+ mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
}
+ auto location =
+ mlir::NameLoc::get(mlir::StringAttr::get(firOpBuilder.getContext(),
+ sym.name().ToString()),
+ baseOp.getLoc());
+ mlir::Value mapOp = createMapInfoOp(
+ firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{},
+ name.str(), bounds, /*members=*/{},
+ /*membersIndex=*/mlir::DenseIntElementsAttr{},
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ mapFlag),
+ captureKind, baseOp.getType());
+
+ clauseOps.mapVars.push_back(mapOp);
+ mapSyms.push_back(&sym);
+ mapLocs.push_back(baseOp.getLoc());
+ mapTypes.push_back(baseOp.getType());
}
};
lower::pft::visitAllSymbols(eval, captureImplicitMap);
diff --git a/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp b/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
index ddaa3c5f404f0..eeeb4de98e363 100644
--- a/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
+++ b/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
@@ -51,6 +51,14 @@ class OMPMapInfoFinalizationPass
: public fir::impl::OMPMapInfoFinalizationPassBase<
OMPMapInfoFinalizationPass> {
+ /// Tracks any intermediate function/subroutine local allocations we
+ /// generate for the descriptors of box type dummy arguments, so that
+ /// we can retrieve it for subsequent reuses within the functions
+ /// scope
+ std::map</*descriptor opaque pointer=*/void *,
+ /*corresponding local alloca=*/fir::AllocaOp>
+ localBoxAllocas;
+
void genDescriptorMemberMaps(mlir::omp::MapInfoOp op,
fir::FirOpBuilder &builder,
mlir::Operation *target) {
@@ -75,14 +83,26 @@ class OMPMapInfoFinalizationPass
// perform an alloca and then store to it and retrieve the data from the new
// alloca.
if (mlir::isa<fir::BaseBoxType>(descriptor.getType())) {
- mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint();
- mlir::Block *allocaBlock = builder.getAllocaBlock();
- assert(allocaBlock && "No alloca block found for this top level op");
- builder.setInsertionPointToStart(allocaBlock);
- auto alloca = builder.create<fir::AllocaOp>(loc, descriptor.getType());
- builder.restoreInsertionPoint(insPt);
- builder.create<fir::StoreOp>(loc, descriptor, alloca);
- descriptor = alloca;
+ // if we have already created a local allocation for this BoxType,
+ // we must be sure to re-use it so that we end up with the same
+ // allocations being utilised for the same descriptor across all map uses,
+ // this prevents runtime issues such as not appropriately releasing or
+ // deleting all mapped data.
+ auto find = localBoxAllocas.find(descriptor.getAsOpaquePointer());
+ if (find != localBoxAllocas.end()) {
+ builder.create<fir::StoreOp>(loc, descriptor, find->second);
+ descriptor = find->second;
+ } else {
+ mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint();
+ mlir::Block *allocaBlock = builder.getAllocaBlock();
+ assert(allocaBlock && "No alloca block found for this top level op");
+ builder.setInsertionPointToStart(allocaBlock);
+ auto alloca = builder.create<fir::AllocaOp>(loc, descriptor.getType());
+ builder.restoreInsertionPoint(insPt);
+ builder.create<fir::StoreOp>(loc, descriptor, alloca);
+ localBoxAllocas[descriptor.getAsOpaquePointer()] = alloca;
+ descriptor = alloca;
+ }
}
mlir::Value baseAddrAddr = builder.create<fir::BoxOffsetOp>(
@@ -228,14 +248,12 @@ class OMPMapInfoFinalizationPass
// operation (usually function) containing the MapInfoOp because this pass
// will mutate siblings of MapInfoOp.
void runOnOperation() override {
- mlir::ModuleOp module =
- mlir::dyn_cast_or_null<mlir::ModuleOp>(getOperation());
- if (!module)
- module = getOperation()->getParentOfType<mlir::ModuleOp>();
+ mlir::func::FuncOp func = getOperation();
+ mlir::ModuleOp module = func->getParentOfType<mlir::ModuleOp>();
fir::KindMapping kindMap = fir::getKindMapping(module);
fir::FirOpBuilder builder{module, std::move(kindMap)};
- getOperation()->walk([&](mlir::omp::MapInfoOp op) {
+ func->walk([&](mlir::omp::MapInfoOp op) {
// TODO: Currently only supports a single user for the MapInfoOp, this
// is fine for the moment as the Fortran Frontend will generate a
// new MapInfoOp per Target operation for the moment. However, when/if
diff --git a/flang/test/Lower/OpenMP/array-bounds.f90 b/flang/test/Lower/OpenMP/array-bounds.f90
index f235d5041ab26..55462daddfbc2 100644
--- a/flang/test/Lower/OpenMP/array-bounds.f90
+++ b/flang/test/Lower/OpenMP/array-bounds.f90
@@ -15,12 +15,12 @@
!HOST: %[[C2:.*]] = arith.constant 1 : index
!HOST: %[[C3:.*]] = arith.constant 4 : index
!HOST: %[[BOUNDS0:.*]] = omp.map.bounds lower_bound(%[[C2]] : index) upper_bound(%[[C3]] : index) extent(%[[C10]] : index) stride(%[[C1]] : index) start_idx(%[[C1]] : index)
-!HOST: %[[MAP0:.*]] = omp.map.info var_ptr(%[[READ_DECL]]#0 : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS0]]) -> !fir.ref<!fir.array<10xi32>> {name = "sp_read(2:5)"}
+!HOST: %[[MAP0:.*]] = omp.map.info var_ptr(%[[READ_DECL]]#1 : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS0]]) -> !fir.ref<!fir.array<10xi32>> {name = "sp_read(2:5)"}
!HOST: %[[C4:.*]] = arith.constant 1 : index
!HOST: %[[C5:.*]] = arith.constant 1 : index
!HOST: %[[C6:.*]] = arith.constant 4 : index
!HOST: %[[BOUNDS1:.*]] = omp.map.bounds lower_bound(%[[C5]] : index) upper_bound(%[[C6]] : index) extent(%[[C10_0]] : index) stride(%[[C4]] : index) start_idx(%[[C4]] : index)
-!HOST: %[[MAP1:.*]] = omp.map.info var_ptr(%[[WRITE_DECL]]#0 : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS1]]) -> !fir.ref<!fir.array<10xi32>> {name = "sp_write(2:5)"}
+!HOST: %[[MAP1:.*]] = omp.map.info var_ptr(%[[WRITE_DECL]]#1 : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS1]]) -> !fir.ref<!fir.array<10xi32>> {name = "sp_write(2:5)"}
!HOST: omp.target map_entries(%[[MAP0]] -> %{{.*}}, %[[MAP1]] -> %{{.*}}, {{.*}} -> {{.*}} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>, !fir.ref<i32>) {
subroutine read_write_section()
@@ -65,9 +65,10 @@ subroutine assumed_shape_array(arr_read_write)
end subroutine assumed_shape_array
+
+
!HOST-LABEL: func.func @_QMassumed_array_routinesPassumed_size_array(
!HOST-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "arr_read_write"}) {
-!HOST: %[[INTERMEDIATE_ALLOCA:.*]] = fir.alloca !fir.box<!fir.array<?xi32>>
!HOST: %[[ARG0_SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
!HOST: %[[ARG0_DECL:.*]]:2 = hlfir.declare %[[ARG0]](%[[ARG0_SHAPE]]) dummy_scope %{{[0-9]+}} {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QMassumed_array_routinesFassumed_size_arrayEarr_read_write"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
!HOST: %[[ALLOCA:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QMassumed_array_routinesFassumed_size_arrayEi"}
@@ -75,10 +76,8 @@ end subroutine assumed_shape_array
!HOST: %[[C4_1:.*]] = arith.subi %c4, %c1{{.*}} : index
!HOST: %[[EXT:.*]] = arith.addi %[[C4_1]], %c1{{.*}} : index
!HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%c1{{.*}} : index) upper_bound(%c4{{.*}} : index) extent(%[[EXT]] : index) stride(%[[DIMS0]]#2 : index) start_idx(%c1{{.*}} : index) {stride_in_bytes = true}
-!HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[INTERMEDIATE_ALLOCA]] base_addr : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
-!HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.array<?xi32>) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.array<?xi32>> {name = "arr_read_write(2:5)"}
-!HOST: omp.target map_entries(%[[MAP_INFO_MEMBER]] -> %{{.*}}, %[[MAP]] -> %{{.*}}, {{.*}} -> {{.*}} : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) {
+!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[ARG0_DECL]]#1 : !fir.ref<!fir.array<?xi32>>, !fir.array<?xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<?xi32>> {name = "arr_read_write(2:5)"}
+!HOST: omp.target map_entries(%[[MAP]] -> %{{.*}}, {{.*}} -> {{.*}} : !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) {
subroutine assumed_size_array(arr_read_write)
integer, intent(inout) :: arr_read_write(*)
diff --git a/flang/test/Lower/OpenMP/common-block-map.f90 b/flang/test/Lower/OpenMP/common-block-map.f90
index 5033129683a8e..0c423efd5eef4 100644
--- a/flang/test/Lower/OpenMP/common-block-map.f90
+++ b/flang/test/Lower/OpenMP/common-block-map.f90
@@ -40,7 +40,7 @@ subroutine map_full_block
!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CB_CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFmap_mix_of_membersEvar2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[MAP_EXP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_2]]#0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "var2"}
+!CHECK: %[[MAP_EXP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_2]]#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "var2"}
!CHECK: %[[MAP_IMP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_1]]#1 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = "var1"}
!CHECK: omp.target map_entries(%[[MAP_EXP]] -> %[[ARG_EXP:.*]], %[[MAP_IMP]] -> %[[ARG_IMP:.*]] : !fir.ref<i32>, !fir.ref<i32>) {
!CHECK: ^bb0(%[[ARG_EXP]]: !fir.ref<i32>, %[[ARG_IMP]]: !fir.ref<i32>):
diff --git a/flang/test/Lower/OpenMP/derived-type-map.f90 b/flang/test/Lower/OpenMP/derived-type-map.f90
index 6121b450f0620..30b89e90470b0 100644
--- a/flang/test/Lower/OpenMP/derived-type-map.f90
+++ b/flang/test/Lower/OpenMP/derived-type-map.f90
@@ -21,7 +21,7 @@ end subroutine mapType_derived_implicit
!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}> {bindc_name = "scalar_arr", uniq_name = "_QFmaptype_derived_explicitEscalar_arr"}
!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "_QFmaptype_derived_explicitEscalar_arr"} : (!fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>) -> (!fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>, !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>)
-!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#0 : !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>, !fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>> {name = "scalar_arr"}
+!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>, !fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>> {name = "scalar_arr"}
!CHECK: omp.target map_entries(%[[MAP]] -> %[[ARG0:.*]] : !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>) {
!CHECK: ^bb0(%[[ARG0]]: !fir.ref<!fir.type<_QFmaptype_derived_explicitTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>>):
subroutine mapType_derived_explicit
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 9b92293cbf92f..1d5ab6942dfa3 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -189,7 +189,7 @@ subroutine omp_target_update_depend
!$omp end task
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds
- !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_update depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
!$omp target update to(a) depend(in:a)
end subroutine omp_target_update_depend
@@ -205,7 +205,7 @@ subroutine omp_target_update_to
!CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}})
!CHECK-DAG: %[[BOUNDS:.*]] = omp.map.bounds
- !CHECK: %[[TO_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>)
+ !CHECK: %[[TO_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>)
!CHECK-SAME: map_clauses(to) capture(ByRef)
!CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
@@ -224,7 +224,7 @@ subroutine omp_target_update_from
!CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}})
!CHECK-DAG: %[[BOUNDS:.*]] = omp.map.bounds
- !CHECK: %[[FROM_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>)
+ !CHECK: %[[FROM_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>)
!CHECK-SAME: map_clauses(from) capture(ByRef)
!CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
@@ -292,7 +292,7 @@ subroutine omp_target_data
!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[VAL_0]](%{{.*}}) {uniq_name = "_QFomp_target_dataEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
integer :: a(1024)
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
- !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) {
!$omp target data map(tofrom: a)
!CHECK: %[[C10:.*]] = arith.constant 10 : i32
@@ -314,14 +314,14 @@ subroutine omp_target_data_mt
!CHECK: %[[VAR_B:.*]] = fir.alloca !fir.array<1024xi32> {bindc_name = "b", uniq_name = "_QFomp_target_data_mtEb"}
!CHECK: %[[VAR_B_DECL:.*]]:2 = hlfir.declare %[[VAR_B]](%{{.*}}) {uniq_name = "_QFomp_target_data_mtEb"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
!CHECK: %[[BOUNDS_A:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
- !CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAR_A_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAR_A_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_data map_entries(%[[MAP_A]] : !fir.ref<!fir.array<1024xi32>>) {
!$omp target data map(a)
!CHECK: omp.terminator
!$omp end target data
!CHECK: }
!CHECK: %[[BOUNDS_B:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
- !CHECK: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[VAR_B_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(always, from) capture(ByRef) bounds(%[[BOUNDS_B]]) -> !fir.ref<!fir.array<1024xi32>> {name = "b"}
+ !CHECK: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[VAR_B_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(always, from) capture(ByRef) bounds(%[[BOUNDS_B]]) -> !fir.ref<!fir.array<1024xi32>> {name = "b"}
!CHECK: omp.target_data map_entries(%[[MAP_B]] : !fir.ref<!fir.array<1024xi32>>) {
!$omp target data map(always, from : b)
!CHECK: omp.terminator
@@ -338,7 +338,7 @@ subroutine omp_target
!CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_targetEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
integer :: a(1024)
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
- !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[VAL_1]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[VAL_1]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target map_entries(%[[MAP]] -> %[[ARG_0:.*]] : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: ^bb0(%[[ARG_0]]: !fir.ref<!fir.array<1024xi32>>):
!$omp target map(tofrom: a)
@@ -372,7 +372,7 @@ subroutine omp_target_depend
!CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index
!CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index
!CHECK: %[[BOUNDS_A:.*]] = omp.map.bounds lower_bound(%[[LBOUND_A]] : index) upper_bound(%[[UBOUND_A]] : index) extent(%[[EXTENT_A]] : index) stride(%[[STRIDE_A]] : index) start_idx(%[[STRIDE_A]] : index)
- !CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref<!fir.array<1024xi32>>) {
!$omp target map(tofrom: a) depend(in: a)
a(1) = 10
@@ -455,12 +455,11 @@ subroutine omp_target_implicit_bounds(n)
!CHECK: %[[VAL_8:.*]] = fir.alloca !fir.array<?xi32>, %[[VAL_7]] {bindc_name = "a", uniq_name = "_QFomp_target_implicit_boundsEa"}
!CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_7]] : (index) -> !fir.shape<1>
!CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_9]]) {uniq_name = "_QFomp_target_implicit_boundsEa"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
- !CHECK: %[[DIMS0:.*]]:3 = fir.box_dims %{{[0-9]+}}#0, %c0{{.*}} : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
- !CHECK: %[[UB:.*]] = arith.subi %[[DIMS0]]#1, %c1{{.*}} : index
+ !CHECK: %[[UB:.*]] = arith.subi %[[VAL_7]], %c1{{.*}} : index
integer :: n
integer :: a(n)
- !CHECK: %[[VAL_14:.*]] = omp.map.bounds lower_bound(%c0{{.*}} : index) upper_bound(%[[UB]] : index) extent(%[[DIMS0]]#1 : index) stride(%[[DIMS0]]#2 : index) start_idx(%c1{{.*}} : index) {stride_in_bytes = true}
+ !CHECK: %[[VAL_14:.*]] = omp.map.bounds lower_bound(%c0{{.*}} : index) upper_bound(%[[UB]] : index) extent(%[[VAL_7]] : index) stride(%c1{{.*}} : index) start_idx(%c1{{.*}} : index)
!CHECK: %[[VAL_15:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref<!fir.array<?xi32>>, !fir.array<?xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds(%[[VAL_14]]) -> !fir.ref<!fir.array<?xi32>> {name = "a"}
!CHECK: %[[VAL_16:.*]] = omp.map.info var_ptr(%[[VAL_COPY]] : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = ""}
!CHECK: omp.target map_entries(%[[VAL_15]] -> %[[VAL_17:.*]], %[[VAL_16]] -> %[[VAL_18:.*]] : !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) {
@@ -587,7 +586,7 @@ subroutine omp_target_parallel_do
!CHECK: %[[C0:.*]] = arith.constant 0 : index
!CHECK: %[[SUB:.*]] = arith.subi %[[C1024]], %[[C1]] : index
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C0]] : index) upper_bound(%[[SUB]] : index) extent(%[[C1024]] : index) stride(%[[C1]] : index) start_idx(%[[C1]] : index)
- !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[VAL_0_DECL]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[VAL_0_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target map_entries(%[[MAP]] -> %[[ARG_0:.*]], %{{.*}} -> %{{.*}} : !fir.ref<!fir.array<1024xi32>>, !fir.ref<i32>) {
!CHECK: ^bb0(%[[ARG_0]]: !fir.ref<!fir.array<1024xi32>>, %{{.*}}: !fir.ref<i32>):
!CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %[[ARG_0]](%{{.*}}) {uniq_name = "_QFomp_target_parallel_doEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
>From 6a30edd54371c4c7244fde70abe7a50c9b72f238 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 5 Jul 2024 15:54:26 -0500
Subject: [PATCH 2/3] remove accidental extraneous newlines
---
flang/test/Lower/OpenMP/array-bounds.f90 | 2 --
1 file changed, 2 deletions(-)
diff --git a/flang/test/Lower/OpenMP/array-bounds.f90 b/flang/test/Lower/OpenMP/array-bounds.f90
index 55462daddfbc2..9e59d71f560fc 100644
--- a/flang/test/Lower/OpenMP/array-bounds.f90
+++ b/flang/test/Lower/OpenMP/array-bounds.f90
@@ -65,8 +65,6 @@ subroutine assumed_shape_array(arr_read_write)
end subroutine assumed_shape_array
-
-
!HOST-LABEL: func.func @_QMassumed_array_routinesPassumed_size_array(
!HOST-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "arr_read_write"}) {
!HOST: %[[ARG0_SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
>From 3e411d53a2fb81608dbfd58ea5d9127abfa411f1 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 2 Aug 2024 08:45:32 -0500
Subject: [PATCH 3/3] [Flang][OpenMP][Offload] Modify OMPMapInfoFinalization to
work on a Module and add runtime test
---
.../flang/Optimizer/Transforms/Passes.td | 2 +-
flang/include/flang/Tools/CLOptions.inc | 3 +-
.../Transforms/OMPMapInfoFinalization.cpp | 62 +++++++++------
.../fortran/local-descriptor-map-regress.f90 | 75 +++++++++++++++++++
4 files changed, 116 insertions(+), 26 deletions(-)
create mode 100644 offload/test/offloading/fortran/local-descriptor-map-regress.f90
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index e8a3e5c689a17..a5986131719b8 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -341,7 +341,7 @@ def LoopVersioning : Pass<"loop-versioning", "mlir::func::FuncOp"> {
}
def OMPMapInfoFinalizationPass
- : Pass<"omp-map-info-finalization", "mlir::func::FuncOp"> {
+ : Pass<"omp-map-info-finalization", "mlir::ModuleOp"> {
let summary = "expands OpenMP MapInfo operations containing descriptors";
let description = [{
Expands MapInfo operations containing descriptor types into multiple
diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc
index 7df5044949463..0f0cf7ad959ae 100644
--- a/flang/include/flang/Tools/CLOptions.inc
+++ b/flang/include/flang/Tools/CLOptions.inc
@@ -357,8 +357,7 @@ inline void createHLFIRToFIRPassPipeline(
/// rather than the host device.
inline void createOpenMPFIRPassPipeline(
mlir::PassManager &pm, bool isTargetDevice) {
- addNestedPassToAllTopLevelOperations(
- pm, fir::createOMPMapInfoFinalizationPass);
+ pm.addPass(fir::createOMPMapInfoFinalizationPass());
pm.addPass(fir::createOMPMarkDeclareTargetPass());
if (isTargetDevice)
pm.addPass(fir::createOMPFunctionFiltering());
diff --git a/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp b/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
index eeeb4de98e363..7b76cbd365d98 100644
--- a/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
+++ b/flang/lib/Optimizer/Transforms/OMPMapInfoFinalization.cpp
@@ -83,7 +83,7 @@ class OMPMapInfoFinalizationPass
// perform an alloca and then store to it and retrieve the data from the new
// alloca.
if (mlir::isa<fir::BaseBoxType>(descriptor.getType())) {
- // if we have already created a local allocation for this BoxType,
+ // If we have already created a local allocation for this BoxType,
// we must be sure to re-use it so that we end up with the same
// allocations being utilised for the same descriptor across all map uses,
// this prevents runtime issues such as not appropriately releasing or
@@ -248,32 +248,48 @@ class OMPMapInfoFinalizationPass
// operation (usually function) containing the MapInfoOp because this pass
// will mutate siblings of MapInfoOp.
void runOnOperation() override {
- mlir::func::FuncOp func = getOperation();
- mlir::ModuleOp module = func->getParentOfType<mlir::ModuleOp>();
+ mlir::ModuleOp module =
+ mlir::dyn_cast_or_null<mlir::ModuleOp>(getOperation());
+ if (!module)
+ module = getOperation()->getParentOfType<mlir::ModuleOp>();
fir::KindMapping kindMap = fir::getKindMapping(module);
fir::FirOpBuilder builder{module, std::move(kindMap)};
- func->walk([&](mlir::omp::MapInfoOp op) {
- // TODO: Currently only supports a single user for the MapInfoOp, this
- // is fine for the moment as the Fortran Frontend will generate a
- // new MapInfoOp per Target operation for the moment. However, when/if
- // we optimise/cleanup the IR, it likely isn't too difficult to
- // extend this function, it would require some modification to create a
- // single new MapInfoOp per new MapInfoOp generated and share it across
- // all users appropriately, making sure to only add a single member link
- // per new generation for the original originating descriptor MapInfoOp.
- assert(llvm::hasSingleElement(op->getUsers()) &&
- "OMPMapInfoFinalization currently only supports single users "
- "of a MapInfoOp");
+ // We wish to maintain some function level scope (currently
+ // just local function scope variables used to load and store box
+ // variables into so we can access their base address, an
+ // quirk of box_offset requires us to have an in memory box, but Fortran
+ // in certain cases does not provide this) whilst not subjecting
+ // ourselves to the possibility of race conditions while this pass
+ // undergoes frequent re-iteration for the near future. So we loop
+ // over function in the module and then map.info inside of those.
+ getOperation()->walk([&](mlir::func::FuncOp func) {
+ // clear all local allocations we made for any boxes in any prior
+ // iterations from previous function scopes.
+ localBoxAllocas.clear();
- if (!op.getMembers().empty()) {
- addImplicitMembersToTarget(op, builder, *op->getUsers().begin());
- } else if (fir::isTypeWithDescriptor(op.getVarType()) ||
- mlir::isa_and_present<fir::BoxAddrOp>(
- op.getVarPtr().getDefiningOp())) {
- builder.setInsertionPoint(op);
- genDescriptorMemberMaps(op, builder, *op->getUsers().begin());
- }
+ func->walk([&](mlir::omp::MapInfoOp op) {
+ // TODO: Currently only supports a single user for the MapInfoOp, this
+ // is fine for the moment as the Fortran Frontend will generate a
+ // new MapInfoOp per Target operation for the moment. However, when/if
+ // we optimise/cleanup the IR, it likely isn't too difficult to
+ // extend this function, it would require some modification to create a
+ // single new MapInfoOp per new MapInfoOp generated and share it across
+ // all users appropriately, making sure to only add a single member link
+ // per new generation for the original originating descriptor MapInfoOp.
+ assert(llvm::hasSingleElement(op->getUsers()) &&
+ "OMPMapInfoFinalization currently only supports single users "
+ "of a MapInfoOp");
+
+ if (!op.getMembers().empty()) {
+ addImplicitMembersToTarget(op, builder, *op->getUsers().begin());
+ } else if (fir::isTypeWithDescriptor(op.getVarType()) ||
+ mlir::isa_and_present<fir::BoxAddrOp>(
+ op.getVarPtr().getDefiningOp())) {
+ builder.setInsertionPoint(op);
+ genDescriptorMemberMaps(op, builder, *op->getUsers().begin());
+ }
+ });
});
}
};
diff --git a/offload/test/offloading/fortran/local-descriptor-map-regress.f90 b/offload/test/offloading/fortran/local-descriptor-map-regress.f90
new file mode 100644
index 0000000000000..5f628b8ad8c7a
--- /dev/null
+++ b/offload/test/offloading/fortran/local-descriptor-map-regress.f90
@@ -0,0 +1,75 @@
+! Small regression test that checks that we do not cause
+! a runtime map error in cases where we are required to
+! allocate a local variable for the fortran descriptor
+! to store into and then load from it, done so by
+! re-using the temporary local variable across all
+! maps related to the mapped variable and associated
+! local variable to make sure that each map does as
+! it's intended to do with the original data. This
+! prevents blobs of local descriptor data remaining
+! attatched on device long after it's supposed to,
+! which can cause weird map issues later in susbequent
+! function invocations. However, it doesn't avoid a user
+! shooting themselves in the foot by mapping data via enter
+! and then not providing a corresponding exit.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+subroutine launchOne(n1, n2, ret)
+ implicit none
+ real, intent(out) :: ret
+ real(4), dimension(n1,n2) :: sbuf31
+ integer :: n1,n2
+!$omp target enter data map(alloc:sbuf31)
+
+!$omp target
+ sbuf31(2, 2) = 10
+!$omp end target
+
+!$omp target update from(sbuf31)
+
+ ret = sbuf31(2, 2)
+
+!$omp target exit data map(delete:sbuf31)
+end subroutine launchOne
+
+subroutine launchTwo(N, ret)
+ implicit none
+ real, intent(inout) :: ret
+ integer :: N
+ real(4), dimension(N) :: p
+
+!$omp target enter data map(to:p)
+
+!$omp target
+ p(8) = 20
+!$omp end target
+
+!$omp target update from(p)
+
+ret = ret + p(8)
+
+! intentional non-deletion, can trigger an illegal map
+! issue in cases where the local map we store and load
+! from for the variable is different across all maps.
+! Not too sure why this is the thing that triggers the
+! problem in general. It seems like it would be an issue
+! made apparent with and without this statement commented,
+! especially as the issue occurs with the enter and not the
+! corresponding exit (from the runtime trace at least).
+!!$omp target exit data map(delete:p)
+end subroutine launchTwo
+
+program reproducer
+ implicit none
+ integer :: N = 10
+ integer :: nr = 10, nt = 10
+ real :: output = 0
+
+ call launchOne(nr, nt, output)
+ call launchTwo(N, output)
+
+ print *, output
+end program reproducer
+
+! CHECK: 30
More information about the flang-commits
mailing list