From 88d999670f8fee2aea8a96fe907128844778a683 Mon Sep 17 00:00:00 2001 From: Kareem Ergawy Date: Wed, 4 Dec 2024 06:46:04 +0100 Subject: [PATCH] [flang][OpenMP][DoConcurrent] Support `fir.shape_shift` values (#211) Extends support for shaped values by adding support for values whose shaped are defined by `fir.shapeshift` types. To that end, we add maps to store all the info from which we can recreate the shape of the mapped object. --- .../OpenMP/DoConcurrentConversion.cpp | 313 ++++++++++++------ .../Transforms/DoConcurrent/basic_device.f90 | 2 +- .../DoConcurrent/map_shape_info.f90 | 86 +++++ .../DoConcurrent/not_perfectly_nested.f90 | 7 +- .../DoConcurrent/runtime_sized_array.f90 | 7 +- .../DoConcurrent/skip_all_nested_loops.f90 | 7 +- 6 files changed, 303 insertions(+), 119 deletions(-) create mode 100644 flang/test/Transforms/DoConcurrent/map_shape_info.f90 diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp index 2218a00d98db60..5055114c0b26a8 100644 --- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp +++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp @@ -76,6 +76,41 @@ mlir::omp::MapInfoOp createMapInfoOp( return op; } +mlir::Value mapTemporaryValue(fir::FirOpBuilder &builder, + mlir::omp::TargetOp targetOp, mlir::Value val, + llvm::StringRef name) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointAfterValue(val); + auto copyVal = builder.createTemporary(val.getLoc(), val.getType()); + builder.createStoreWithConvert(copyVal.getLoc(), val, copyVal); + + llvm::SmallVector bounds; + builder.setInsertionPoint(targetOp); + mlir::Value mapOp = createMapInfoOp( + builder, copyVal.getLoc(), copyVal, + /*varPtrPtr=*/mlir::Value{}, name.str(), bounds, + /*members=*/llvm::SmallVector{}, + /*membersIndex=*/mlir::ArrayAttr{}, + static_cast>( + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT), + mlir::omp::VariableCaptureKind::ByCopy, copyVal.getType()); + + mlir::Region &targetRegion = targetOp.getRegion(); + + auto argIface = llvm::cast(*targetOp); + unsigned insertIndex = + argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs(); + targetOp.getMapVarsMutable().append(mlir::ValueRange{mapOp}); + mlir::Value clonedValArg = + targetRegion.insertArgument(insertIndex, mapOp.getType(), mapOp.getLoc()); + + mlir::Block *targetEntryBlock = &targetRegion.getBlocks().front(); + builder.setInsertionPointToStart(targetEntryBlock); + auto loadOp = + builder.create(clonedValArg.getLoc(), clonedValArg); + return loadOp.getResult(); +} + /// Check if cloning the bounds introduced any dependency on the outer region. /// If so, then either clone them as well if they are MemoryEffectFree, or else /// copy them to a new temporary and add them to the map and block_argument @@ -104,31 +139,10 @@ void cloneOrMapRegionOutsiders(fir::FirOpBuilder &builder, return use.getOwner()->getBlock() == targetEntryBlock; }); } else { - mlir::OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointAfter(valOp); - auto copyVal = builder.createTemporary(val.getLoc(), val.getType()); - builder.createStoreWithConvert(copyVal.getLoc(), val, copyVal); - - llvm::SmallVector bounds; - std::stringstream name; - builder.setInsertionPoint(targetOp); - mlir::Value mapOp = createMapInfoOp( - builder, copyVal.getLoc(), copyVal, - /*varPtrPtr=*/mlir::Value{}, name.str(), bounds, - /*members=*/llvm::SmallVector{}, - /*membersIndex=*/mlir::ArrayAttr{}, - static_cast< - std::underlying_type_t>( - llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT), - mlir::omp::VariableCaptureKind::ByCopy, copyVal.getType()); - targetOp.getMapVarsMutable().append(mapOp); - mlir::Value clonedValArg = - targetRegion.addArgument(copyVal.getType(), copyVal.getLoc()); - builder.setInsertionPointToStart(targetEntryBlock); - auto loadOp = - builder.create(clonedValArg.getLoc(), clonedValArg); + mlir::Value mappedTemp = mapTemporaryValue(builder, targetOp, val, + /*name=*/llvm::StringRef{}); val.replaceUsesWithIf( - loadOp->getResult(0), [targetEntryBlock](mlir::OpOperand &use) { + mappedTemp, [targetEntryBlock](mlir::OpOperand &use) { return use.getOwner()->getBlock() == targetEntryBlock; }); } @@ -598,25 +612,25 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { loopNestClauseOps, &targetClauseOps); // Prevent mapping host-evaluated variables. - loopNestLiveIns.erase( - llvm::remove_if(loopNestLiveIns, - [&](mlir::Value liveIn) { - return llvm::is_contained( - targetClauseOps.hostEvalVars, liveIn); - }), - loopNestLiveIns.end()); - + loopNestLiveIns.erase(llvm::remove_if(loopNestLiveIns, + [&](mlir::Value liveIn) { + return llvm::is_contained( + targetClauseOps.hostEvalVars, + liveIn); + }), + loopNestLiveIns.end()); + + LiveInShapeInfoMap liveInShapeInfoMap; // The outermost loop will contain all the live-in values in all nested // loops since live-in values are collected recursively for all nested // ops. for (mlir::Value liveIn : loopNestLiveIns) - targetClauseOps.mapVars.push_back( - genMapInfoOpForLiveIn(rewriter, liveIn)); + targetClauseOps.mapVars.push_back(genMapInfoOpForLiveIn( + rewriter, liveIn, liveInShapeInfoMap[liveIn])); targetOp = genTargetOp(doLoop.getLoc(), rewriter, mapper, loopNestLiveIns, - targetClauseOps, loopNestClauseOps); - + targetClauseOps, loopNestClauseOps, liveInShapeInfoMap); genTeamsOp(doLoop.getLoc(), rewriter); } @@ -655,48 +669,104 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { } private: - void genBoundsOps(mlir::ConversionPatternRewriter &rewriter, - mlir::Location loc, hlfir::DeclareOp declareOp, - llvm::SmallVectorImpl &boundsOps) const { - if (declareOp.getShape() == nullptr) { + struct TargetDeclareShapeCreationInfo { + // Note: We use `std::vector` (rather than `llvm::SmallVector` as usual) to + // interface more easily `ShapeShiftOp::getOrigins()` which returns + // `std::vector`. + std::vector startIndices{}; + std::vector extents{}; + + bool isShapedValue() const { return !extents.empty(); } + bool isShapeShiftedValue() const { return !startIndices.empty(); } + }; + + using LiveInShapeInfoMap = + llvm::DenseMap; + + void + genBoundsOps(mlir::ConversionPatternRewriter &rewriter, mlir::Location loc, + mlir::Value shape, llvm::SmallVectorImpl &boundsOps, + TargetDeclareShapeCreationInfo &targetShapeCreationInfo) const { + if (shape == nullptr) { return; } - auto shapeOp = mlir::dyn_cast_if_present( - declareOp.getShape().getDefiningOp()); + auto shapeOp = + mlir::dyn_cast_if_present(shape.getDefiningOp()); + auto shapeShiftOp = + mlir::dyn_cast_if_present(shape.getDefiningOp()); + + if (shapeOp == nullptr && shapeShiftOp == nullptr) + TODO(loc, + "Shapes not defined by `fir.shape` or `fir.shape_shift` op's are " + "not supported yet."); + + auto extents = shapeOp != nullptr + ? std::vector(shapeOp.getExtents().begin(), + shapeOp.getExtents().end()) + : shapeShiftOp.getExtents(); + + mlir::Type idxType = extents.front().getType(); - if (shapeOp == nullptr) - TODO(loc, "Shapes not defined by shape op's are not supported yet."); + auto one = rewriter.create( + loc, idxType, rewriter.getIntegerAttr(idxType, 1)); + // For non-shifted values, that starting index is the default Fortran + // value: 1. + std::vector startIndices = + shapeOp != nullptr ? std::vector(extents.size(), one) + : shapeShiftOp.getOrigins(); - auto extents = shapeOp.getExtents(); + auto genBoundsOp = [&](mlir::Value startIndex, mlir::Value extent) { + // We map the entire range of data by default, therefore, we always map + // from the start. + auto normalizedLB = rewriter.create( + loc, idxType, rewriter.getIntegerAttr(idxType, 0)); - auto genBoundsOp = [&](mlir::Value extent) { - mlir::Type extentType = extent.getType(); - auto lb = rewriter.create( - loc, extentType, rewriter.getIntegerAttr(extentType, 0)); - // TODO I think this caluclation might not be correct. But this is how - // it is done in PFT->OpenMP lowering. So keeping it like this until we - // double check. - mlir::Value ub = rewriter.create(loc, extent, lb); + mlir::Value ub = rewriter.create(loc, extent, one); return rewriter.create( - loc, rewriter.getType(), lb, ub, extent, - mlir::Value{}, false, mlir::Value{}); + loc, rewriter.getType(), normalizedLB, ub, + extent, + /*stride=*/mlir::Value{}, /*stride_in_bytes=*/false, startIndex); }; - for (auto extent : extents) - boundsOps.push_back(genBoundsOp(extent)); + for (auto [startIndex, extent] : llvm::zip_equal(startIndices, extents)) + boundsOps.push_back(genBoundsOp(startIndex, extent)); + + if (shapeShiftOp != nullptr) + targetShapeCreationInfo.startIndices = std::move(startIndices); + targetShapeCreationInfo.extents = std::move(extents); } - mlir::omp::MapInfoOp - genMapInfoOpForLiveIn(mlir::ConversionPatternRewriter &rewriter, - mlir::Value liveIn) const { + mlir::omp::MapInfoOp genMapInfoOpForLiveIn( + mlir::ConversionPatternRewriter &rewriter, mlir::Value liveIn, + TargetDeclareShapeCreationInfo &targetShapeCreationInfo) const { + mlir::Value rawAddr = liveIn; + mlir::Value shape = nullptr; + llvm::StringRef name; + + mlir::Operation *liveInDefiningOp = liveIn.getDefiningOp(); auto declareOp = - mlir::dyn_cast_if_present(liveIn.getDefiningOp()); + mlir::dyn_cast_if_present(liveInDefiningOp); + + if (declareOp != nullptr) { + // Use the raw address to avoid unboxing `fir.box` values whenever + // possible. Put differently, if we have access to the direct value memory + // reference/address, we use it. + rawAddr = declareOp.getOriginalBase(); + shape = declareOp.getShape(); + name = declareOp.getUniqName(); + } - if (declareOp == nullptr) - TODO(liveIn.getLoc(), - "Values not defined by declare op's are not supported yet."); + if (!llvm::isa(rawAddr.getType())) { + fir::FirOpBuilder builder( + rewriter, fir::getKindMapping( + liveInDefiningOp->getParentOfType())); + builder.setInsertionPointAfter(liveInDefiningOp); + auto copyVal = builder.createTemporary(liveIn.getLoc(), liveIn.getType()); + builder.createStoreWithConvert(copyVal.getLoc(), liveIn, copyVal); + rawAddr = copyVal; + } mlir::Type liveInType = liveIn.getType(); mlir::Type eleType = liveInType; @@ -716,12 +786,9 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { } llvm::SmallVector boundsOps; - genBoundsOps(rewriter, liveIn.getLoc(), declareOp, boundsOps); + genBoundsOps(rewriter, liveIn.getLoc(), shape, boundsOps, + targetShapeCreationInfo); - // Use the raw address to avoid unboxing `fir.box` values whenever possible. - // Put differently, if we have access to the direct value memory - // reference/address, we use it. - mlir::Value rawAddr = declareOp.getOriginalBase(); return Fortran::lower::omp::internal::createMapInfoOp( rewriter, liveIn.getLoc(), rawAddr, /*varPtrPtr=*/{}, declareOp.getUniqName().str(), boundsOps, @@ -737,7 +804,8 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { genTargetOp(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, mlir::IRMapping &mapper, llvm::ArrayRef mappedVars, mlir::omp::TargetOperands &clauseOps, - mlir::omp::LoopNestOperands &loopNestClauseOps) const { + mlir::omp::LoopNestOperands &loopNestClauseOps, + const LiveInShapeInfoMap &liveInShapeInfoMap) const { auto targetOp = rewriter.create(loc, clauseOps); auto argIface = llvm::cast(*targetOp); @@ -753,23 +821,35 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { } rewriter.createBlock(®ion, {}, regionArgTypes, regionArgLocs); + fir::FirOpBuilder builder( + rewriter, + fir::getKindMapping(targetOp->getParentOfType())); - for (auto [arg, mapInfoOp] : - llvm::zip_equal(argIface.getMapBlockArgs(), clauseOps.mapVars)) { + for (auto [arg, mapInfoOp, mappedVar] : llvm::zip_equal( + argIface.getMapBlockArgs(), clauseOps.mapVars, mappedVars)) { auto miOp = mlir::cast(mapInfoOp.getDefiningOp()); - hlfir::DeclareOp liveInDeclare = genLiveInDeclare(rewriter, arg, miOp); - mlir::Value miOperand = miOp.getVariableOperand(0); + hlfir::DeclareOp liveInDeclare = genLiveInDeclare( + builder, targetOp, arg, miOp, liveInShapeInfoMap.at(mappedVar)); - // TODO If `miOperand.getDefiningOp()` is a `fir::BoxAddrOp`, we probably + // TODO If `mappedVar.getDefiningOp()` is a `fir::BoxAddrOp`, we probably // need to "unpack" the box by getting the defining op of it's value. // However, we did not hit this case in reality yet so leaving it as a // todo for now. - mapper.map(miOperand, liveInDeclare.getOriginalBase()); + auto mapHostValueToDevice = [&](mlir::Value hostValue, + mlir::Value deviceValue) { + if (!llvm::isa(hostValue.getType())) + mapper.map(hostValue, + builder.loadIfRef(hostValue.getLoc(), deviceValue)); + else + mapper.map(hostValue, deviceValue); + }; + + mapHostValueToDevice(mappedVar, liveInDeclare.getOriginalBase()); if (auto origDeclareOp = mlir::dyn_cast_if_present( - miOperand.getDefiningOp())) - mapper.map(origDeclareOp.getBase(), liveInDeclare.getBase()); + mappedVar.getDefiningOp())) + mapHostValueToDevice(origDeclareOp.getBase(), liveInDeclare.getBase()); } for (auto [arg, hostEval] : llvm::zip_equal(argIface.getHostEvalBlockArgs(), @@ -785,57 +865,70 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { mapper.lookup(loopNestClauseOps.loopSteps[i]); } - fir::FirOpBuilder firBuilder( - rewriter, - fir::getKindMapping(targetOp->getParentOfType())); - Fortran::lower::omp::internal::cloneOrMapRegionOutsiders(firBuilder, - targetOp); + Fortran::lower::omp::internal::cloneOrMapRegionOutsiders(builder, targetOp); rewriter.setInsertionPoint( rewriter.create(targetOp.getLoc())); return targetOp; } - hlfir::DeclareOp - genLiveInDeclare(mlir::ConversionPatternRewriter &rewriter, - mlir::Value liveInArg, - mlir::omp::MapInfoOp liveInMapInfoOp) const { + hlfir::DeclareOp genLiveInDeclare( + fir::FirOpBuilder &builder, mlir::omp::TargetOp targetOp, + mlir::Value liveInArg, mlir::omp::MapInfoOp liveInMapInfoOp, + const TargetDeclareShapeCreationInfo &targetShapeCreationInfo) const { mlir::Type liveInType = liveInArg.getType(); - + std::string liveInName = liveInMapInfoOp.getName().has_value() + ? liveInMapInfoOp.getName().value().str() + : std::string(""); if (fir::isa_ref_type(liveInType)) liveInType = fir::unwrapRefType(liveInType); mlir::Value shape = [&]() -> mlir::Value { - if (hlfir::isFortranScalarNumericalType(liveInType)) + if (!targetShapeCreationInfo.isShapedValue()) return {}; - if (hlfir::isFortranArrayObject(liveInType)) { - llvm::SmallVector shapeOpOperands; - - for (auto boundsOperand : liveInMapInfoOp.getBounds()) { - auto boundsOp = - mlir::cast(boundsOperand.getDefiningOp()); - mlir::Operation *localExtentDef = - boundsOp.getExtent().getDefiningOp()->clone(); - rewriter.getInsertionBlock()->push_back(localExtentDef); - assert(localExtentDef->getNumResults() == 1); - - shapeOpOperands.push_back(localExtentDef->getResult(0)); + llvm::SmallVector extentOperands; + llvm::SmallVector startIndexOperands; + + if (targetShapeCreationInfo.isShapeShiftedValue()) { + llvm::SmallVector shapeShiftOperands; + + size_t shapeIdx = 0; + for (auto [startIndex, extent] : + llvm::zip_equal(targetShapeCreationInfo.startIndices, + targetShapeCreationInfo.extents)) { + shapeShiftOperands.push_back( + Fortran::lower::omp::internal::mapTemporaryValue( + builder, targetOp, startIndex, + liveInName + ".start_idx.dim" + std::to_string(shapeIdx))); + shapeShiftOperands.push_back( + Fortran::lower::omp::internal::mapTemporaryValue( + builder, targetOp, extent, + liveInName + ".extent.dim" + std::to_string(shapeIdx))); + ++shapeIdx; } - return rewriter.create(liveInArg.getLoc(), - shapeOpOperands); + auto shapeShiftType = fir::ShapeShiftType::get( + builder.getContext(), shapeShiftOperands.size() / 2); + return builder.create( + liveInArg.getLoc(), shapeShiftType, shapeShiftOperands); + } + + llvm::SmallVector shapeOperands; + size_t shapeIdx = 0; + for (auto extent : targetShapeCreationInfo.extents) { + shapeOperands.push_back( + Fortran::lower::omp::internal::mapTemporaryValue( + builder, targetOp, extent, + liveInName + ".extent.dim" + std::to_string(shapeIdx))); + ++shapeIdx; } - std::string opStr; - llvm::raw_string_ostream opOs(opStr); - opOs << "Unsupported type: " << liveInType; - llvm_unreachable(opOs.str().c_str()); + return builder.create(liveInArg.getLoc(), shapeOperands); }(); - return rewriter.create(liveInArg.getLoc(), liveInArg, - liveInMapInfoOp.getName().value(), - shape); + return builder.create(liveInArg.getLoc(), liveInArg, + liveInName, shape); } mlir::omp::TeamsOp diff --git a/flang/test/Transforms/DoConcurrent/basic_device.f90 b/flang/test/Transforms/DoConcurrent/basic_device.f90 index 5b5d1f5ff77c52..46be87003c085f 100644 --- a/flang/test/Transforms/DoConcurrent/basic_device.f90 +++ b/flang/test/Transforms/DoConcurrent/basic_device.f90 @@ -35,7 +35,7 @@ program do_concurrent_basic ! CHECK-DAG: %[[I_MAP_INFO:.*]] = omp.map.info var_ptr(%[[I_ORIG_DECL]]#1 ! CHECK: %[[C0:.*]] = arith.constant 0 : index - ! CHECK: %[[UPPER_BOUND:.*]] = arith.subi %[[A_EXTENT]], %[[C0]] : index + ! CHECK: %[[UPPER_BOUND:.*]] = arith.subi %[[A_EXTENT]], %{{c1.*}} : index ! CHECK: %[[A_BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C0]] : index) ! CHECK-SAME: upper_bound(%[[UPPER_BOUND]] : index) diff --git a/flang/test/Transforms/DoConcurrent/map_shape_info.f90 b/flang/test/Transforms/DoConcurrent/map_shape_info.f90 new file mode 100644 index 00000000000000..4ae95862aa6044 --- /dev/null +++ b/flang/test/Transforms/DoConcurrent/map_shape_info.f90 @@ -0,0 +1,86 @@ + +! Tests mapping of a basic `do concurrent` loop to +! `!$omp target teams distribute parallel do`. + +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fdo-concurrent-parallel=device %s -o - \ +! RUN: | FileCheck %s + +program do_concurrent_shape + implicit none + integer :: a(10, 20) + integer :: i, j + + do concurrent (i=1:10, j=1:20) + a(i, j) = i * j + end do +end program do_concurrent_shape + +! CHECK-LABEL: do_concurrent_shape +! CHECK: fir.store %{{c10.*}} to %[[DIM0_EXT:.*]] : !fir.ref +! CHECK: fir.store %{{c20.*}} to %[[DIM1_EXT:.*]] : !fir.ref + +! CHECK: omp.map.info +! CHECK: omp.map.info +! CHECK: omp.map.info + +! CHECK: %[[DIM0_EXT_MAP:.*]] = omp.map.info +! CHECK-SAME: var_ptr(%[[DIM0_EXT]] : !fir.ref, index) +! CHECK-SAME: map_clauses(implicit, exit_release_or_enter_alloc) +! CHECK-SAME: capture(ByCopy) -> !fir.ref {name = "_QFEa.extent.dim0"} + +! CHECK: %[[DIM1_EXT_MAP:.*]] = omp.map.info +! CHECK-SAME: var_ptr(%[[DIM1_EXT]] : !fir.ref, index) +! CHECK-SAME: map_clauses(implicit, exit_release_or_enter_alloc) +! CHECK-SAME: capture(ByCopy) -> !fir.ref {name = "_QFEa.extent.dim1"} + +! CHECK: omp.target host_eval({{.*}}) map_entries( +! CHECK-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! CHECK-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! CHECK-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! CHECK-SAME: %[[DIM0_EXT_MAP]] -> %[[DIM0_EXT_ARG:[^,]+]], +! CHECK-SAME: %[[DIM1_EXT_MAP]] -> %[[DIM1_EXT_ARG:[^,]+]] : {{.*}}) + +! CHECK-DAG: %[[DIM0_EXT_DEV:.*]] = fir.load %[[DIM0_EXT_ARG]] +! CHECK-DAG: %[[DIM1_EXT_DEV:.*]] = fir.load %[[DIM1_EXT_ARG]] + +! CHECK: %[[SHAPE:.*]] = fir.shape %[[DIM0_EXT_DEV]], %[[DIM1_EXT_DEV]] +! CHECK: %{{.*}}:2 = hlfir.declare %{{.*}}(%[[SHAPE]]) {uniq_name = "_QFEa"} + +subroutine do_concurrent_shape_shift + implicit none + integer :: a(2:10) + integer :: i + + do concurrent (i=1:10) + a(i) = i + end do +end subroutine do_concurrent_shape_shift + +! CHECK: fir.store %{{c2.*}} to %[[DIM0_STRT:.*]] : !fir.ref +! CHECK: fir.store %{{c9.*}} to %[[DIM0_EXT:.*]] : !fir.ref + +! CHECK: omp.map.info +! CHECK: omp.map.info + +! CHECK: %[[DIM0_STRT_MAP:.*]] = omp.map.info +! CHECK-SAME: var_ptr(%[[DIM0_STRT]] : !fir.ref, index) +! CHECK-SAME: map_clauses(implicit, exit_release_or_enter_alloc) +! CHECK-SAME: capture(ByCopy) -> !fir.ref {name = "_QF{{.*}}Ea.start_idx.dim0"} + +! CHECK: %[[DIM0_EXT_MAP:.*]] = omp.map.info +! CHECK-SAME: var_ptr(%[[DIM0_EXT]] : !fir.ref, index) +! CHECK-SAME: map_clauses(implicit, exit_release_or_enter_alloc) +! CHECK-SAME: capture(ByCopy) -> !fir.ref {name = "_QF{{.*}}Ea.extent.dim0"} + +! CHECK: omp.target host_eval({{.*}}) map_entries( +! CHECK-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! CHECK-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! CHECK-SAME: %[[DIM0_STRT_MAP]] -> %[[DIM0_STRT_ARG:[^,]+]], +! CHECK-SAME: %[[DIM0_EXT_MAP]] -> %[[DIM0_EXT_ARG:[^,]+]] : {{.*}}) + +! CHECK-DAG: %[[DIM0_STRT_DEV:.*]] = fir.load %[[DIM0_STRT_ARG]] +! CHECK-DAG: %[[DIM0_EXT_DEV:.*]] = fir.load %[[DIM0_EXT_ARG]] + +! CHECK: %[[SHAPE_SHIFT:.*]] = fir.shape_shift %[[DIM0_STRT_DEV]], %[[DIM0_EXT_DEV]] +! CHECK: %{{.*}}:2 = hlfir.declare %{{.*}}(%[[SHAPE_SHIFT]]) {uniq_name = "_QF{{.*}}Ea"} + diff --git a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 index 14d5c2070d3022..5bc713e6509a71 100644 --- a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 +++ b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 @@ -33,8 +33,11 @@ program main ! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[X_ARG:[^,]+]], ! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[J_ARG:[^,]+]], ! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[K_ARG:[^,]+]], -! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[A_ARG:[^:]+]]: -! DEVICE-SAME: !fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref>) { +! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[A_ARG:[^,]+]], +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^:]+}} : +! DEVICE-SAME: {{.*}}) { ! DEVICE: %[[TARGET_J_DECL:.*]]:2 = hlfir.declare %[[J_ARG]] {uniq_name = "_QFEj"} ! DEVICE: %[[TARGET_K_DECL:.*]]:2 = hlfir.declare %[[K_ARG]] {uniq_name = "_QFEk"} diff --git a/flang/test/Transforms/DoConcurrent/runtime_sized_array.f90 b/flang/test/Transforms/DoConcurrent/runtime_sized_array.f90 index 5420ff4586be60..80815059878295 100644 --- a/flang/test/Transforms/DoConcurrent/runtime_sized_array.f90 +++ b/flang/test/Transforms/DoConcurrent/runtime_sized_array.f90 @@ -19,11 +19,10 @@ subroutine foo(n) ! CHECK-DAG: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFfooEi"} ! CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFfooEa"} -! CHECK-DAG: %[[N_ALLOC:.*]] = fir.alloca i32 -! CHECK-DAG: %[[I_MAP:.*]] = omp.map.info var_ptr(%[[I_DECL]]#1 : {{.*}}) -! CHECK-DAG: %[[A_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#1 : {{.*}}) -! CHECK-DAG: %[[N_MAP:.*]] = omp.map.info var_ptr(%[[N_ALLOC]] : {{.*}}) +! CHECK-DAG: %[[I_MAP:.*]] = omp.map.info var_ptr(%[[I_DECL]]#1 : {{.*}}) {{.*}} {name = "_QFfooEi"} +! CHECK-DAG: %[[A_MAP:.*]] = omp.map.info var_ptr(%[[A_DECL]]#1 : {{.*}}) {{.*}} {name = "_QFfooEa"} +! CHECK-DAG: %[[N_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}) {{.*}} {name = "_QFfooEa.extent.dim0"} ! CHECK: omp.target ! CHECK-SAME: map_entries(%[[I_MAP]] -> %[[I_ARG:arg[0-9]*]], diff --git a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 index b1e921f71bd410..7b04fe37786141 100644 --- a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 +++ b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 @@ -32,8 +32,11 @@ program main ! DEVICE: omp.target {{.*}}map_entries(%{{[^[:space:]]+}} -> %[[I_ARG:[^,]+]], ! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[J_ARG:[^,]+]], ! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[K_ARG:[^,]+]], -! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[A_ARG:[^:]+]]: -! DEVICE-SAME: !fir.ref, !fir.ref, !fir.ref, !fir.ref>) { +! DEVICE-SAME: %{{[^[:space:]]+}} -> %[[A_ARG:[^,]+]], +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^,]+}}, +! DEVICE-SAME: %{{[^[:space:]]+}} -> %{{[^:]+}} : +! DEVICE-SAME: {{.*}}) { ! DEVICE: %[[TARGET_J_DECL:.*]]:2 = hlfir.declare %[[J_ARG]] {uniq_name = "_QFEj"} ! DEVICE: %[[TARGET_K_DECL:.*]]:2 = hlfir.declare %[[K_ARG]] {uniq_name = "_QFEk"}