[flang-commits] [flang] [mlir] [openmp] [Flang][OpenMP] Initial mapping of Fortran pointers and allocatables for target devices (PR #71766)
via flang-commits
flang-commits at lists.llvm.org
Mon Nov 27 06:06:24 PST 2023
https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/71766
>From 370a271d638069378856d21e7df14d09da28242c Mon Sep 17 00:00:00 2001
From: Andrew Gozillon <Andrew.Gozillon at amd.com>
Date: Mon, 27 Nov 2023 08:02:44 -0600
Subject: [PATCH] [Flang][OpenMP] Initial mapping of Fortran pointers and
allocatables for target devices
This patch seeks to add an initial lowering for pointers and allocatable variables explicitly captured by implicit and explicit map in Flang OpenMP.
---
.../include/flang/Optimizer/CodeGen/CodeGen.h | 7 +
flang/lib/Lower/DirectivesCommon.h | 9 +-
flang/lib/Lower/OpenMP.cpp | 109 +++--
flang/lib/Optimizer/CodeGen/CMakeLists.txt | 1 +
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 5 +
flang/lib/Optimizer/CodeGen/CodeGenOpenMP.cpp | 134 +++++++
flang/lib/Optimizer/Dialect/FIRType.cpp | 3 +
.../OpenMP/map-types-and-sizes.f90 | 23 +-
flang/test/Lower/OpenMP/FIR/target.f90 | 2 +-
.../Lower/OpenMP/allocatable-array-bounds.f90 | 101 +++++
flang/test/Lower/OpenMP/allocatable-map.f90 | 16 +
flang/test/Lower/OpenMP/target.f90 | 2 +-
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 16 +-
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 263 +++++++++++-
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 2 +
mlir/test/Dialect/OpenMP/ops.mlir | 15 +
...target-fortran-allocatable-types-host.mlir | 374 ++++++++++++++++++
.../allocatable-array-section-1d-bounds.f90 | 46 +++
.../allocatable-array-section-3d-bounds.f90 | 44 +++
.../fortran/allocatable-map-scopes.f95 | 66 ++++
.../fortran/pointer-scopes-enter-exit-map.f90 | 83 ++++
...pointer-target-array-section-3d-bounds.f90 | 43 ++
.../fortran/pointer-target-map-scopes.f95 | 64 +++
.../target_enter_exit_allocatables.f90 | 44 +++
.../fortran/target_enter_exit_array.f90 | 41 ++
.../fortran/target_single_value_allocate.f90 | 26 ++
26 files changed, 1479 insertions(+), 60 deletions(-)
create mode 100644 flang/lib/Optimizer/CodeGen/CodeGenOpenMP.cpp
create mode 100644 flang/test/Lower/OpenMP/allocatable-array-bounds.f90
create mode 100644 flang/test/Lower/OpenMP/allocatable-map.f90
create mode 100644 mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
create mode 100644 openmp/libomptarget/test/offloading/fortran/allocatable-array-section-1d-bounds.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/allocatable-array-section-3d-bounds.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/allocatable-map-scopes.f95
create mode 100644 openmp/libomptarget/test/offloading/fortran/pointer-scopes-enter-exit-map.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/pointer-target-array-section-3d-bounds.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/pointer-target-map-scopes.f95
create mode 100644 openmp/libomptarget/test/offloading/fortran/target_enter_exit_allocatables.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/target_enter_exit_array.f90
create mode 100644 openmp/libomptarget/test/offloading/fortran/target_single_value_allocate.f90
diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h
index 7d8e548d89a18b5a..7391bbadbfcf2456 100644
--- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h
+++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h
@@ -19,6 +19,7 @@
namespace fir {
struct NameUniquer;
+class LLVMTypeConverter;
#define GEN_PASS_DECL_FIRTOLLVMLOWERING
#define GEN_PASS_DECL_CODEGENREWRITE
@@ -79,6 +80,12 @@ std::unique_ptr<mlir::Pass> createLLVMDialectToLLVMPass(
std::unique_ptr<mlir::Pass> createBoxedProcedurePass();
std::unique_ptr<mlir::Pass> createBoxedProcedurePass(bool useThunks);
+/// Specialised conversion patterns of OpenMP operations for FIR to LLVM
+/// dialect, utilised in cases where the default OpenMP dialect handling cannot
+/// handle all cases for intermingled fir types and operations.
+void populateOpenMPFIRToLLVMConversionPatterns(
+ LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns);
+
// declarative passes
#define GEN_PASS_REGISTRATION
#include "flang/Optimizer/CodeGen/CGPasses.h.inc"
diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h
index 58b8ea23450eb9d7..3bdb9ca557576b03 100644
--- a/flang/lib/Lower/DirectivesCommon.h
+++ b/flang/lib/Lower/DirectivesCommon.h
@@ -650,8 +650,9 @@ genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc,
builder.create<mlir::arith::SubIOp>(loc, dimInfo.getExtent(), one);
if (dim == 0) // First stride is the element size.
byteStride = dimInfo.getByteStride();
+
mlir::Value bound = builder.create<BoundsOp>(
- loc, boundTy, lb, ub, mlir::Value(), byteStride, true, baseLb);
+ loc, boundTy, lb, ub, dimInfo.getExtent(), byteStride, true, baseLb);
// Compute the stride for the next dimension.
byteStride = builder.create<mlir::arith::MulIOp>(loc, byteStride,
dimInfo.getExtent());
@@ -689,7 +690,6 @@ genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
// ub = extent - 1
ub = builder.create<mlir::arith::SubIOp>(loc, ext, one);
}
-
mlir::Value bound =
builder.create<BoundsOp>(loc, boundTy, lb, ub, ext, one, false, baseLb);
bounds.push_back(bound);
@@ -815,12 +815,15 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
}
}
}
+
+ extent = fir::factory::readExtent(builder, loc, dataExv, dimension);
+
if (!ubound) {
// ub = extent - 1
- extent = fir::factory::readExtent(builder, loc, dataExv, dimension);
ubound = builder.create<mlir::arith::SubIOp>(loc, extent, one);
}
}
+
mlir::Value bound = builder.create<BoundsOp>(
loc, boundTy, lbound, ubound, extent, stride, strideInBytes, baseLb);
bounds.push_back(bound);
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index a49589d8c59ff816..fe753ddbc4fa68e5 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -20,6 +20,7 @@
#include "flang/Lower/StatementContext.h"
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/MutableBox.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Parser/dump-parse-tree.h"
@@ -1710,27 +1711,22 @@ bool ClauseProcessor::processLink(
static mlir::omp::MapInfoOp
createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value baseAddr, std::stringstream &name,
- mlir::SmallVector<mlir::Value> bounds, uint64_t mapType,
+ mlir::Value baseAddr, mlir::Value varPtrPtr,
+ std::stringstream &name, mlir::SmallVector<mlir::Value> bounds,
+ mlir::SmallVector<mlir::Value> members, uint64_t mapType,
mlir::omp::VariableCaptureKind mapCaptureType,
mlir::Type retTy) {
- mlir::Value varPtr, varPtrPtr;
- mlir::TypeAttr varType;
-
- if (auto boxTy = baseAddr.getType().dyn_cast<fir::BaseBoxType>()) {
- baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr);
- retTy = baseAddr.getType();
- }
-
- varPtr = baseAddr;
- varType = mlir::TypeAttr::get(
- llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType());
+ mlir::TypeAttr varType = mlir::TypeAttr::get(
+ !fir::isAssumedShape(retTy)
+ ? llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType()
+ : retTy);
mlir::omp::MapInfoOp op = builder.create<mlir::omp::MapInfoOp>(
- loc, retTy, varPtr, varType, varPtrPtr, bounds,
+ loc, retTy, baseAddr, varType, varPtrPtr, members, bounds,
builder.getIntegerAttr(builder.getIntegerType(64, false), mapType),
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),
builder.getStringAttr(name.str()));
+
return op;
}
@@ -1791,6 +1787,8 @@ bool ClauseProcessor::processMap(
for (const Fortran::parser::OmpObject &ompObject :
std::get<Fortran::parser::OmpObjectList>(mapClause->v.t).v) {
+ auto origSymbol =
+ converter.getSymbolAddress(*getOmpObjectSymbol(ompObject));
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;
mlir::Value baseAddr = Fortran::lower::gatherDataOperandAddrAndBounds<
@@ -1798,24 +1796,41 @@ bool ClauseProcessor::processMap(
mlir::omp::DataBoundsOp>(
converter, firOpBuilder, semanticsContext, stmtCtx, ompObject,
clauseLocation, asFortran, bounds, treatIndexAsSection);
-
- // Explicit map captures are captured ByRef by default,
- // optimisation passes may alter this to ByCopy or other capture
- // types to optimise
- mlir::Value mapOp = createMapInfoOp(
- firOpBuilder, clauseLocation, baseAddr, asFortran, bounds,
- static_cast<
- std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
- mapTypeBits),
- mlir::omp::VariableCaptureKind::ByRef, baseAddr.getType());
-
- mapOperands.push_back(mapOp);
- if (mapSymTypes)
- mapSymTypes->push_back(baseAddr.getType());
- if (mapSymLocs)
- mapSymLocs->push_back(baseAddr.getLoc());
- if (mapSymbols)
- mapSymbols->push_back(getOmpObjectSymbol(ompObject));
+ if (fir::isPointerType(origSymbol.getType()) ||
+ fir::isAllocatableType(origSymbol.getType()) ||
+ fir::isAssumedShape(origSymbol.getType())) {
+ mapOperands.push_back(createMapInfoOp(
+ firOpBuilder, clauseLocation, origSymbol, mlir::Value{},
+ asFortran, bounds, {},
+ static_cast<std::underlying_type_t<
+ llvm::omp::OpenMPOffloadMappingFlags>>(mapTypeBits),
+ mlir::omp::VariableCaptureKind::ByRef, origSymbol.getType()));
+
+ if (mapSymTypes)
+ mapSymTypes->push_back(origSymbol.getType());
+ if (mapSymLocs)
+ mapSymLocs->push_back(origSymbol.getLoc());
+ if (mapSymbols)
+ mapSymbols->push_back(getOmpObjectSymbol(ompObject));
+ } else {
+ // Explicit map captures are captured ByRef by default,
+ // optimisation passes may alter this to ByCopy or other capture
+ // types to optimise
+ mlir::Value mapOp = createMapInfoOp(
+ firOpBuilder, clauseLocation, baseAddr, mlir::Value{},
+ asFortran, bounds, {},
+ static_cast<std::underlying_type_t<
+ llvm::omp::OpenMPOffloadMappingFlags>>(mapTypeBits),
+ mlir::omp::VariableCaptureKind::ByRef, baseAddr.getType());
+
+ mapOperands.push_back(mapOp);
+ if (mapSymTypes)
+ mapSymTypes->push_back(baseAddr.getType());
+ if (mapSymLocs)
+ mapSymLocs->push_back(baseAddr.getLoc());
+ if (mapSymbols)
+ mapSymbols->push_back(getOmpObjectSymbol(ompObject));
+ }
}
});
}
@@ -2527,6 +2542,7 @@ static void genBodyOfTargetOp(
for (const Fortran::semantics::Symbol *sym : mapSymbols) {
const mlir::BlockArgument &arg = region.getArgument(argIndex);
fir::ExtendedValue extVal = converter.getSymbolExtendedValue(*sym);
+
extVal.match(
[&](const fir::BoxValue &v) {
converter.bindSymbol(*sym,
@@ -2590,7 +2606,8 @@ static void genBodyOfTargetOp(
std::stringstream name;
firOpBuilder.setInsertionPoint(targetOp);
mlir::Value mapOp = createMapInfoOp(
- firOpBuilder, copyVal.getLoc(), copyVal, name, bounds,
+ firOpBuilder, copyVal.getLoc(), copyVal, mlir::Value{}, name,
+ bounds, llvm::SmallVector<mlir::Value>{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT),
@@ -2718,12 +2735,26 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
}
}
- mlir::Value mapOp = createMapInfoOp(
- converter.getFirOpBuilder(), baseOp.getLoc(), baseOp, name, bounds,
- static_cast<
- std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
- mapFlag),
- captureKind, baseOp.getType());
+ mlir::Value mapOp;
+ if (fir::isPointerType(baseOp.getType()) ||
+ fir::isAllocatableType(baseOp.getType()) ||
+ fir::isAssumedShape(baseOp.getType())) {
+ mapOp = createMapInfoOp(
+ converter.getFirOpBuilder(), baseOp.getLoc(), baseOp,
+ mlir::Value{}, name, bounds, {},
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ mapFlag),
+ captureKind, baseOp.getType());
+ } else {
+ mapOp = createMapInfoOp(
+ converter.getFirOpBuilder(), baseOp.getLoc(), baseOp,
+ mlir::Value{}, name, bounds, {},
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ mapFlag),
+ captureKind, baseOp.getType());
+ }
mapOperands.push_back(mapOp);
mapSymTypes.push_back(baseOp.getType());
diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index 0daa97b00dfa00c8..b304b8c950b7f85a 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -1,4 +1,5 @@
add_flang_library(FIRCodeGen
+ CodeGenOpenMP.cpp
BoxedProcedure.cpp
CGOps.cpp
CodeGen.cpp
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 9eabacdc818f6f4a..c1e4cbabe02e0036 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3836,6 +3836,11 @@ class FIRToLLVMLowering
mlir::populateMathToLibmConversionPatterns(pattern);
mlir::populateComplexToLLVMConversionPatterns(typeConverter, pattern);
mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
+
+ // Flang specific overloads for OpenMP operations, to allow for special
+ // handling of things like Box types.
+ fir::populateOpenMPFIRToLLVMConversionPatterns(typeConverter, pattern);
+
mlir::ConversionTarget target{*context};
target.addLegalDialect<mlir::LLVM::LLVMDialect>();
// The OpenMP dialect is legal for Operations without regions, for those
diff --git a/flang/lib/Optimizer/CodeGen/CodeGenOpenMP.cpp b/flang/lib/Optimizer/CodeGen/CodeGenOpenMP.cpp
new file mode 100644
index 0000000000000000..5d9e78d558053d85
--- /dev/null
+++ b/flang/lib/Optimizer/CodeGen/CodeGenOpenMP.cpp
@@ -0,0 +1,134 @@
+#include "flang/Optimizer/CodeGen/CodeGen.h"
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/LowLevelIntrinsics.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Support/FatalError.h"
+#include "flang/Optimizer/Support/InternalNames.h"
+#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
+#include "mlir/Conversion/LLVMCommon/Pattern.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+using namespace fir;
+
+#define DEBUG_TYPE "flang-codegen-openmp"
+
+// fir::LLVMTypeConverter for converting to LLVM IR dialect types.
+#include "flang/Optimizer/CodeGen/TypeConverter.h"
+
+namespace {
+/// A pattern that converts the region arguments in a single-region OpenMP
+/// operation to the LLVM dialect. The body of the region is not modified and is
+/// expected to either be processed by the conversion infrastructure or already
+/// contain ops compatible with LLVM dialect types.
+template <typename OpType>
+class OpenMPFIROpConversion : public mlir::ConvertOpToLLVMPattern<OpType> {
+public:
+ explicit OpenMPFIROpConversion(const fir::LLVMTypeConverter &lowering)
+ : mlir::ConvertOpToLLVMPattern<OpType>(lowering) {}
+
+ const fir::LLVMTypeConverter &lowerTy() const {
+ return *static_cast<const fir::LLVMTypeConverter *>(
+ this->getTypeConverter());
+ }
+};
+
+// FIR Op specific conversion for MapInfoOp that overwrites the default OpenMP
+// Dialect lowering, this allows FIR specific lowering of types, required for
+// descriptors of allocatables currently.
+struct MapInfoOpConversion
+ : public OpenMPFIROpConversion<mlir::omp::MapInfoOp> {
+ using OpenMPFIROpConversion::OpenMPFIROpConversion;
+
+ mlir::omp::MapInfoOp generateImplicitDescriptorMaps(
+ mlir::omp::MapInfoOp curOp, mlir::Value firBox, mlir::Value llvmBox,
+ mlir::ValueRange boundsOps, mlir::Type firBoxTys,
+ mlir::TypeAttr llvmBoxTy,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto ptTy =
+ mlir::LLVM::LLVMPointerType::get(llvmBoxTy.getValue().getContext());
+ auto baseAddr = rewriter.create<mlir::LLVM::GEPOp>(
+ firBox.getLoc(), ptTy, llvmBoxTy.getValue(), llvmBox,
+ llvm::ArrayRef<mlir::LLVM::GEPArg>{0, kAddrPosInBox});
+
+ // We require the underlying type of the base addr/pointer inside of the
+ // descriptor for later lowering (a bit of an issue as we've deprecated
+ // typed pointers in LLVM/MLIR)
+ mlir::Type eleTy;
+ if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(firBoxTys)) {
+ eleTy = boxTy.getEleTy();
+ if (auto ptrTy = mlir::dyn_cast<fir::PointerType>(eleTy))
+ eleTy = ptrTy.getEleTy();
+ if (auto heapTy = mlir::dyn_cast<fir::HeapType>(eleTy))
+ eleTy = heapTy.getEleTy();
+ eleTy = getTypeConverter()->convertType(eleTy);
+ }
+
+ auto descriptorBaseAddr = rewriter.create<mlir::omp::MapInfoOp>(
+ curOp->getLoc(), baseAddr.getType(), baseAddr,
+ mlir::TypeAttr::get(eleTy), mlir::Value{},
+ mlir::SmallVector<mlir::Value>{}, curOp.getBounds(),
+ curOp.getMapTypeAttr(), curOp.getMapCaptureTypeAttr(),
+ curOp.getNameAttr());
+
+ return rewriter.create<mlir::omp::MapInfoOp>(
+ curOp->getLoc(), curOp.getVarPtr().getType(), curOp.getVarPtr(),
+ llvmBoxTy, mlir::Value{},
+ mlir::SmallVector<mlir::Value>{descriptorBaseAddr},
+ mlir::SmallVector<mlir::Value>{}, curOp.getMapTypeAttr(),
+ curOp.getMapCaptureTypeAttr(), curOp.getNameAttr());
+ }
+
+ mlir::LogicalResult
+ matchAndRewrite(mlir::omp::MapInfoOp curOp, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ const mlir::TypeConverter *converter = getTypeConverter();
+ llvm::SmallVector<mlir::Type> resTypes;
+ if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes)))
+ return mlir::failure();
+
+ llvm::SmallVector<mlir::NamedAttribute> newAttrs;
+ mlir::omp::MapInfoOp newOp;
+ for (mlir::NamedAttribute attr : curOp->getAttrs()) {
+ if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr.getValue())) {
+ mlir::Type newAttr;
+ if (fir::isPointerType(typeAttr.getValue()) ||
+ fir::isAllocatableType(typeAttr.getValue()) ||
+ fir::isAssumedShape(typeAttr.getValue())) {
+ newAttr = lowerTy().convertBoxTypeAsStruct(
+ mlir::cast<fir::BaseBoxType>(typeAttr.getValue()));
+ mlir::TypeAttr boxAttr = mlir::TypeAttr::get(newAttr);
+ newOp = generateImplicitDescriptorMaps(
+ curOp, curOp.getVarPtr(), adaptor.getVarPtr(),
+ adaptor.getBounds(), typeAttr.getValue(), boxAttr, rewriter);
+ } else {
+ newAttr = converter->convertType(typeAttr.getValue());
+ }
+ newAttrs.emplace_back(attr.getName(), mlir::TypeAttr::get(newAttr));
+ } else {
+ newAttrs.push_back(attr);
+ }
+ }
+
+ if (newOp)
+ rewriter.replaceOp(curOp, newOp);
+ else
+ rewriter.replaceOpWithNewOp<mlir::omp::MapInfoOp>(
+ curOp, resTypes, adaptor.getOperands(), newAttrs);
+
+ return mlir::success();
+ }
+};
+} // namespace
+
+void fir::populateOpenMPFIRToLLVMConversionPatterns(
+ LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns) {
+
+ patterns.add<MapInfoOpConversion>(converter);
+}
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 730317a9bc238b5f..c0446964740c39a6 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -1266,4 +1266,7 @@ void FIROpsDialect::registerTypes() {
OpenMPPointerLikeModel<fir::LLVMPointerType>>(*getContext());
fir::LLVMPointerType::attachInterface<
OpenACCPointerLikeModel<fir::LLVMPointerType>>(*getContext());
+
+ fir::BoxType::attachInterface<OpenMPPointerLikeModel<fir::BoxType>>(
+ *getContext());
}
diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
index f0a0e5e765b41515..adce7bb3497cc146 100644
--- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90
+++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
@@ -30,7 +30,6 @@ subroutine mapType_array
!$omp end target
end subroutine mapType_array
-!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 8]
!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 547]
subroutine mapType_ptr
integer, pointer :: a
@@ -39,6 +38,16 @@ subroutine mapType_ptr
!$omp end target
end subroutine mapType_ptr
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 547]
+subroutine mapType_allocatable
+ integer, allocatable :: a
+ allocate(a)
+ !$omp target
+ a = 10
+ !$omp end target
+ deallocate(a)
+end subroutine mapType_allocatable
+
!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [2 x i64] [i64 8, i64 4]
!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 544, i64 800]
subroutine mapType_c_ptr
@@ -58,3 +67,15 @@ subroutine mapType_char
a = 'b'
!$omp end target
end subroutine mapType_char
+
+!CHECK-LABEL: define void @maptype_ptr_() {
+!CHECK: %[[DESC_ELE_SIZE:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %{{.*}}, i64 0, i32 1
+!CHECK: %[[DESC_ELE_SIZE_LOAD:.*]] = load i64, ptr %[[DESC_ELE_SIZE]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DESC_ELE_SIZE_LOAD]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+
+!CHECK-LABEL: define void @maptype_allocatable_() {
+!CHECK: %[[DESC_ELE_SIZE:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %{{.*}}, i64 0, i32 1
+!CHECK: %[[DESC_ELE_SIZE_LOAD:.*]] = load i64, ptr %[[DESC_ELE_SIZE]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR_1:.*]] = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DESC_ELE_SIZE_LOAD]], ptr %[[OFFLOAD_SIZE_ARR_1]], align 8
\ No newline at end of file
diff --git a/flang/test/Lower/OpenMP/FIR/target.f90 b/flang/test/Lower/OpenMP/FIR/target.f90
index 2034ac84334e5468..818b6c41a04944c8 100644
--- a/flang/test/Lower/OpenMP/FIR/target.f90
+++ b/flang/test/Lower/OpenMP/FIR/target.f90
@@ -356,7 +356,7 @@ end subroutine omp_target_device_ptr
subroutine omp_target_device_addr
integer, pointer :: a
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFomp_target_device_addrEa"}
- !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> {{.*}} {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> {{.*}} {is_fortran_allocatable, name = "a"}
!CHECK: omp.target_data map_entries(%[[MAP]] : {{.*}}) use_device_addr(%[[VAL_0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>) {
!$omp target data map(tofrom: a) use_device_addr(a)
!CHECK: ^bb0(%[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>):
diff --git a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90
new file mode 100644
index 0000000000000000..7cc3bf7d211da061
--- /dev/null
+++ b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90
@@ -0,0 +1,101 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefixes HOST
+
+!HOST-LABEL: func.func @_QPread_write_section() {
+
+!HOST: %[[ALLOCA_1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "sp_read", uniq_name = "_QFread_write_sectionEsp_read"}
+!HOST: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[ALLOCA_1]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFread_write_sectionEsp_read"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+
+!HOST: %[[ALLOCA_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "sp_write", uniq_name = "_QFread_write_sectionEsp_write"}
+!HOST: %[[DECLARE_2:.*]]:2 = hlfir.declare %[[ALLOCA_2]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFread_write_sectionEsp_write"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+
+!HOST: %[[LOAD_1:.*]] = fir.load %[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[LOAD_2:.*]] = fir.load %[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[CONSTANT_1:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_1:.*]]:3 = fir.box_dims %[[LOAD_2]], %[[CONSTANT_1]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_2:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_2:.*]]:3 = fir.box_dims %[[LOAD_1]], %[[CONSTANT_2]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_3:.*]] = arith.constant 2 : index
+!HOST: %[[LB_1:.*]] = arith.subi %[[CONSTANT_3]], %[[BOX_1]]#0 : index
+!HOST: %[[CONSTANT_4:.*]] = arith.constant 5 : index
+!HOST: %[[UB_1:.*]] = arith.subi %[[CONSTANT_4]], %[[BOX_1]]#0 : index
+!HOST: %[[BOUNDS_1:.*]] = omp.bounds lower_bound(%[[LB_1]] : index) upper_bound(%[[UB_1]] : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true}
+!HOST: %[[MAP_INFO_1:.*]] = omp.map_info var_ptr(%[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_1]]) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {is_fortran_allocatable, name = "sp_read(2:5)"}
+
+!HOST: %[[LOAD_3:.*]] = fir.load %[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[LOAD_4:.*]] = fir.load %[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[CONSTANT_5:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_3:.*]]:3 = fir.box_dims %[[LOAD_4]], %[[CONSTANT_5]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_6:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_4:.*]]:3 = fir.box_dims %[[LOAD_3]], %[[CONSTANT_6]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_7:.*]] = arith.constant 2 : index
+!HOST: %[[LB_2:.*]] = arith.subi %[[CONSTANT_7]], %[[BOX_3]]#0 : index
+!HOST: %[[CONSTANT_8:.*]] = arith.constant 5 : index
+!HOST: %[[UB_2:.*]] = arith.subi %[[CONSTANT_8]], %[[BOX_3]]#0 : index
+!HOST: %[[BOUNDS_2:.*]] = omp.bounds lower_bound(%[[LB_2]] : index) upper_bound(%[[UB_2]] : index) stride(%[[BOX_4]]#2 : index) start_idx(%[[BOX_3]]#0 : index) {stride_in_bytes = true}
+!HOST: %[[MAP_INFO_2:.*]] = omp.map_info var_ptr(%11#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_2]]) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {is_fortran_allocatable, name = "sp_write(2:5)"}
+subroutine read_write_section()
+ integer, allocatable :: sp_read(:)
+ integer, allocatable :: sp_write(:)
+ allocate(sp_read(10))
+ allocate(sp_write(10))
+ sp_write = (/0,0,0,0,0,0,0,0,0,0/)
+ sp_read = (/1,2,3,4,5,6,7,8,9,10/)
+
+!$omp target map(tofrom:sp_read(2:5)) map(tofrom:sp_write(2:5))
+ do i = 2, 5
+ sp_write(i) = sp_read(i)
+ end do
+!$omp end target
+end subroutine read_write_section
+
+module assumed_allocatable_array_routines
+ contains
+
+!HOST-LABEL: func.func @_QMassumed_allocatable_array_routinesPassumed_shape_array(
+
+!HOST: %[[DECLARE:.*]]:2 = hlfir.declare %[[ARG:.*]] {fortran_attrs = #fir.var_attrs<allocatable, intent_inout>, uniq_name = "_QMassumed_allocatable_array_routinesFassumed_shape_arrayEarr_read_write"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+!HOST: %[[LOAD_1:.*]] = fir.load %[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[LOAD_2:.*]] = fir.load %[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[CONSTANT_1:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_1:.*]]:3 = fir.box_dims %[[LOAD_2]], %[[CONSTANT_1]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_2:.*]] = arith.constant 0 : index
+!HOST: %[[BOX_2:.*]]:3 = fir.box_dims %[[LOAD_1]], %[[CONSTANT_2]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!HOST: %[[CONSTANT_3:.*]] = arith.constant 2 : index
+!HOST: %[[LB:.*]] = arith.subi %[[CONSTANT_3]], %[[BOX_1]]#0 : index
+!HOST: %[[CONSTANT_4:.*]] = arith.constant 5 : index
+!HOST: %[[UB:.*]] = arith.subi %[[CONSTANT_4]], %[[BOX_1]]#0 : index
+!HOST: %[[BOUNDS:.*]] = omp.bounds lower_bound(%[[LB]] : index) upper_bound(%[[UB]] : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true}
+!HOST: %[[MAP_INFO:.*]] = omp.map_info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {is_fortran_allocatable, name = "arr_read_write(2:5)"}
+subroutine assumed_shape_array(arr_read_write)
+ integer, allocatable, intent(inout) :: arr_read_write(:)
+
+!$omp target map(tofrom:arr_read_write(2:5))
+ do i = 2, 5
+ arr_read_write(i) = i
+ end do
+!$omp end target
+end subroutine assumed_shape_array
+end module assumed_allocatable_array_routines
+
+!HOST-LABEL: func.func @_QPcall_assumed_shape_and_size_array() {
+!HOST: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "arr_read_write", uniq_name = "_QFcall_assumed_shape_and_size_arrayEarr_read_write"}
+!HOST: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFcall_assumed_shape_and_size_arrayEarr_read_write"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+!HOST: %[[ALLOCA_MEM:.*]] = fir.allocmem !fir.array<?xi32>, %{{.*}} {fir.must_be_heap = true, uniq_name = "_QFcall_assumed_shape_and_size_arrayEarr_read_write.alloc"}
+!HOST: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
+!HOST: %[[EMBOX:.*]] = fir.embox %[[ALLOCA_MEM]](%[[SHAPE]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+!HOST: fir.store %[[EMBOX]] to %[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!HOST: %[[CONSTANT_1:.*]] = arith.constant 10 : index
+!HOST: %[[CONSTANT_2:.*]] = arith.constant 20 : index
+!HOST: %[[CONSTANT_3:.*]] = arith.constant 1 : index
+!HOST: %[[CONSTANT_4:.*]] = arith.constant 11 : index
+!HOST: %[[SHAPE:.*]] = fir.shape %[[CONSTANT_4]] : (index) -> !fir.shape<1>
+!HOST: %[[DESIGNATE:.*]] = hlfir.designate %[[LOAD]] (%[[CONSTANT_1]]:%[[CONSTANT_2]]:%[[CONSTANT_3]]) shape %[[SHAPE]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<11xi32>>
+!HOST: fir.call @_QPassumed_size_array(%[[DESIGNATE]]) fastmath<contract> : (!fir.ref<!fir.array<11xi32>>) -> ()
+subroutine call_assumed_shape_and_size_array
+ use assumed_allocatable_array_routines
+ integer, allocatable :: arr_read_write(:)
+ allocate(arr_read_write(20))
+ call assumed_size_array(arr_read_write(10:20))
+ deallocate(arr_read_write)
+end subroutine call_assumed_shape_and_size_array
diff --git a/flang/test/Lower/OpenMP/allocatable-map.f90 b/flang/test/Lower/OpenMP/allocatable-map.f90
new file mode 100644
index 0000000000000000..4c7f45dfe2f2f566
--- /dev/null
+++ b/flang/test/Lower/OpenMP/allocatable-map.f90
@@ -0,0 +1,16 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefixes="HLFIRDIALECT"
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | FileCheck %s --check-prefixes="LLVMOMPDIALECT"
+
+!LLVMOMPDIALECT: %[[ALLOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "point"} : (i64) -> !llvm.ptr
+!LLVMOMPDIALECT: %[[MAP:.*]] = omp.map_info var_ptr(%[[ALLOCA]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(implicit, tofrom) capture(ByRef) -> !llvm.ptr {is_fortran_allocatable, name = "point"}
+!LLVMOMPDIALECT: omp.target map_entries({{.*}}, %[[MAP]] -> {{.*}} : {{.*}}, !llvm.ptr) {
+
+!HLFIRDIALECT: %[[POINTER:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFpointer_routineEpoint"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
+!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map_info var_ptr(%[[POINTER]]#1 : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {is_fortran_allocatable, name = "point"}
+!HLFIRDIALECT: omp.target map_entries({{.*}}, %[[POINTER_MAP]] -> {{.*}} : {{.*}}, !fir.ref<!fir.box<!fir.ptr<i32>>>) {
+subroutine pointer_routine()
+ integer, pointer :: point
+!$omp target map(tofrom:pointer)
+ point = 1
+!$omp end target
+end subroutine pointer_routine
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 26b4d595d52291b6..0188ad2e45e6e5cc 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -357,7 +357,7 @@ subroutine omp_target_device_addr
integer, pointer :: a
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFomp_target_device_addrEa"}
!CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
- !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> {{.*}} {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> {{.*}} {is_fortran_allocatable, name = "a"}
!CHECK: omp.target_data map_entries(%[[MAP]] : {{.*}}) use_device_addr(%[[VAL_0_DECL]]#1 : !fir.ref<!fir.box<!fir.ptr<i32>>>) {
!$omp target data map(tofrom: a) use_device_addr(a)
!CHECK: ^bb0(%[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>):
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 8ff5380f71ad453c..3bca0f565082fa8c 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -1148,6 +1148,7 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> {
let arguments = (ins OpenMP_PointerLikeType:$var_ptr,
TypeAttr:$var_type,
Optional<OpenMP_PointerLikeType>:$var_ptr_ptr,
+ Variadic<OpenMP_PointerLikeType>:$members,
Variadic<DataBoundsType>:$bounds, /* rank-0 to rank-{n-1} */
OptionalAttr<UI64Attr>:$map_type,
OptionalAttr<VariableCaptureKindAttr>:$map_capture_type,
@@ -1187,13 +1188,17 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> {
- `var_type`: The type of the variable to copy.
- `var_ptr_ptr`: Used when the variable copied is a member of a class, structure
or derived type and refers to the originating struct.
+ - `members`: Used to indicate mapped child members for the current MapInfoOp,
+ represented as other MapInfoOp's, utilised in cases where a parent structure
+ type and members of the structure type are being mapped at the same time.
+ For example: map(to: parent, parent->member, parent->member2[:10])
- `bounds`: Used when copying slices of array's, pointers or pointer members of
- objects (e.g. derived types or classes), indicates the bounds to be copied
- of the variable. When it's an array slice it is in rank order where rank 0
- is the inner-most dimension.
+ objects (e.g. derived types or classes), indicates the bounds to be copied
+ of the variable. When it's an array slice it is in rank order where rank 0
+ is the inner-most dimension.
- 'map_clauses': OpenMP map type for this map capture, for example: from, to and
- always. It's a bitfield composed of the OpenMP runtime flags stored in
- OpenMPOffloadMappingFlags.
+ always. It's a bitfield composed of the OpenMP runtime flags stored in
+ OpenMPOffloadMappingFlags.
- 'map_capture_type': Capture type for the variable e.g. this, byref, byvalue, byvla
this can affect how the variable is lowered.
- `name`: Holds the name of variable as specified in user clause (including bounds).
@@ -1205,6 +1210,7 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> {
`var_ptr_ptr` `(` $var_ptr_ptr `:` type($var_ptr_ptr) `)`
| `map_clauses` `(` custom<MapClause>($map_type) `)`
| `capture` `(` custom<CaptureType>($map_capture_type) `)`
+ | `members` `(` $members `:` type($members) `)`
| `bounds` `(` $bounds `)`
) `->` type($omp_ptr) attr-dict
}];
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 48a78eddfbf97d3c..0c98d9b818071773 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -33,6 +33,7 @@
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <any>
+#include <cstdint>
#include <optional>
#include <utility>
@@ -1676,14 +1677,14 @@ uint64_t getArrayElementSizeInBits(LLVM::LLVMArrayType arrTy, DataLayout &dl) {
// This function is somewhat equivalent to Clang's getExprTypeSize inside of
// CGOpenMPRuntime.cpp.
llvm::Value *getSizeInBytes(DataLayout &dl, const mlir::Type &type,
- Operation *clauseOp, llvm::IRBuilderBase &builder,
+ Operation *clauseOp, llvm::Value *basePointer,
+ llvm::Type *baseType, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
// utilising getTypeSizeInBits instead of getTypeSize as getTypeSize gives
// the size in inconsistent byte or bit format.
uint64_t underlyingTypeSzInBits = dl.getTypeSizeInBits(type);
- if (auto arrTy = llvm::dyn_cast_if_present<LLVM::LLVMArrayType>(type)) {
+ if (auto arrTy = llvm::dyn_cast_if_present<LLVM::LLVMArrayType>(type))
underlyingTypeSzInBits = getArrayElementSizeInBits(arrTy, dl);
- }
if (auto memberClause =
mlir::dyn_cast_if_present<mlir::omp::MapInfoOp>(clauseOp)) {
@@ -1747,10 +1748,11 @@ void collectMapDataFromMapOperands(MapInfoData &mapData,
mapData.BasePointers.push_back(mapData.OriginalValue.back());
}
- mapData.Sizes.push_back(getSizeInBytes(dl, mapOp.getVarType(), mapOp,
- builder, moduleTranslation));
mapData.BaseType.push_back(
moduleTranslation.convertType(mapOp.getVarType()));
+ mapData.Sizes.push_back(getSizeInBytes(
+ dl, mapOp.getVarType(), mapOp, mapData.BasePointers.back(),
+ mapData.BaseType.back(), builder, moduleTranslation));
mapData.MapClause.push_back(mapOp.getOperation());
mapData.Types.push_back(
llvm::omp::OpenMPOffloadMappingFlags(mapOp.getMapType().value()));
@@ -1762,6 +1764,150 @@ void collectMapDataFromMapOperands(MapInfoData &mapData,
}
}
+static void processMapWithMembersOf(
+ LLVM::ModuleTranslation &moduleTranslation, llvm::IRBuilderBase &builder,
+ llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl,
+ llvm::OpenMPIRBuilder::MapInfosTy &combinedInfo, MapInfoData &mapData,
+ uint64_t mapDataIndex, bool isTargetParams) {
+ auto parentClause =
+ mlir::dyn_cast<mlir::omp::MapInfoOp>(mapData.MapClause[mapDataIndex]);
+
+ ////////// First Parent Map Segment //////////
+ // Map the first segment of our structure
+ combinedInfo.Types.emplace_back(
+ isTargetParams
+ ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM
+ : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE);
+ combinedInfo.DevicePointers.emplace_back(
+ llvm::OpenMPIRBuilder::DeviceInfoTy::None);
+ combinedInfo.Names.emplace_back(LLVM::createMappingInformation(
+ mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder));
+ combinedInfo.BasePointers.emplace_back(mapData.BasePointers[mapDataIndex]);
+ combinedInfo.Pointers.emplace_back(mapData.Pointers[mapDataIndex]);
+
+ // Calculate size of the parent object being mapped based on the
+ // addresses at runtime, highAddr - lowAddr = size. This of course
+ // doesn't factor in allocated data like pointers, hence the further
+ // processing of members specified by users, or in the case of
+ // Fortran pointers and allocatables, the mapping of the pointed to
+ // data by the descriptor (which itself, is a structure containing
+ // runtime information on the dynamically allocated data).
+ llvm::Value *lowAddr = builder.CreatePointerCast(
+ mapData.Pointers[mapDataIndex], builder.getPtrTy());
+ llvm::Value *highAddr = builder.CreatePointerCast(
+ builder.CreateConstGEP1_32(mapData.BaseType[mapDataIndex],
+ mapData.Pointers[mapDataIndex], 1),
+ builder.getPtrTy());
+ llvm::Value *size = builder.CreateIntCast(
+ builder.CreatePtrDiff(builder.getInt8Ty(), highAddr, lowAddr),
+ builder.getInt64Ty(),
+ /*isSigned=*/false);
+ combinedInfo.Sizes.push_back(size);
+
+ ////////// Second Parent Map Segment //////////
+ // This creates the initial MEMBER_OF mapping that consists of
+ // the parent/top level container (same as above effectively, except
+ // with a fixed initial compile time size and seperate maptype which
+ // indicates the true mape type (tofrom etc.) and that it is a part
+ // of a larger mapping and indicating the link between it and it's
+ // members that are also explicitly mapped).
+ llvm::omp::OpenMPOffloadMappingFlags mapFlag =
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
+ if (isTargetParams)
+ mapFlag &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
+
+ llvm::omp::OpenMPOffloadMappingFlags memberOfFlag =
+ ompBuilder.getMemberOfFlag(combinedInfo.BasePointers.size() - 1);
+ ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag);
+
+ combinedInfo.Types.emplace_back(mapFlag);
+ combinedInfo.DevicePointers.emplace_back(
+ llvm::OpenMPIRBuilder::DeviceInfoTy::None);
+ combinedInfo.Names.emplace_back(LLVM::createMappingInformation(
+ mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder));
+ combinedInfo.BasePointers.emplace_back(mapData.BasePointers[mapDataIndex]);
+ combinedInfo.Pointers.emplace_back(mapData.Pointers[mapDataIndex]);
+ combinedInfo.Sizes.emplace_back(mapData.Sizes[mapDataIndex]);
+
+ ////////// Mapping of Members Segment //////////
+ for (auto mappedMembers : parentClause.getMembers()) {
+ auto memberClause =
+ mlir::dyn_cast<mlir::omp::MapInfoOp>(mappedMembers.getDefiningOp());
+ int memberDataIdx = -1;
+ for (size_t i = 0; i < mapData.MapClause.size(); ++i) {
+ if (mapData.MapClause[i] == memberClause)
+ memberDataIdx = i;
+ }
+
+ assert(memberDataIdx >= 0 && "could not find mapped member of structure");
+
+ // Same MemberOfFlag to indicate its link with parent and other members
+ // of, and we flag that it's part of a pointer and object coupling.
+ auto mapFlag =
+ llvm::omp::OpenMPOffloadMappingFlags(memberClause.getMapType().value());
+ mapFlag &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
+ ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag);
+ mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
+ combinedInfo.Types.emplace_back(mapFlag);
+ combinedInfo.DevicePointers.emplace_back(
+ llvm::OpenMPIRBuilder::DeviceInfoTy::None);
+ combinedInfo.Names.emplace_back(
+ LLVM::createMappingInformation(memberClause.getLoc(), ompBuilder));
+
+ combinedInfo.BasePointers.emplace_back(mapData.BasePointers[memberDataIdx]);
+
+ std::vector<llvm::Value *> idx{builder.getInt64(0)};
+ llvm::Value *offsetAddress = nullptr;
+ if (!memberClause.getBounds().empty()) {
+ if (mapData.BaseType[memberDataIdx]->isArrayTy()) {
+ for (int i = memberClause.getBounds().size() - 1; i >= 0; --i) {
+ if (auto boundOp = mlir::dyn_cast_if_present<mlir::omp::DataBoundsOp>(
+ memberClause.getBounds()[i].getDefiningOp())) {
+ idx.push_back(
+ moduleTranslation.lookupValue(boundOp.getLowerBound()));
+ }
+ }
+ } else {
+ std::vector<llvm::Value *> dimensionIndexSizeOffset{
+ builder.getInt64(1)};
+ for (size_t i = 1; i < memberClause.getBounds().size(); ++i) {
+ if (auto boundOp = mlir::dyn_cast_if_present<mlir::omp::DataBoundsOp>(
+ memberClause.getBounds()[i].getDefiningOp())) {
+ dimensionIndexSizeOffset.push_back(builder.CreateMul(
+ moduleTranslation.lookupValue(boundOp.getExtent()),
+ dimensionIndexSizeOffset[i - 1]));
+ }
+ }
+
+ for (int i = memberClause.getBounds().size() - 1; i >= 0; --i) {
+ if (auto boundOp = mlir::dyn_cast_if_present<mlir::omp::DataBoundsOp>(
+ memberClause.getBounds()[i].getDefiningOp())) {
+ if (!offsetAddress)
+ offsetAddress = builder.CreateMul(
+ moduleTranslation.lookupValue(boundOp.getLowerBound()),
+ dimensionIndexSizeOffset[i]);
+ else
+ offsetAddress = builder.CreateAdd(
+ offsetAddress,
+ builder.CreateMul(
+ moduleTranslation.lookupValue(boundOp.getLowerBound()),
+ dimensionIndexSizeOffset[i]));
+ }
+ }
+ }
+ }
+
+ llvm::Value *memberIdx =
+ builder.CreateLoad(builder.getPtrTy(), mapData.Pointers[memberDataIdx]);
+ memberIdx = builder.CreateInBoundsGEP(
+ mapData.BaseType[memberDataIdx], memberIdx,
+ offsetAddress ? std::vector<llvm::Value *>{offsetAddress} : idx,
+ "member_idx");
+ combinedInfo.Pointers.emplace_back(memberIdx);
+ combinedInfo.Sizes.emplace_back(mapData.Sizes[memberDataIdx]);
+ }
+}
+
// Generate all map related information and fill the combinedInfo.
static void genMapInfos(llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation,
@@ -1782,15 +1928,56 @@ static void genMapInfos(llvm::IRBuilderBase &builder,
combinedInfo.Names.clear();
};
+ llvm::SmallVector<size_t, 4> primaryMapIdx;
+ for (size_t i = 0; i < mapData.MapClause.size(); ++i) {
+ primaryMapIdx.push_back(i);
+ }
+
+ // TODO: Handle nested MembersOf, currently only cares about the first level
+ // of nesting (all that was relevant for Fortran descriptors), but a slight
+ // refactoring of mapInfoData to hold nestings or membersOf may be a better
+ // approach to simplify things.
+ for (size_t i = 0; i < mapData.MapClause.size(); ++i) {
+ auto mapInfoOp = mlir::dyn_cast<mlir::omp::MapInfoOp>(mapData.MapClause[i]);
+ for (auto member : mapInfoOp.getMembers()) {
+ for (size_t j = 0; j < primaryMapIdx.size(); j++) {
+ if (member.getDefiningOp() == mapData.MapClause[primaryMapIdx[j]]) {
+ primaryMapIdx.erase(&primaryMapIdx[j]);
+ j--;
+ }
+ }
+ }
+ }
+
// We operate under the assumption that all vectors that are
// required in MapInfoData are of equal lengths (either filled with
// default constructed data or appropiate information) so we can
// utilise the size from any component of MapInfoData, if we can't
// something is missing from the initial MapInfoData construction.
- for (size_t i = 0; i < mapData.MapClause.size(); ++i) {
+ for (unsigned long i : primaryMapIdx) {
+ auto mapInfoOp = mlir::dyn_cast<mlir::omp::MapInfoOp>(mapData.MapClause[i]);
+
+ bool isImplicit =
+ mapInfoOp.getMapType().value() &
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
+
+ // TODO: Look into more thoroughly handling implicit semantics, this
+ // mimics what Clang currently does with structures, which is map the
+ // structure and not the internals i.e. the descriptor without the pointer
+ // itself, so not a deep copy, which may be incorrect for
+ // allocatables/pointers, but allows explicit mapping and initial
+ // enter/exit handling
+ if (!isImplicit && !mapInfoOp.getMembers().empty()) {
+ processMapWithMembersOf(moduleTranslation, builder, *ompBuilder, dl,
+ combinedInfo, mapData, i, isTargetParams);
+ continue;
+ }
+
// Declare Target Mappings are excluded from being marked as
- // OMP_MAP_TARGET_PARAM as they are not passed as parameters, they're marked
- // with OMP_MAP_PTR_AND_OBJ instead.
+ // OMP_MAP_TARGET_PARAM as they are not passed as parameters, they're
+ // marked with OMP_MAP_PTR_AND_OBJ instead.
auto mapFlag = mapData.Types[i];
if (mapData.IsDeclareTarget[i])
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
@@ -1929,6 +2116,33 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
collectMapDataFromMapOperands(mapData, mapOperands, moduleTranslation, DL,
builder);
+ // In the case of Fortran descriptors some members get added implicitly
+ // after the target region has been generated during CodeGen lowering
+ // which prevents them from being added trivially to the target region
+ // as map arguments, we must handle this case here by generating
+ // MapInfoData for them.
+ SmallVector<Value> mapMemberOperands;
+ for (size_t i = 0; i < mapOperands.size(); ++i) {
+ auto mapInfoOp =
+ mlir::dyn_cast<mlir::omp::MapInfoOp>(mapOperands[i].getDefiningOp());
+ for (auto members : mapInfoOp.getMembers()) {
+ if (!std::any_of(mapOperands.begin(), mapOperands.end(),
+ [&](auto mapOp) {
+ return mapOp.getDefiningOp() ==
+ members.getDefiningOp();
+ }) &&
+ !std::any_of(mapMemberOperands.begin(), mapMemberOperands.end(),
+ [&](auto mapOp) {
+ return mapOp.getDefiningOp() ==
+ members.getDefiningOp();
+ }))
+ mapMemberOperands.push_back(members);
+ }
+ }
+
+ collectMapDataFromMapOperands(mapData, mapMemberOperands, moduleTranslation,
+ DL, builder);
+
// Fill up the arrays with all the mapped variables.
llvm::OpenMPIRBuilder::MapInfosTy combinedInfo;
auto genMapInfoCB =
@@ -2322,6 +2536,7 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
auto bodyCB = [&](InsertPointTy allocaIP,
InsertPointTy codeGenIP) -> InsertPointTy {
builder.restoreIP(codeGenIP);
+
unsigned argIndex = 0;
for (auto &mapOp : mapOperands) {
auto mapInfoOp =
@@ -2332,6 +2547,7 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
moduleTranslation.mapValue(arg, mapOpValue);
argIndex++;
}
+
llvm::BasicBlock *exitBlock = convertOmpOpRegions(
targetRegion, "omp.target", builder, moduleTranslation, bodyGenStatus);
builder.SetInsertPoint(exitBlock);
@@ -2363,6 +2579,33 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
collectMapDataFromMapOperands(mapData, mapOperands, moduleTranslation, dl,
builder);
+ // In the case of Fortran descriptors some members get added implicitly
+ // after the target region has been generated during CodeGen lowering
+ // which prevents them from being added trivially to the target region
+ // as map arguments, we must handle this case here by generating
+ // MapInfoData for them.
+ SmallVector<Value> mapMemberOperands;
+ for (size_t i = 0; i < mapOperands.size(); ++i) {
+ auto mapInfoOp =
+ mlir::dyn_cast<mlir::omp::MapInfoOp>(mapOperands[i].getDefiningOp());
+ for (auto members : mapInfoOp.getMembers()) {
+ if (!std::any_of(mapOperands.begin(), mapOperands.end(),
+ [&](auto mapOp) {
+ return mapOp.getDefiningOp() ==
+ members.getDefiningOp();
+ }) &&
+ !std::any_of(mapMemberOperands.begin(), mapMemberOperands.end(),
+ [&](auto mapOp) {
+ return mapOp.getDefiningOp() ==
+ members.getDefiningOp();
+ }))
+ mapMemberOperands.push_back(members);
+ }
+ }
+
+ collectMapDataFromMapOperands(mapData, mapMemberOperands, moduleTranslation,
+ dl, builder);
+
// We wish to modify some of the methods in which kernel arguments are
// passed based on their capture type by the target region, this can
// involve generating new loads and stores, which changes the
@@ -2396,7 +2639,7 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
// keep host fallback functions working identically to the device
// version (e.g. pass ByCopy values should be treated as such on
// host and device, currently not always the case)
- if (!ompBuilder->Config.isTargetDevice()) {
+ if (!ompBuilder->Config.isTargetDevice() || !arg.getType()->isPointerTy()) {
retVal = cast<llvm::Value>(&arg);
return codeGenIP;
}
@@ -2407,7 +2650,7 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
};
llvm::SmallVector<llvm::Value *, 4> kernelInput;
- for (size_t i = 0; i < mapData.MapClause.size(); ++i) {
+ for (size_t i = 0; i < mapOperands.size(); ++i) {
// declare target arguments are not passed to kernels as arguments
if (!mapData.IsDeclareTarget[i])
kernelInput.push_back(mapData.OriginalValue[i]);
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 322843e65627603c..abe368af75f8d09b 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1422,6 +1422,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
if (failed(translator.convertFunctions()))
return nullptr;
+ translator.llvmModule->dump();
+
if (llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
return nullptr;
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 4d88d9ac86fe16c9..548a95284f373ea5 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -2082,3 +2082,18 @@ func.func @omp_targets_with_map_bounds(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> ()
return
}
+
+// CHECK-LABEL: omp_targets_is_allocatable
+// CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr)
+func.func @omp_targets_is_allocatable(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> () {
+ // CHECK: %[[MAP0:.*]] = omp.map_info var_ptr(%[[ARG0]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {is_fortran_allocatable, name = ""}
+ %mapv1 = omp.map_info var_ptr(%arg0 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {is_fortran_allocatable, name = ""}
+ // CHECK: %[[MAP1:.*]] = omp.map_info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(to) capture(ByCopy) -> !llvm.ptr {name = ""}
+ %mapv2 = omp.map_info var_ptr(%arg1 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(to) capture(ByCopy) -> !llvm.ptr {name = ""}
+ // CHECK: omp.target map_entries(%[[MAP0]] -> {{.*}}, %[[MAP1]] -> {{.*}} : !llvm.ptr, !llvm.ptr)
+ omp.target map_entries(%mapv1 -> %arg2, %mapv2 -> %arg3 : !llvm.ptr, !llvm.ptr) {
+ ^bb0(%arg2: !llvm.ptr, %arg3 : !llvm.ptr):
+ omp.terminator
+ }
+ return
+}
diff --git a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
new file mode 100644
index 0000000000000000..d3329b28ab6cfa3a
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
@@ -0,0 +1,374 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// This test checks the offload sizes, map types and base pointers and pointers
+// provided to the OpenMP kernel argument structure are correct when lowering
+// to LLVM-IR from MLIR when the fortran allocatables flag is switched on and
+// a fortran allocatable descriptor type is provided alongside the omp.map_info,
+// the test utilises mapping of array sections, full arrays and individual
+// allocated scalars.
+
+module attributes {omp.is_target_device = false} {
+ llvm.func @free(!llvm.ptr)
+ llvm.func @malloc(i64) -> !llvm.ptr
+ llvm.func @_QQmain() attributes {bindc_name = "main"} {
+ %0 = llvm.mlir.constant(1 : i32) : i32
+ %1 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %2 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %3 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %4 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %5 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %6 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %7 = llvm.mlir.constant(10 : index) : i64
+ %8 = llvm.mlir.constant(5 : index) : i64
+ %9 = llvm.mlir.constant(2 : index) : i64
+ %10 = llvm.mlir.constant(1 : index) : i64
+ %11 = llvm.mlir.constant(0 : index) : i64
+ %12 = llvm.mlir.addressof @_QFEfull_arr : !llvm.ptr
+ %13 = llvm.mlir.constant(1 : i64) : i64
+ %14 = llvm.alloca %13 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "scalar"} : (i64) -> !llvm.ptr
+ %15 = llvm.mlir.zero : !llvm.ptr
+ %16 = llvm.mlir.constant(27 : i32) : i32
+ %17 = llvm.getelementptr %15[1] : (!llvm.ptr) -> !llvm.ptr, f32
+ %18 = llvm.ptrtoint %17 : !llvm.ptr to i64
+ %19 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %20 = llvm.insertvalue %18, %19[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %21 = llvm.mlir.constant(20180515 : i32) : i32
+ %22 = llvm.insertvalue %21, %20[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %23 = llvm.mlir.constant(0 : i32) : i32
+ %24 = llvm.trunc %23 : i32 to i8
+ %25 = llvm.insertvalue %24, %22[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %26 = llvm.trunc %16 : i32 to i8
+ %27 = llvm.insertvalue %26, %25[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %28 = llvm.mlir.constant(2 : i32) : i32
+ %29 = llvm.trunc %28 : i32 to i8
+ %30 = llvm.insertvalue %29, %27[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %31 = llvm.insertvalue %24, %30[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %32 = llvm.insertvalue %15, %31[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %32, %6 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %33 = llvm.load %6 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %33, %14 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %34 = llvm.mlir.addressof @_QFEsect_arr : !llvm.ptr
+ %35 = llvm.mul %18, %7 : i64
+ %36 = llvm.call @malloc(%35) {operandSegmentSizes = array<i32: 0, 1>, uniq_name = "_QFEfull_arr.alloc"} : (i64) -> !llvm.ptr
+ %37 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %38 = llvm.insertvalue %18, %37[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %39 = llvm.insertvalue %21, %38[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %40 = llvm.trunc %0 : i32 to i8
+ %41 = llvm.insertvalue %40, %39[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %42 = llvm.insertvalue %26, %41[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %43 = llvm.insertvalue %29, %42[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %44 = llvm.insertvalue %24, %43[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %45 = llvm.insertvalue %13, %44[7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %46 = llvm.insertvalue %7, %45[7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %47 = llvm.insertvalue %18, %46[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %48 = llvm.insertvalue %36, %47[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %48, %5 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %49 = llvm.load %5 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %49, %12 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %50 = llvm.getelementptr %15[1] : (!llvm.ptr) -> !llvm.ptr, i32
+ %51 = llvm.ptrtoint %50 : !llvm.ptr to i64
+ %52 = llvm.mul %51, %7 : i64
+ %53 = llvm.call @malloc(%52) {operandSegmentSizes = array<i32: 0, 1>, uniq_name = "_QFEsect_arr.alloc"} : (i64) -> !llvm.ptr
+ %54 = llvm.mlir.constant(9 : i32) : i32
+ %55 = llvm.insertvalue %51, %37[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %56 = llvm.insertvalue %21, %55[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %57 = llvm.insertvalue %40, %56[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %58 = llvm.trunc %54 : i32 to i8
+ %59 = llvm.insertvalue %58, %57[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %60 = llvm.insertvalue %29, %59[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %61 = llvm.insertvalue %24, %60[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %62 = llvm.insertvalue %13, %61[7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %63 = llvm.insertvalue %7, %62[7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %64 = llvm.insertvalue %51, %63[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %65 = llvm.insertvalue %53, %64[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %65, %4 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %66 = llvm.load %4 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %66, %34 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %67 = llvm.call @malloc(%18) {operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFEscalar.alloc"} : (i64) -> !llvm.ptr
+ %68 = llvm.insertvalue %67, %31[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %68, %3 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %69 = llvm.load %3 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %69, %14 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %70 = llvm.load %12 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %70, %2 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %71 = llvm.getelementptr %2[0, 7, %11, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %72 = llvm.load %71 : !llvm.ptr -> i64
+ %73 = llvm.getelementptr %2[0, 7, %11, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %74 = llvm.load %73 : !llvm.ptr -> i64
+ %75 = llvm.getelementptr %2[0, 7, %11, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %76 = llvm.load %75 : !llvm.ptr -> i64
+ %77 = llvm.sub %74, %10 : i64
+ %78 = omp.bounds lower_bound(%11 : i64) upper_bound(%77 : i64) stride(%76 : i64) start_idx(%72 : i64) {stride_in_bytes = true}
+ %79 = omp.map_info var_ptr(%12 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) bounds(%78) -> !llvm.ptr {is_fortran_allocatable, name = "full_arr"}
+ %80 = llvm.load %34 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %80, %1 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %81 = llvm.getelementptr %1[0, 7, %11, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %82 = llvm.load %81 : !llvm.ptr -> i64
+ %83 = llvm.getelementptr %1[0, 7, %11, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %84 = llvm.getelementptr %1[0, 7, %11, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %85 = llvm.load %84 : !llvm.ptr -> i64
+ %86 = llvm.sub %9, %82 : i64
+ %87 = llvm.sub %8, %82 : i64
+ %88 = omp.bounds lower_bound(%86 : i64) upper_bound(%87 : i64) stride(%85 : i64) start_idx(%82 : i64) {stride_in_bytes = true}
+ %89 = omp.map_info var_ptr(%34 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) bounds(%88) -> !llvm.ptr {is_fortran_allocatable, name = "sect_arr(2:5)"}
+ %90 = omp.map_info var_ptr(%14 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {is_fortran_allocatable, name = "scalar"}
+ omp.target map_entries(%79 -> %arg0, %89 -> %arg1, %90 -> %arg2 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr):
+ %91 = llvm.mlir.constant(1 : i32) : i32
+ %92 = llvm.alloca %91 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %93 = llvm.alloca %91 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %94 = llvm.alloca %91 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %95 = llvm.alloca %91 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %96 = llvm.mlir.constant(true) : i1
+ %97 = llvm.mlir.constant(false) : i1
+ %98 = llvm.mlir.constant(0 : i64) : i64
+ %99 = llvm.mlir.constant(3 : i64) : i64
+ %100 = llvm.mlir.constant(1 : i64) : i64
+ %101 = llvm.mlir.constant(0 : index) : i64
+ %102 = llvm.mlir.constant(1.000000e+00 : f32) : f32
+ %103 = llvm.load %arg0 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %103, %95 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %104 = llvm.getelementptr %95[0, 7, %101, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %105 = llvm.load %104 : !llvm.ptr -> i64
+ %106 = llvm.getelementptr %95[0, 7, %101, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %107 = llvm.getelementptr %95[0, 7, %101, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %108 = llvm.getelementptr %95[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %109 = llvm.load %108 : !llvm.ptr -> !llvm.ptr
+ %110 = llvm.sub %100, %105 : i64
+ %111 = llvm.getelementptr %109[%110] : (!llvm.ptr, i64) -> !llvm.ptr, f32
+ llvm.store %102, %111 : f32, !llvm.ptr
+ %112 = llvm.load %arg1 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.store %112, %94 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+ %113 = llvm.getelementptr %94[0, 7, %101, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %114 = llvm.load %113 : !llvm.ptr -> i64
+ %115 = llvm.getelementptr %94[0, 7, %101, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %116 = llvm.getelementptr %94[0, 7, %101, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %117 = llvm.getelementptr %94[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %118 = llvm.load %117 : !llvm.ptr -> !llvm.ptr
+ %119 = llvm.sub %99, %114 : i64
+ %120 = llvm.getelementptr %118[%119] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ llvm.store %91, %120 : i32, !llvm.ptr
+ %121 = llvm.load %arg2 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %121, %93 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %122 = llvm.getelementptr %93[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %123 = llvm.load %122 : !llvm.ptr -> !llvm.ptr
+ %124 = llvm.ptrtoint %123 : !llvm.ptr to i64
+ %125 = llvm.icmp "ne" %124, %98 : i64
+ llvm.cond_br %125, ^bb2(%97, %123 : i1, !llvm.ptr), ^bb1
+ ^bb1: // pred: ^bb0
+ %126 = llvm.mlir.zero : !llvm.ptr
+ %127 = llvm.getelementptr %126[1] : (!llvm.ptr) -> !llvm.ptr, f32
+ %128 = llvm.ptrtoint %127 : !llvm.ptr to i64
+ %129 = llvm.call @malloc(%128) {in_type = f32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = ".auto.alloc"} : (i64) -> !llvm.ptr
+ llvm.br ^bb2(%96, %129 : i1, !llvm.ptr)
+ ^bb2(%130: i1, %131: !llvm.ptr): // 2 preds: ^bb0, ^bb1
+ %132 = llvm.sitofp %91 : i32 to f32
+ llvm.store %132, %131 : f32, !llvm.ptr
+ llvm.cond_br %130, ^bb3, ^bb6
+ ^bb3: // pred: ^bb2
+ llvm.cond_br %125, ^bb4, ^bb5
+ ^bb4: // pred: ^bb3
+ llvm.call @free(%123) : (!llvm.ptr) -> ()
+ llvm.br ^bb5
+ ^bb5: // 2 preds: ^bb3, ^bb4
+ %133 = llvm.mlir.constant(27 : i32) : i32
+ %134 = llvm.mlir.zero : !llvm.ptr
+ %135 = llvm.getelementptr %134[1] : (!llvm.ptr) -> !llvm.ptr, f32
+ %136 = llvm.ptrtoint %135 : !llvm.ptr to i64
+ %137 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %138 = llvm.insertvalue %136, %137[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %139 = llvm.mlir.constant(20180515 : i32) : i32
+ %140 = llvm.insertvalue %139, %138[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %141 = llvm.mlir.constant(0 : i32) : i32
+ %142 = llvm.trunc %141 : i32 to i8
+ %143 = llvm.insertvalue %142, %140[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %144 = llvm.trunc %133 : i32 to i8
+ %145 = llvm.insertvalue %144, %143[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %146 = llvm.mlir.constant(2 : i32) : i32
+ %147 = llvm.trunc %146 : i32 to i8
+ %148 = llvm.insertvalue %147, %145[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %149 = llvm.insertvalue %142, %148[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ %150 = llvm.insertvalue %131, %149[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %150, %92 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ %151 = llvm.load %92 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+ llvm.store %151, %arg2 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+ llvm.br ^bb6
+ ^bb6: // 2 preds: ^bb2, ^bb5
+ omp.terminator
+ }
+ llvm.return
+ }
+ llvm.mlir.global internal @_QFEfull_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
+ %0 = llvm.mlir.constant(0 : index) : i64
+ %1 = llvm.mlir.zero : !llvm.ptr
+ %2 = llvm.mlir.constant(27 : i32) : i32
+ %3 = llvm.getelementptr %1[1] : (!llvm.ptr) -> !llvm.ptr, f32
+ %4 = llvm.ptrtoint %3 : !llvm.ptr to i64
+ %5 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %6 = llvm.insertvalue %4, %5[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %7 = llvm.mlir.constant(20180515 : i32) : i32
+ %8 = llvm.insertvalue %7, %6[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %9 = llvm.mlir.constant(1 : i32) : i32
+ %10 = llvm.trunc %9 : i32 to i8
+ %11 = llvm.insertvalue %10, %8[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %12 = llvm.trunc %2 : i32 to i8
+ %13 = llvm.insertvalue %12, %11[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %14 = llvm.mlir.constant(2 : i32) : i32
+ %15 = llvm.trunc %14 : i32 to i8
+ %16 = llvm.insertvalue %15, %13[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %17 = llvm.mlir.constant(0 : i32) : i32
+ %18 = llvm.trunc %17 : i32 to i8
+ %19 = llvm.insertvalue %18, %16[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %20 = llvm.mlir.constant(1 : i64) : i64
+ %21 = llvm.insertvalue %20, %19[7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %22 = llvm.insertvalue %0, %21[7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %23 = llvm.insertvalue %4, %22[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %24 = llvm.insertvalue %1, %23[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.return %24 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ }
+ llvm.mlir.global internal @_QFEsect_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
+ %0 = llvm.mlir.constant(0 : index) : i64
+ %1 = llvm.mlir.zero : !llvm.ptr
+ %2 = llvm.mlir.constant(9 : i32) : i32
+ %3 = llvm.getelementptr %1[1] : (!llvm.ptr) -> !llvm.ptr, i32
+ %4 = llvm.ptrtoint %3 : !llvm.ptr to i64
+ %5 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %6 = llvm.insertvalue %4, %5[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %7 = llvm.mlir.constant(20180515 : i32) : i32
+ %8 = llvm.insertvalue %7, %6[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %9 = llvm.mlir.constant(1 : i32) : i32
+ %10 = llvm.trunc %9 : i32 to i8
+ %11 = llvm.insertvalue %10, %8[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %12 = llvm.trunc %2 : i32 to i8
+ %13 = llvm.insertvalue %12, %11[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %14 = llvm.mlir.constant(2 : i32) : i32
+ %15 = llvm.trunc %14 : i32 to i8
+ %16 = llvm.insertvalue %15, %13[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %17 = llvm.mlir.constant(0 : i32) : i32
+ %18 = llvm.trunc %17 : i32 to i8
+ %19 = llvm.insertvalue %18, %16[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %20 = llvm.mlir.constant(1 : i64) : i64
+ %21 = llvm.insertvalue %20, %19[7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %22 = llvm.insertvalue %0, %21[7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %23 = llvm.insertvalue %4, %22[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %24 = llvm.insertvalue %1, %23[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ llvm.return %24 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ }
+ llvm.mlir.global linkonce constant @_QQcl.6606f061cfd55e600f1165aa97a647a5() comdat(@__llvm_comdat::@_QQcl.6606f061cfd55e600f1165aa97a647a5) {addr_space = 0 : i32} : !llvm.array<97 x i8> {
+ %0 = llvm.mlir.constant("/home/agozillo/git/flang-dev/work-dir/declare-target-map/omptarget-fortran-allocatables-test.f90\00") : !llvm.array<97 x i8>
+ llvm.return %0 : !llvm.array<97 x i8>
+ }
+ llvm.comdat @__llvm_comdat {
+ llvm.comdat_selector @_QQcl.6606f061cfd55e600f1165aa97a647a5 any
+ }
+ llvm.mlir.global external constant @_QQEnvironmentDefaults() {addr_space = 0 : i32} : !llvm.ptr {
+ %0 = llvm.mlir.zero : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+ }
+}
+
+// CHECK: @.offload_sizes = private unnamed_addr constant [9 x i64] [i64 0, i64 48, i64 0, i64 0, i64 48, i64 0, i64 0, i64 24, i64 0]
+// CHECK: @.offload_maptypes = private unnamed_addr constant [9 x i64] [i64 32, i64 281474976710657, i64 281474976710675, i64 32, i64 1125899906842625, i64 1125899906842643, i64 32, i64 1970324836974593, i64 1970324836974611]
+// CHECK: @.offload_mapnames = private constant [9 x ptr] [ptr @0, ptr @0, ptr @0, ptr @1, ptr @1, ptr @1, ptr @2, ptr @2, ptr @2]
+
+// CHECK: define void @_QQmain()
+
+// CHECK: %[[ARR_SECT_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+// CHECK: %[[FULL_ARR_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+// CHECK: %[[SCALAR_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8
+
+// CHECK: %[[FULL_ARR_UB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[FULL_ARR_ALLOCA]], i32 0, i32 7, i64 0, i32 1
+// CHECK: %[[LFULL_ARR_UB:.*]] = load i64, ptr %[[FULL_ARR_UB]], align 4
+// CHECK: %[[FULL_ARR_UB2:.*]] = sub i64 %[[LFULL_ARR_UB]], 1
+
+// CHECK: %[[ARR_SECT_LB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ARR_SECT_ALLOCA]], i32 0, i32 7, i64 0, i32 0
+// CHECK: %[[LARR_SECT_LB:.*]] = load i64, ptr %[[ARR_SECT_LB]], align 4
+// CHECK: %[[ARR_SECT_BOUNDS:.*]] = sub i64 2, %[[LARR_SECT_LB]]
+// CHECK: %[[ARR_SECT_BOUNDS2:.*]] = sub i64 5, %[[LARR_SECT_LB]]
+
+// CHECK: %[[FULL_ARR_UB3:.*]] = sub i64 %[[FULL_ARR_UB2]], 0
+// CHECK: %[[FULL_ARR_UB4:.*]] = add i64 %[[FULL_ARR_UB3]], 1
+// CHECK: %[[FULL_ARR_UB5:.*]] = mul i64 1, %[[FULL_ARR_UB4]]
+// CHECK: %[[FULL_ARR_TYPE_SIZE:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i64 0, i32 1), align 4
+// CHECK: %[[FULL_ARR_SIZE:.*]] = mul i64 %[[FULL_ARR_UB5]], %[[FULL_ARR_TYPE_SIZE]]
+
+// CHECK: %[[ARR_SECT_RANGE:.*]] = sub i64 %[[ARR_SECT_BOUNDS2]], %[[ARR_SECT_BOUNDS]]
+// CHECK: %[[ARR_SECT_ELEMENTS:.*]] = add i64 %[[ARR_SECT_RANGE]], 1
+// CHECK: %[[ARR_SECT_ELEMENTS2:.*]] = mul i64 1, %[[ARR_SECT_ELEMENTS]]
+// CHECK: %[[ARR_SECT_TYPE_SIZE:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i64 0, i32 1), align 4
+// CHECK: %[[ARR_SECT_SIZE:.*]] = mul i64 %[[ARR_SECT_ELEMENTS2]], %[[ARR_SECT_TYPE_SIZE]]
+
+// CHECK: %[[SCALAR_TYPE_SIZE:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i64 0, i32 1
+// CHECK: %[[SCALAR_SIZE:.*]] = load i64, ptr %[[SCALAR_TYPE_SIZE]], align 4
+
+// CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEfull_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+// CHECK: %[[FULL_ARR_ELE_SZ:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i64 0, i32 1), align 4
+// CHECK: %[[FULL_ARR_OFFSET:.*]] = mul i64 0, %[[FULL_ARR_ELE_SZ]]
+// CHECK: %[[LFULL_ARR:.*]] = load ptr, ptr @_QFEfull_arr, align 8
+// CHECK: %[[FULL_ARR_PTR:.*]] = getelementptr i8, ptr %[[LFULL_ARR]], i64 %[[FULL_ARR_OFFSET]]
+
+// CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEsect_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+// CHECK: %[[ARR_SECT_ELE_SZ:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i64 0, i32 1), align 4
+// CHECK: %[[ARR_SECT_OFFSET:.*]] = mul i64 %[[ARR_SECT_BOUNDS]], %[[ARR_SECT_ELE_SZ]]
+// CHECK: %[[LARR_SECT:.*]] = load ptr, ptr @_QFEsect_arr, align 8
+// CHECK: %[[ARR_SECT_PTR:.*]] = getelementptr i8, ptr %[[LARR_SECT]], i64 %[[ARR_SECT_OFFSET]]
+
+// CHECK: %[[SCALAR_DESC_CALC1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 1
+// CHECK: %[[SCALAR_DESC_CALC2:.*]] = ptrtoint ptr %[[SCALAR_DESC_CALC1]] to i64
+// CHECK: %[[SCALAR_DESC_CALC3:.*]] = ptrtoint ptr %[[SCALAR_ALLOCA]] to i64
+// CHECK: %[[SCALAR_DESC_CALC4:.*]] = sub i64 %[[SCALAR_DESC_CALC2]], %[[SCALAR_DESC_CALC3]]
+// CHECK: %[[SCALAR_DESC_SZ:.*]] = sdiv exact i64 %[[SCALAR_DESC_CALC4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+// CHECK: %[[SCALAR_BASE:.*]] = getelementptr inbounds { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i64 0, i32 0
+// CHECK: %[[LSCALAR_BASE:.*]] = load ptr, ptr %[[SCALAR_BASE]], align 8
+// CHECK: %[[SCALAR_PTR:.*]] = getelementptr i8, ptr %[[LSCALAR_BASE]], i64 0
+
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK: store i64 %[[FULL_ARR_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+// CHECK: store ptr %[[FULL_ARR_PTR]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 2
+// CHECK: store i64 %[[FULL_ARR_SIZE]], ptr %[[OFFLOADSIZES]], align 8
+
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 3
+// CHECK: store i64 %[[ARR_SECT_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
+// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 4
+// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
+// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+// CHECK: store ptr %[[ARR_SECT_PTR]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 5
+// CHECK: store i64 %[[ARR_SECT_SIZE]], ptr %[[OFFLOADSIZES]], align 8
+
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 6
+// CHECK: store i64 %[[SCALAR_DESC_SZ]], ptr %[[OFFLOADSIZES]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 7
+// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 7
+// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 8
+// CHECK: store ptr %[[SCALAR_BASE]], ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 8
+// CHECK: store ptr %[[SCALAR_PTR]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 8
+// CHECK: store i64 %[[SCALAR_SIZE]], ptr %[[OFFLOADSIZES]], align 8
diff --git a/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-1d-bounds.f90 b/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-1d-bounds.f90
new file mode 100644
index 0000000000000000..99dbe99d40497c73
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-1d-bounds.f90
@@ -0,0 +1,46 @@
+! Offloading test checking interaction of a
+! two 1-D allocatable arrays with a target region
+! while providing the map upper and lower bounds
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer, allocatable :: sp_read(:), sp_write(:)
+ allocate(sp_read(10))
+ allocate(sp_write(10))
+
+ do i = 1, 10
+ sp_read(i) = i
+ sp_write(i) = 0
+ end do
+
+ !$omp target map(tofrom:sp_read(2:6)) map(tofrom:sp_write(2:6))
+ do i = 1, 10
+ sp_write(i) = sp_read(i)
+ end do
+ !$omp end target
+
+ do i = 1, 10
+ print *, sp_write(i)
+ end do
+
+ deallocate(sp_read)
+ deallocate(sp_write)
+end program
+
+! CHECK: 0
+! CHECK: 2
+! CHECK: 3
+! CHECK: 4
+! CHECK: 5
+! CHECK: 6
+! CHECK: 0
+! CHECK: 0
+! CHECK: 0
+! CHECK: 0
diff --git a/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-3d-bounds.f90 b/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-3d-bounds.f90
new file mode 100644
index 0000000000000000..0786e0fd744e786f
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/allocatable-array-section-3d-bounds.f90
@@ -0,0 +1,44 @@
+! Offloading test checking interaction of allocatables
+! with multi-dimensional bounds (3-D in this case) and
+! a target region
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer, allocatable :: inArray(:,:,:)
+ integer, allocatable :: outArray(:,:,:)
+
+ allocate(inArray(3,3,3))
+ allocate(outArray(3,3,3))
+
+ do i = 1, 3
+ do j = 1, 3
+ do k = 1, 3
+ inArray(i, j, k) = 42
+ outArray(i, j, k) = 0
+ end do
+ end do
+ end do
+
+!$omp target map(tofrom:inArray(1:3, 1:3, 2:2), outArray(1:3, 1:3, 1:3))
+ do j = 1, 3
+ do k = 1, 3
+ outArray(k, j, 2) = inArray(k, j, 2)
+ end do
+ end do
+!$omp end target
+
+print *, outArray
+
+deallocate(inArray)
+deallocate(outArray)
+
+end program
+
+! CHECK: 0 0 0 0 0 0 0 0 0 42 42 42 42 42 42 42 42 42 0 0 0 0 0 0 0 0 0
diff --git a/openmp/libomptarget/test/offloading/fortran/allocatable-map-scopes.f95 b/openmp/libomptarget/test/offloading/fortran/allocatable-map-scopes.f95
new file mode 100644
index 0000000000000000..bb47d3de96d2a9b7
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/allocatable-map-scopes.f95
@@ -0,0 +1,66 @@
+! Offloading test checking interaction of allocatables
+! with target in different scopes
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+module test
+ contains
+ subroutine func_arg(arg_alloc)
+ integer, allocatable, intent (inout) :: arg_alloc(:)
+
+ !$omp target map(tofrom: arg_alloc)
+ do index = 1, 10
+ arg_alloc(index) = arg_alloc(index) + index
+ end do
+ !$omp end target
+
+ print *, arg_alloc
+ end subroutine func_arg
+end module
+
+subroutine func
+ integer, allocatable :: local_alloc(:)
+ allocate(local_alloc(10))
+
+ !$omp target map(tofrom: local_alloc)
+ do index = 1, 10
+ local_alloc(index) = index
+ end do
+ !$omp end target
+
+ print *, local_alloc
+
+ deallocate(local_alloc)
+end subroutine func
+
+
+program main
+ use test
+ integer, allocatable :: map_ptr(:)
+
+ allocate(map_ptr(10))
+
+ !$omp target map(tofrom: map_ptr)
+ do index = 1, 10
+ map_ptr(index) = index
+ end do
+ !$omp end target
+
+ call func
+
+ print *, map_ptr
+
+ call func_arg(map_ptr)
+
+ deallocate(map_ptr)
+end program
+
+! CHECK: 1 2 3 4 5 6 7 8 9 10
+! CHECK: 1 2 3 4 5 6 7 8 9 10
+! CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/openmp/libomptarget/test/offloading/fortran/pointer-scopes-enter-exit-map.f90 b/openmp/libomptarget/test/offloading/fortran/pointer-scopes-enter-exit-map.f90
new file mode 100644
index 0000000000000000..dee75af06927beee
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/pointer-scopes-enter-exit-map.f90
@@ -0,0 +1,83 @@
+! Offloading test checking interaction of pointers
+! with target in different scopes
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+module test
+ contains
+ subroutine func_arg(arg_alloc)
+ integer, pointer, intent (inout) :: arg_alloc(:)
+
+ !$omp target enter data map(alloc: arg_alloc)
+
+ !$omp target
+ do index = 1, 10
+ arg_alloc(index) = arg_alloc(index) + index
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from: arg_alloc)
+
+ !$omp target exit data map(delete: arg_alloc)
+
+ print *, arg_alloc
+ end subroutine func_arg
+end module
+
+subroutine func
+ integer, pointer :: local_alloc(:)
+ allocate(local_alloc(10))
+
+ !$omp target enter data map(alloc: local_alloc)
+
+ !$omp target
+ do index = 1, 10
+ local_alloc(index) = index
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from: local_alloc)
+
+ !$omp target exit data map(delete: local_alloc)
+
+ print *, local_alloc
+
+ deallocate(local_alloc)
+end subroutine func
+
+
+program main
+ use test
+ integer, pointer :: map_ptr(:)
+ allocate(map_ptr(10))
+
+ !$omp target enter data map(alloc: map_ptr)
+
+ !$omp target
+ do index = 1, 10
+ map_ptr(index) = index
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from: map_ptr)
+
+ !$omp target exit data map(delete: map_ptr)
+
+ call func
+
+ print *, map_ptr
+
+ call func_arg(map_ptr)
+
+ deallocate(map_ptr)
+end program
+
+! CHECK: 1 2 3 4 5 6 7 8 9 10
+! CHECK: 1 2 3 4 5 6 7 8 9 10
+! CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/openmp/libomptarget/test/offloading/fortran/pointer-target-array-section-3d-bounds.f90 b/openmp/libomptarget/test/offloading/fortran/pointer-target-array-section-3d-bounds.f90
new file mode 100644
index 0000000000000000..ff2298cf5dbc9dc0
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/pointer-target-array-section-3d-bounds.f90
@@ -0,0 +1,43 @@
+! Offloading test checking interaction of pointer
+! and target with target where 3-D bounds have
+! been specified
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer, pointer :: inArray(:,:,:)
+ integer, pointer :: outArray(:,:,:)
+ integer, target :: in(3,3,3)
+ integer, target :: out(3,3,3)
+
+ inArray => in
+ outArray => out
+
+ do i = 1, 3
+ do j = 1, 3
+ do k = 1, 3
+ inArray(i, j, k) = 42
+ outArray(i, j, k) = 0
+ end do
+ end do
+ end do
+
+!$omp target map(tofrom:inArray(1:3, 1:3, 2:2), outArray(1:3, 1:3, 1:3))
+ do j = 1, 3
+ do k = 1, 3
+ outArray(k, j, 2) = inArray(k, j, 2)
+ end do
+ end do
+!$omp end target
+
+ print *, outArray
+
+end program
+
+! CHECK: 0 0 0 0 0 0 0 0 0 42 42 42 42 42 42 42 42 42 0 0 0 0 0 0 0 0 0
diff --git a/openmp/libomptarget/test/offloading/fortran/pointer-target-map-scopes.f95 b/openmp/libomptarget/test/offloading/fortran/pointer-target-map-scopes.f95
new file mode 100644
index 0000000000000000..d9a7000719f0e85e
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/pointer-target-map-scopes.f95
@@ -0,0 +1,64 @@
+! Offloading test checking interaction of pointer
+! and target with target across multiple scopes
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+module test
+ contains
+ subroutine func_arg(arg_alloc)
+ integer, pointer, intent (inout) :: arg_alloc(:)
+
+ !$omp target map(tofrom: arg_alloc)
+ do index = 1, 10
+ arg_alloc(index) = arg_alloc(index) + index
+ end do
+ !$omp end target
+
+ print *, arg_alloc
+ end subroutine func_arg
+end module
+
+subroutine func
+ integer, pointer :: local_alloc(:)
+ integer, target :: b(10)
+ local_alloc => b
+
+ !$omp target map(tofrom: local_alloc)
+ do index = 1, 10
+ local_alloc(index) = index
+ end do
+ !$omp end target
+
+ print *, local_alloc
+ end subroutine func
+
+
+ program main
+ use test
+ integer, pointer :: map_ptr(:)
+ integer, target :: b(10)
+
+ map_ptr => b
+
+ !$omp target map(tofrom: map_ptr)
+ do index = 1, 10
+ map_ptr(index) = index
+ end do
+ !$omp end target
+
+ call func
+
+ print *, map_ptr
+
+ call func_arg(map_ptr)
+end program
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/openmp/libomptarget/test/offloading/fortran/target_enter_exit_allocatables.f90 b/openmp/libomptarget/test/offloading/fortran/target_enter_exit_allocatables.f90
new file mode 100644
index 0000000000000000..865be95ba9682d3c
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/target_enter_exit_allocatables.f90
@@ -0,0 +1,44 @@
+! Offloading test checking interaction of allocatables
+! with enter, exit and target
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer, allocatable :: A(:)
+ allocate(A(10))
+
+ !$omp target enter data map(alloc: A)
+
+ !$omp target
+ do I = 1, 10
+ A(I) = I
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from: A)
+
+ !$omp target exit data map(delete: A)
+
+ do i = 1, 10
+ print *, A(i)
+ end do
+
+ deallocate(A)
+end program
+
+! CHECK: 1
+! CHECK: 2
+! CHECK: 3
+! CHECK: 4
+! CHECK: 5
+! CHECK: 6
+! CHECK: 7
+! CHECK: 8
+! CHECK: 9
+! CHECK: 10
diff --git a/openmp/libomptarget/test/offloading/fortran/target_enter_exit_array.f90 b/openmp/libomptarget/test/offloading/fortran/target_enter_exit_array.f90
new file mode 100644
index 0000000000000000..4a9fb6ee177f6548
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/target_enter_exit_array.f90
@@ -0,0 +1,41 @@
+! Offloading test checking interaction of fixed size
+! arrays with enter, exit and target
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer :: A(10)
+
+ !$omp target enter data map(alloc: A)
+
+ !$omp target
+ do I = 1, 10
+ A(I) = I
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from: A)
+
+ !$omp target exit data map(delete: A)
+
+ do i = 1, 10
+ print *, A(i)
+ end do
+end program
+
+! CHECK: 1
+! CHECK: 2
+! CHECK: 3
+! CHECK: 4
+! CHECK: 5
+! CHECK: 6
+! CHECK: 7
+! CHECK: 8
+! CHECK: 9
+! CHECK: 10
diff --git a/openmp/libomptarget/test/offloading/fortran/target_single_value_allocate.f90 b/openmp/libomptarget/test/offloading/fortran/target_single_value_allocate.f90
new file mode 100644
index 0000000000000000..9330e0094495246b
--- /dev/null
+++ b/openmp/libomptarget/test/offloading/fortran/target_single_value_allocate.f90
@@ -0,0 +1,26 @@
+! Offloading test checking interaction of a
+! non-array allocatable with a target region
+! REQUIRES: flang, amdgcn-amd-amdhsa
+! UNSUPPORTED: nvptx64-nvidia-cuda
+! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+! UNSUPPORTED: aarch64-unknown-linux-gnu
+! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
+! UNSUPPORTED: x86_64-pc-linux-gnu
+! UNSUPPORTED: x86_64-pc-linux-gnu-LTO
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ integer, allocatable :: test
+ allocate(test)
+ test = 10
+
+!$omp target map(tofrom:test)
+ test = 50
+!$omp end target
+
+ print *, test
+
+ deallocate(test)
+end program
+
+! CHECK: 50
More information about the flang-commits
mailing list