diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index 09f7b892f1ecb..b772c523caba4 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -215,6 +215,11 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { llvm::ArrayRef lenParams, bool asTarget = false); + /// Create a two dimensional ArrayAttr containing integer data as + /// IntegerAttrs, effectively: ArrayAttr>>. + mlir::ArrayAttr create2DI64ArrayAttr( + llvm::SmallVectorImpl> &intData); + /// Create a temporary using `fir.alloca`. This function does not hoist. /// It is the callers responsibility to set the insertion point if /// hoisting is required. diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index a4d2524bccf5c..209e79e518263 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -889,16 +889,17 @@ void ClauseProcessor::processMapObjects( lower::StatementContext &stmtCtx, mlir::Location clauseLocation, const omp::ObjectList &objects, llvm::omp::OpenMPOffloadMappingFlags mapTypeBits, - std::map> &parentMemberIndices, + std::map &parentMemberIndices, llvm::SmallVectorImpl &mapVars, llvm::SmallVectorImpl *mapSyms, llvm::SmallVectorImpl *mapSymLocs, llvm::SmallVectorImpl *mapSymTypes) const { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + for (const omp::Object &object : objects) { llvm::SmallVector bounds; std::stringstream asFortran; + std::optional parentObj; lower::AddrAndBoundsInfo info = lower::gatherDataOperandAddrAndBoundsowner().IsDerivedType()) { + omp::ObjectList objectList = gatherObjects(object, semaCtx); + assert(!objectList.empty() && + "could not find parent objects of derived type member"); + parentObj = objectList[0]; + parentMemberIndices.emplace(parentObj.value(), + OmpMapParentAndMemberData{}); + + if (isMemberOrParentAllocatableOrPointer(object, semaCtx)) { + llvm::SmallVector indices; + generateMemberPlacementIndices(object, indices, semaCtx); + baseOp = createParentSymAndGenIntermediateMaps( + clauseLocation, converter, semaCtx, stmtCtx, objectList, indices, + parentMemberIndices[parentObj.value()], asFortran.str(), + mapTypeBits); + } + } + // Explicit map captures are captured ByRef by default, // optimisation passes may alter this to ByCopy or other capture // types to optimise - mlir::Value baseOp = info.rawInput; auto location = mlir::NameLoc::get( mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()), baseOp.getLoc()); mlir::omp::MapInfoOp mapOp = createMapInfoOp( firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds, - /*members=*/{}, /*membersIndex=*/mlir::DenseIntElementsAttr{}, + /*members=*/{}, /*membersIndex=*/mlir::ArrayAttr{}, static_cast< std::underlying_type_t>( mapTypeBits), mlir::omp::VariableCaptureKind::ByRef, baseOp.getType()); - if (object.sym()->owner().IsDerivedType()) { - addChildIndexAndMapToParent(object, parentMemberIndices, mapOp, semaCtx); + if (parentObj.has_value()) { + addChildIndexAndMapToParent( + object, parentMemberIndices[parentObj.value()], mapOp, semaCtx); } else { mapVars.push_back(mapOp); - if (mapSyms) - mapSyms->push_back(object.sym()); + mapSyms->push_back(object.sym()); if (mapSymTypes) mapSymTypes->push_back(baseOp.getType()); if (mapSymLocs) @@ -949,9 +968,7 @@ bool ClauseProcessor::processMap( llvm::SmallVector localMapSyms; llvm::SmallVectorImpl *ptrMapSyms = mapSyms ? mapSyms : &localMapSyms; - std::map> - parentMemberIndices; + std::map parentMemberIndices; bool clauseFound = findRepeatableClause( [&](const omp::clause::Map &clause, const parser::CharBlock &source) { @@ -1003,17 +1020,15 @@ bool ClauseProcessor::processMap( mapSymLocs, mapSymTypes); }); - insertChildMapInfoIntoParent(converter, parentMemberIndices, result.mapVars, - *ptrMapSyms, mapSymTypes, mapSymLocs); - + insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, + result.mapVars, mapSymTypes, mapSymLocs, + ptrMapSyms); return clauseFound; } bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx, mlir::omp::MapClauseOps &result) { - std::map> - parentMemberIndices; + std::map parentMemberIndices; llvm::SmallVector mapSymbols; auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) { @@ -1034,9 +1049,9 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx, clauseFound = findRepeatableClause(callbackFn) || clauseFound; - insertChildMapInfoIntoParent(converter, parentMemberIndices, result.mapVars, - mapSymbols, - /*mapSymTypes=*/nullptr, /*mapSymLocs=*/nullptr); + insertChildMapInfoIntoParent( + converter, semaCtx, stmtCtx, parentMemberIndices, result.mapVars, + /*mapSymTypes=*/nullptr, /*mapSymLocs=*/nullptr, &mapSymbols); return clauseFound; } @@ -1110,9 +1125,7 @@ bool ClauseProcessor::processUseDeviceAddr( llvm::SmallVectorImpl &useDeviceTypes, llvm::SmallVectorImpl &useDeviceLocs, llvm::SmallVectorImpl &useDeviceSyms) const { - std::map> - parentMemberIndices; + std::map parentMemberIndices; bool clauseFound = findRepeatableClause( [&](const omp::clause::UseDeviceAddr &clause, const parser::CharBlock &source) { @@ -1125,9 +1138,9 @@ bool ClauseProcessor::processUseDeviceAddr( &useDeviceSyms, &useDeviceLocs, &useDeviceTypes); }); - insertChildMapInfoIntoParent(converter, parentMemberIndices, - result.useDeviceAddrVars, useDeviceSyms, - &useDeviceTypes, &useDeviceLocs); + insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, + result.useDeviceAddrVars, &useDeviceTypes, + &useDeviceLocs, &useDeviceSyms); return clauseFound; } @@ -1136,9 +1149,8 @@ bool ClauseProcessor::processUseDevicePtr( llvm::SmallVectorImpl &useDeviceTypes, llvm::SmallVectorImpl &useDeviceLocs, llvm::SmallVectorImpl &useDeviceSyms) const { - std::map> - parentMemberIndices; + std::map parentMemberIndices; + bool clauseFound = findRepeatableClause( [&](const omp::clause::UseDevicePtr &clause, const parser::CharBlock &source) { @@ -1151,9 +1163,9 @@ bool ClauseProcessor::processUseDevicePtr( &useDeviceSyms, &useDeviceLocs, &useDeviceTypes); }); - insertChildMapInfoIntoParent(converter, parentMemberIndices, - result.useDevicePtrVars, useDeviceSyms, - &useDeviceTypes, &useDeviceLocs); + insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, + result.useDevicePtrVars, &useDeviceTypes, + &useDeviceLocs, &useDeviceSyms); return clauseFound; } diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h index 0c8e7bd47ab5a..0f6f0c9863582 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.h +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h @@ -178,8 +178,7 @@ class ClauseProcessor { lower::StatementContext &stmtCtx, mlir::Location clauseLocation, const omp::ObjectList &objects, llvm::omp::OpenMPOffloadMappingFlags mapTypeBits, - std::map> &parentMemberIndices, + std::map &parentMemberIndices, llvm::SmallVectorImpl &mapVars, llvm::SmallVectorImpl *mapSyms, llvm::SmallVectorImpl *mapSymLocs = nullptr, diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h index 51bf0eab0f8d0..34639673a1bd5 100644 --- a/flang/lib/Lower/OpenMP/Clauses.h +++ b/flang/lib/Lower/OpenMP/Clauses.h @@ -55,6 +55,13 @@ struct IdTyTemplate { return designator == other.designator; } + // Defining an "ordering" which allows types derived from this to be + // utilised in maps and other containers that require comparison + // operators for ordering + bool operator<(const IdTyTemplate &other) const { + return symbol < other.symbol; + } + operator bool() const { return symbol != nullptr; } }; @@ -76,6 +83,10 @@ struct ObjectT, Fortran::semantics::Symbol *sym() const { return identity.symbol; } const std::optional &ref() const { return identity.designator; } + bool operator<(const ObjectT &other) const { + return identity < other.identity; + } + IdTy identity; }; } // namespace tomp::type diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 8195f4a897a90..a1a6d8816e4bc 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -935,7 +935,7 @@ static void genBodyOfTargetOp( firOpBuilder, copyVal.getLoc(), copyVal, /*varPtrPtr=*/mlir::Value{}, name.str(), bounds, /*members=*/llvm::SmallVector{}, - /*membersIndex=*/mlir::DenseIntElementsAttr{}, + /*membersIndex=*/mlir::ArrayAttr{}, static_cast< std::underlying_type_t>( llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT), @@ -1792,7 +1792,7 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, mlir::Value mapOp = createMapInfoOp( firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{}, name.str(), bounds, /*members=*/{}, - /*membersIndex=*/mlir::DenseIntElementsAttr{}, + /*membersIndex=*/mlir::ArrayAttr{}, static_cast< std::underlying_type_t>( mapFlag), diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp index 47bc12e1b8a03..2e25f374934b9 100644 --- a/flang/lib/Lower/OpenMP/Utils.cpp +++ b/flang/lib/Lower/OpenMP/Utils.cpp @@ -13,9 +13,15 @@ #include "Utils.h" #include "Clauses.h" +#include + +#include #include +#include #include #include +#include +#include #include #include #include @@ -23,9 +29,6 @@ #include #include -#include -#include - llvm::cl::opt treatIndexAsSection( "openmp-treat-index-as-section", llvm::cl::desc("In the OpenMP data clauses treat `a(N)` as `a(N:N)`."), @@ -117,14 +120,12 @@ void gatherFuncAndVarSyms( symbolAndClause.emplace_back(clause, *object.sym()); } -mlir::omp::MapInfoOp -createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc, - mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name, - llvm::ArrayRef bounds, - llvm::ArrayRef members, - mlir::DenseIntElementsAttr membersIndex, uint64_t mapType, - mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy, - bool partialMap) { +mlir::omp::MapInfoOp createMapInfoOp( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value baseAddr, + mlir::Value varPtrPtr, std::string name, mlir::ArrayRef bounds, + mlir::ArrayRef members, mlir::ArrayAttr membersIndex, + uint64_t mapType, mlir::omp::VariableCaptureKind mapCaptureType, + mlir::Type retTy, bool partialMap) { if (auto boxTy = llvm::dyn_cast(baseAddr.getType())) { baseAddr = builder.create(loc, baseAddr); retTy = baseAddr.getType(); @@ -145,11 +146,174 @@ createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc, builder.getIntegerAttr(builder.getIntegerType(64, false), mapType), builder.getAttr(mapCaptureType), builder.getStringAttr(name), builder.getBoolAttr(partialMap)); - return op; } -static int +omp::ObjectList gatherObjects(omp::Object obj, + semantics::SemanticsContext &semaCtx) { + omp::ObjectList objList; + std::optional baseObj = obj; + while (baseObj.has_value()) { + objList.push_back(baseObj.value()); + baseObj = getBaseObject(baseObj.value(), semaCtx); + } + return omp::ObjectList{llvm::reverse(objList)}; +} + +bool isDuplicateMemberMapInfo(OmpMapParentAndMemberData &parentMembers, + llvm::SmallVectorImpl &memberIndices) { + for (auto memberData : parentMembers.memberPlacementIndices) + if (std::equal(memberIndices.begin(), memberIndices.end(), + memberData.begin())) + return true; + return false; +} + +static void generateArrayIndices(lower::AbstractConverter &converter, + fir::FirOpBuilder &firOpBuilder, + lower::StatementContext &stmtCtx, + mlir::Location clauseLocation, + llvm::SmallVectorImpl &indices, + omp::Object object) { + if (auto maybeRef = evaluate::ExtractDataRef(*object.ref())) { + evaluate::DataRef ref = *maybeRef; + if (auto *arr = std::get_if(&ref.u)) { + for (auto v : arr->subscript()) { + if (std::holds_alternative(v.u)) { + llvm_unreachable("Triplet indexing in map clause is unsupported"); + } else { + auto expr = + std::get(v.u); + mlir::Value subscript = fir::getBase( + converter.genExprValue(toEvExpr(expr.value()), stmtCtx)); + mlir::Value one = firOpBuilder.createIntegerConstant( + clauseLocation, firOpBuilder.getIndexType(), 1); + subscript = firOpBuilder.createConvert( + clauseLocation, firOpBuilder.getIndexType(), subscript); + indices.push_back(firOpBuilder.create( + clauseLocation, subscript, one)); + } + } + } + } +} + +// When mapping members of derived types, there is a chance that one of the +// members along the way to a mapped member is an descriptor. In which case +// we have to make sure we generate a map for those along the way otherwise +// we will be missing a chunk of data required to actually map the member +// type to device. This function effectively generates these maps and the +// appropriate data accesses required to generate these maps. It will avoid +// creating duplicate maps, as duplicates are just as bad as unmapped +// descriptor data in a lot of cases for the runtime (and unnecessary +// data movement should be avoided where possible) +mlir::Value createParentSymAndGenIntermediateMaps( + mlir::Location clauseLocation, lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, lower::StatementContext &stmtCtx, + omp::ObjectList &objectList, llvm::SmallVector &indices, + OmpMapParentAndMemberData &parentMemberIndices, std::string asFortran, + llvm::omp::OpenMPOffloadMappingFlags mapTypeBits) { + + auto arrayExprWithSubscript = [](omp::Object obj) { + if (auto maybeRef = evaluate::ExtractDataRef(*obj.ref())) { + evaluate::DataRef ref = *maybeRef; + if (auto *arr = std::get_if(&ref.u)) + return !arr->subscript().empty(); + } + return false; + }; + + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + lower::AddrAndBoundsInfo parentBaseAddr = lower::getDataOperandBaseAddr( + converter, firOpBuilder, *objectList[0].sym(), clauseLocation); + mlir::Value curValue = parentBaseAddr.addr; + + // Iterate over all objects in the objectList, this should consist of all + // record types between the parent and the member being mapped (including + // the parent). The object list may also contain array objects as well, + // this can occur when specifying bounds or a specific element access + // within a member map, we skip these. + size_t currentIndex = 0; + for (size_t i = 0; i < objectList.size(); ++i) { + if (fir::SequenceType arrType = mlir::dyn_cast( + fir::unwrapPassByRefType(curValue.getType()))) { + if (arrayExprWithSubscript(objectList[i])) { + llvm::SmallVector indices; + generateArrayIndices(converter, firOpBuilder, stmtCtx, clauseLocation, + indices, objectList[i]); + assert(!indices.empty() && "missing expected indices for map clause"); + curValue = firOpBuilder.create( + clauseLocation, firOpBuilder.getRefType(arrType.getEleTy()), + curValue, indices); + } + } + + if (fir::RecordType recordType = mlir::dyn_cast( + fir::unwrapPassByRefType(curValue.getType()))) { + mlir::Value idxConst = firOpBuilder.createIntegerConstant( + clauseLocation, firOpBuilder.getIndexType(), indices[currentIndex]); + mlir::Type memberTy = + recordType.getTypeList().at(indices[currentIndex]).second; + curValue = firOpBuilder.create( + clauseLocation, firOpBuilder.getRefType(memberTy), curValue, + idxConst); + + if ((currentIndex == indices.size() - 1) || + !fir::isTypeWithDescriptor(memberTy)) { + currentIndex++; + continue; + } + + llvm::SmallVector interimIndices( + indices.begin(), std::next(indices.begin(), currentIndex + 1)); + if (!isDuplicateMemberMapInfo(parentMemberIndices, interimIndices)) { + // Generate initial bounds operations using the standard lowering + // utility + llvm::SmallVector intermBounds; + if (i + 1 < objectList.size() && + objectList[i + 1].sym()->IsObjectArray()) { + std::stringstream intermFortran; + Fortran::lower::gatherDataOperandAddrAndBounds< + mlir::omp::MapBoundsOp, mlir::omp::MapBoundsType>( + converter, converter.getFirOpBuilder(), semaCtx, + converter.getFctCtx(), *objectList[i + 1].sym(), + objectList[i + 1].ref(), clauseLocation, intermFortran, + intermBounds, treatIndexAsSection); + } + + llvm::omp::OpenMPOffloadMappingFlags intermMapType = mapTypeBits; + // remove all map TO, FROM and TOFROM bits, from the intermediate + // allocatable maps, we simply wish to alloc or release them. It may be + // safer to just pass OMP_MAP_NONE as the map type, but we may still + // need some of the other map types the mapped member utilises, so for + // now it's good to keep an eye on this. + intermMapType &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO; + intermMapType &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; + + mlir::omp::MapInfoOp mapOp = createMapInfoOp( + firOpBuilder, clauseLocation, curValue, + /*varPtrPtr=*/mlir::Value{}, asFortran, + /*bounds=*/intermBounds, + /*members=*/{}, + /*membersIndex=*/mlir::ArrayAttr{}, + static_cast< + std::underlying_type_t>( + intermMapType), + mlir::omp::VariableCaptureKind::ByRef, curValue.getType()); + + parentMemberIndices.memberPlacementIndices.push_back(interimIndices); + parentMemberIndices.memberMap.push_back(mapOp); + } + + curValue = firOpBuilder.create(clauseLocation, curValue); + currentIndex++; + } + } + + return curValue; +} + +static int64_t getComponentPlacementInParent(const semantics::Symbol *componentSym) { const auto *derived = componentSym->owner() .derivedTypeSpec() @@ -183,99 +347,69 @@ getComponentObject(std::optional object, return getComponentObject(baseObj.value(), semaCtx); } -static void -generateMemberPlacementIndices(const Object &object, - llvm::SmallVectorImpl &indices, - semantics::SemanticsContext &semaCtx) { +void generateMemberPlacementIndices(const Object &object, + llvm::SmallVectorImpl &indices, + semantics::SemanticsContext &semaCtx) { + indices.clear(); auto compObj = getComponentObject(object, semaCtx); + while (compObj) { - indices.push_back(getComponentPlacementInParent(compObj->sym())); + int64_t index = getComponentPlacementInParent(compObj->sym()); + assert(index >= 0); + indices.push_back(index); compObj = getComponentObject(getBaseObject(compObj.value(), semaCtx), semaCtx); } - indices = llvm::SmallVector{llvm::reverse(indices)}; + indices = llvm::SmallVector{llvm::reverse(indices)}; } -void addChildIndexAndMapToParent( - const omp::Object &object, - std::map> &parentMemberIndices, - mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx) { - std::optional dataRef = ExtractDataRef(object.ref()); - assert(dataRef.has_value() && - "DataRef could not be extracted during mapping of derived type " - "cannot proceed"); - const semantics::Symbol *parentSym = &dataRef->GetFirstSymbol(); - assert(parentSym && "Could not find parent symbol during lower of " - "a component member in OpenMP map clause"); - llvm::SmallVector indices; +void addChildIndexAndMapToParent(const omp::Object &object, + OmpMapParentAndMemberData &parentMemberIndices, + mlir::omp::MapInfoOp &mapOp, + semantics::SemanticsContext &semaCtx) { + llvm::SmallVector indices; generateMemberPlacementIndices(object, indices, semaCtx); - parentMemberIndices[parentSym].push_back({indices, mapOp}); + parentMemberIndices.memberPlacementIndices.push_back(indices); + parentMemberIndices.memberMap.push_back(mapOp); } -static void calculateShapeAndFillIndices( - llvm::SmallVectorImpl &shape, - llvm::SmallVectorImpl &memberPlacementData) { - shape.push_back(memberPlacementData.size()); - size_t largestIndicesSize = - std::max_element(memberPlacementData.begin(), memberPlacementData.end(), - [](auto a, auto b) { - return a.memberPlacementIndices.size() < - b.memberPlacementIndices.size(); - }) - ->memberPlacementIndices.size(); - shape.push_back(largestIndicesSize); - - // DenseElementsAttr expects a rectangular shape for the data, so all - // index lists have to be of the same length, this emplaces -1 as filler. - for (auto &v : memberPlacementData) { - if (v.memberPlacementIndices.size() < largestIndicesSize) { - auto *prevEnd = v.memberPlacementIndices.end(); - v.memberPlacementIndices.resize(largestIndicesSize); - std::fill(prevEnd, v.memberPlacementIndices.end(), -1); - } +bool isMemberOrParentAllocatableOrPointer( + const Object &object, semantics::SemanticsContext &semaCtx) { + if (semantics::IsAllocatableOrObjectPointer(object.sym())) + return true; + + auto compObj = getBaseObject(object, semaCtx); + while (compObj) { + if (compObj.has_value() && + semantics::IsAllocatableOrObjectPointer(compObj.value().sym())) + return true; + compObj = getBaseObject(compObj.value(), semaCtx); } -} -static mlir::DenseIntElementsAttr createDenseElementsAttrFromIndices( - llvm::SmallVectorImpl &memberPlacementData, - fir::FirOpBuilder &builder) { - llvm::SmallVector shape; - calculateShapeAndFillIndices(shape, memberPlacementData); - - llvm::SmallVector indicesFlattened = - std::accumulate(memberPlacementData.begin(), memberPlacementData.end(), - llvm::SmallVector(), - [](llvm::SmallVector &x, OmpMapMemberIndicesData y) { - x.insert(x.end(), y.memberPlacementIndices.begin(), - y.memberPlacementIndices.end()); - return x; - }); - - return mlir::DenseIntElementsAttr::get( - mlir::VectorType::get(shape, - mlir::IntegerType::get(builder.getContext(), 32)), - indicesFlattened); + return false; } void insertChildMapInfoIntoParent( - lower::AbstractConverter &converter, - std::map> &parentMemberIndices, + lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, + lower::StatementContext &stmtCtx, + std::map &parentMemberIndices, llvm::SmallVectorImpl &mapOperands, - llvm::SmallVectorImpl &mapSyms, llvm::SmallVectorImpl *mapSymTypes, - llvm::SmallVectorImpl *mapSymLocs) { + llvm::SmallVectorImpl *mapSymLocs, + llvm::SmallVectorImpl *mapSymbols) { + + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + for (auto indices : parentMemberIndices) { bool parentExists = false; size_t parentIdx; - for (parentIdx = 0; parentIdx < mapSyms.size(); ++parentIdx) { - if (mapSyms[parentIdx] == indices.first) { + + for (parentIdx = 0; parentIdx < mapSymbols->size(); ++parentIdx) + if ((*mapSymbols)[parentIdx] == indices.first.sym()) { parentExists = true; break; } - } if (parentExists) { auto mapOp = llvm::cast( @@ -287,76 +421,60 @@ void insertChildMapInfoIntoParent( // has defined a series of parent and children maps where the parent // precedes the children. An alternative, may be to do // delayed generation of map info operations from the clauses and - // organize them first before generation. - mapOp->moveAfter(indices.second.back().memberMap); + // organize them first before generation. Or to use the + // topologicalSort utility which will enforce a stronger SSA + // dominance ordering at the cost of efficiency/time. + mapOp->moveAfter(indices.second.memberMap.back()); - for (auto memberIndicesData : indices.second) - mapOp.getMembersMutable().append( - memberIndicesData.memberMap.getResult()); + for (mlir::omp::MapInfoOp memberMap : indices.second.memberMap) + mapOp.getMembersMutable().append(memberMap.getResult()); - mapOp.setMembersIndexAttr(createDenseElementsAttrFromIndices( - indices.second, converter.getFirOpBuilder())); + mapOp.setMembersIndexAttr(firOpBuilder.create2DI64ArrayAttr( + indices.second.memberPlacementIndices)); } else { // NOTE: We take the map type of the first child, this may not // be the correct thing to do, however, we shall see. For the moment // it allows this to work with enter and exit without causing MLIR // verification issues. The more appropriate thing may be to take // the "main" map type clause from the directive being used. - uint64_t mapType = indices.second[0].memberMap.getMapType().value_or(0); - - // create parent to emplace and bind members - mlir::Value origSymbol = converter.getSymbolAddress(*indices.first); + uint64_t mapType = indices.second.memberMap[0].getMapType().value_or(0); llvm::SmallVector members; - for (OmpMapMemberIndicesData memberIndicesData : indices.second) - members.push_back((mlir::Value)memberIndicesData.memberMap); - - mlir::Value mapOp = createMapInfoOp( - converter.getFirOpBuilder(), origSymbol.getLoc(), origSymbol, - /*varPtrPtr=*/mlir::Value(), indices.first->name().ToString(), - /*bounds=*/{}, members, - createDenseElementsAttrFromIndices(indices.second, - converter.getFirOpBuilder()), - mapType, mlir::omp::VariableCaptureKind::ByRef, origSymbol.getType(), + for (mlir::omp::MapInfoOp memberMap : indices.second.memberMap) + members.push_back(memberMap.getResult()); + + // Create parent to emplace and bind members + llvm::SmallVector bounds; + std::stringstream asFortran; + lower::AddrAndBoundsInfo info = + lower::gatherDataOperandAddrAndBounds( + converter, firOpBuilder, semaCtx, converter.getFctCtx(), + *indices.first.sym(), indices.first.ref(), + converter.getCurrentLocation(), asFortran, bounds, + treatIndexAsSection); + + mlir::omp::MapInfoOp mapOp = createMapInfoOp( + firOpBuilder, info.rawInput.getLoc(), info.rawInput, + /*varPtrPtr=*/mlir::Value(), asFortran.str(), bounds, members, + firOpBuilder.create2DI64ArrayAttr( + indices.second.memberPlacementIndices), + mapType, mlir::omp::VariableCaptureKind::ByRef, + info.rawInput.getType(), /*partialMap=*/true); mapOperands.push_back(mapOp); - mapSyms.push_back(indices.first); if (mapSymTypes) mapSymTypes->push_back(mapOp.getType()); if (mapSymLocs) mapSymLocs->push_back(mapOp.getLoc()); + if (mapSymbols) + mapSymbols->push_back(indices.first.sym()); } } } -semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject) { - semantics::Symbol *sym = nullptr; - Fortran::common::visit( - common::visitors{ - [&](const parser::Designator &designator) { - if (auto *arrayEle = - parser::Unwrap(designator)) { - // Use getLastName to retrieve the arrays symbol, this will - // provide the farthest right symbol (the last) in a designator, - // i.e. providing something like the following: - // "dtype1%dtype2%array[2:10]", will result in "array" - sym = GetLastName(arrayEle->base).symbol; - } else if (auto *structComp = - parser::Unwrap( - designator)) { - sym = structComp->component.symbol; - } else if (const parser::Name *name = - semantics::getDesignatorNameIfDataRef(designator)) { - sym = name->symbol; - } - }, - [&](const parser::Name &name) { sym = name.symbol; }}, - ompObject.u); - return sym; -} - void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp, mlir::Location loc) { using Lastprivate = omp::clause::Lastprivate; diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h index 658d062e67b27..b97fe832298d4 100644 --- a/flang/lib/Lower/OpenMP/Utils.h +++ b/flang/lib/Lower/OpenMP/Utils.h @@ -14,6 +14,7 @@ #include "mlir/IR/Location.h" #include "mlir/IR/Value.h" #include "llvm/Support/CommandLine.h" +#include extern llvm::cl::opt treatIndexAsSection; extern llvm::cl::opt enableDelayedPrivatization; @@ -34,6 +35,7 @@ struct OmpObjectList; } // namespace parser namespace lower { +class StatementContext; namespace pft { struct Evaluation; } @@ -49,38 +51,95 @@ using DeclareTargetCapturePair = // and index data when lowering OpenMP map clauses. Keeps track of the // placement of the component in the derived type hierarchy it rests within, // alongside the generated mlir::omp::MapInfoOp for the mapped component. -struct OmpMapMemberIndicesData { +// +// As an example of what the contents of this data structure may be like, +// when provided the following derived type and map of that type: +// +// type :: bottom_layer +// real(8) :: i2 +// real(4) :: array_i2(10) +// real(4) :: array_j2(10) +// end type bottom_layer +// +// type :: top_layer +// real(4) :: i +// integer(4) :: array_i(10) +// real(4) :: j +// type(bottom_layer) :: nested +// integer, allocatable :: array_j(:) +// integer(4) :: k +// end type top_layer +// +// type(top_layer) :: top_dtype +// +// map(tofrom: top_dtype%nested%i2, top_dtype%k, top_dtype%nested%array_i2) +// +// We would end up with an OmpMapParentAndMemberData populated like below: +// +// memberPlacementIndices: +// Vector 1: 3, 0 +// Vector 2: 5 +// Vector 3: 3, 1 +// +// memberMap: +// Entry 1: omp.map.info for "top_dtype%nested%i2" +// Entry 2: omp.map.info for "top_dtype%k" +// Entry 3: omp.map.info for "top_dtype%nested%array_i2" +// +// And this OmpMapParentAndMemberData would be accessed via the parent +// symbol for top_dtype. Other parent derived type instances that have +// members mapped would have there own OmpMapParentAndMemberData entry +// accessed via their own symbol. +struct OmpMapParentAndMemberData { // The indices representing the component members placement in its derived // type parents hierarchy. - llvm::SmallVector memberPlacementIndices; + llvm::SmallVector> memberPlacementIndices; // Placement of the member in the member vector. - mlir::omp::MapInfoOp memberMap; + llvm::SmallVector memberMap; }; -mlir::omp::MapInfoOp -createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc, - mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name, - mlir::ArrayRef bounds, - mlir::ArrayRef members, - mlir::DenseIntElementsAttr membersIndex, uint64_t mapType, - mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy, - bool partialMap = false); - -void addChildIndexAndMapToParent( - const omp::Object &object, - std::map> &parentMemberIndices, - mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx); +mlir::omp::MapInfoOp createMapInfoOp( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value baseAddr, + mlir::Value varPtrPtr, std::string name, mlir::ArrayRef bounds, + mlir::ArrayRef members, mlir::ArrayAttr membersIndex, + uint64_t mapType, mlir::omp::VariableCaptureKind mapCaptureType, + mlir::Type retTy, bool partialMap = false); + +void addChildIndexAndMapToParent(const omp::Object &object, + OmpMapParentAndMemberData &parentMemberIndices, + mlir::omp::MapInfoOp &mapOp, + semantics::SemanticsContext &semaCtx); void insertChildMapInfoIntoParent( - lower::AbstractConverter &converter, - std::map> &parentMemberIndices, + Fortran::lower::AbstractConverter &converter, + Fortran::semantics::SemanticsContext &semaCtx, + Fortran::lower::StatementContext &stmtCtx, + std::map &parentMemberIndices, llvm::SmallVectorImpl &mapOperands, - llvm::SmallVectorImpl &mapSyms, llvm::SmallVectorImpl *mapSymTypes, - llvm::SmallVectorImpl *mapSymLocs); + llvm::SmallVectorImpl *mapSymLocs, + llvm::SmallVectorImpl *mapSyms); + +void generateMemberPlacementIndices( + const Object &object, llvm::SmallVectorImpl &indices, + Fortran::semantics::SemanticsContext &semaCtx); + +bool isMemberOrParentAllocatableOrPointer( + const Object &object, Fortran::semantics::SemanticsContext &semaCtx); + +bool isDuplicateMemberMapInfo(OmpMapParentAndMemberData &parentMembers, + llvm::SmallVectorImpl &memberIndices); + +mlir::Value createParentSymAndGenIntermediateMaps( + mlir::Location clauseLocation, Fortran::lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, lower::StatementContext &stmtCtx, + omp::ObjectList &objectList, llvm::SmallVector &indices, + OmpMapParentAndMemberData &parentMemberIndices, std::string asFortran, + llvm::omp::OpenMPOffloadMappingFlags mapTypeBits); + +omp::ObjectList gatherObjects(omp::Object obj, + semantics::SemanticsContext &semaCtx); mlir::Type getLoopVarType(lower::AbstractConverter &converter, std::size_t loopVarTypeSize); @@ -94,8 +153,6 @@ void gatherFuncAndVarSyms( int64_t getCollapseValue(const List &clauses); -semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject); - void genObjectList(const ObjectList &objects, lower::AbstractConverter &converter, llvm::SmallVectorImpl &operands); diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 9ad37c8df434a..bb13022014fe3 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -267,6 +267,26 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() { return getEntryBlock(); } +static mlir::ArrayAttr makeI64ArrayAttr(llvm::ArrayRef values, + mlir::MLIRContext *context) { + llvm::SmallVector attrs; + attrs.reserve(values.size()); + for (auto &v : values) + attrs.push_back(mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), + mlir::APInt(64, v))); + return mlir::ArrayAttr::get(context, attrs); +} + +mlir::ArrayAttr fir::FirOpBuilder::create2DI64ArrayAttr( + llvm::SmallVectorImpl> &intData) { + llvm::SmallVector arrayAttr; + arrayAttr.reserve(intData.size()); + mlir::MLIRContext *context = getContext(); + for (auto &v : intData) + arrayAttr.push_back(makeI64ArrayAttr(v, context)); + return mlir::ArrayAttr::get(context, arrayAttr); +} + mlir::Value fir::FirOpBuilder::createTemporaryAlloc( mlir::Location loc, mlir::Type type, llvm::StringRef name, mlir::ValueRange lenParams, mlir::ValueRange shape, diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index 7ebeb51cf3dec..d66bebdc55d2a 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -38,7 +38,10 @@ #include "mlir/Support/LLVM.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include +#include #include +#include namespace flangomp { #define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS @@ -49,6 +52,12 @@ namespace { class MapInfoFinalizationPass : public flangomp::impl::MapInfoFinalizationPassBase< MapInfoFinalizationPass> { + /// Helper class tracking a members parent and its + /// placement in the parents member list + struct ParentAndPlacement { + mlir::omp::MapInfoOp parent; + size_t index; + }; /// Tracks any intermediate function/subroutine local allocations we /// generate for the descriptors of box type dummy arguments, so that @@ -58,21 +67,62 @@ class MapInfoFinalizationPass /*corresponding local alloca=*/fir::AllocaOp> localBoxAllocas; - void genDescriptorMemberMaps(mlir::omp::MapInfoOp op, - fir::FirOpBuilder &builder, - mlir::Operation *target) { - mlir::Location loc = op.getLoc(); - mlir::Value descriptor = op.getVarPtr(); + /// getMemberUserList gathers all users of a particular MapInfoOp that are + /// other MapInfoOp's and places them into the mapMemberUsers list, which + /// records the map that the current argument MapInfoOp "op" is part of + /// alongside the placement of "op" in the recorded users members list. The + /// intent of the generated list is to find all MapInfoOp's that may be + /// considered parents of the passed in "op" and in which it shows up in the + /// member list, alongside collecting the placement information of "op" in its + /// parents member list. + void + getMemberUserList(mlir::omp::MapInfoOp op, + llvm::SmallVectorImpl &mapMemberUsers) { + for (auto *users : op->getUsers()) + if (auto map = mlir::dyn_cast_if_present(users)) + for (auto [i, mapMember] : llvm::enumerate(map.getMembers())) + if (mapMember.getDefiningOp() == op) + mapMemberUsers.push_back({map, i}); + } + + llvm::SmallVector + getAsIntegers(llvm::ArrayRef values) { + llvm::SmallVector ints; + ints.reserve(values.size()); + llvm::transform(values, std::back_inserter(ints), + [](mlir::Attribute value) { + return mlir::cast(value).getInt(); + }); + return ints; + } + + /// This function will expand a MapInfoOp's member indices back into a vector + /// so that they can be trivially modified as unfortunately the attribute type + /// that's used does not have modifiable fields at the moment (generally + /// awkward to work with) + void getMemberIndicesAsVectors( + mlir::omp::MapInfoOp mapInfo, + llvm::SmallVector> &indices) { + indices.reserve(mapInfo.getMembersIndexAttr().getValue().size()); + for (auto v : mapInfo.getMembersIndexAttr().getValue()) { + auto memberIndex = mlir::cast(v); + indices.push_back(getAsIntegers(memberIndex.getValue())); + } + } - // If we enter this function, but the mapped type itself is not the - // descriptor, then it's likely the address of the descriptor so we - // must retrieve the descriptor SSA. - if (!fir::isTypeWithDescriptor(op.getVarType())) { + /// When provided a MapInfoOp containing a descriptor type that + /// we must expand into multiple maps this function will extract + /// the value from it and return it, in certain cases we must + /// generate a new allocation to store into so that the + /// fir::BoxOffsetOp we utilise to access the descriptor datas + /// base address can be utilised. + mlir::Value getDescriptorFromBoxMap(mlir::omp::MapInfoOp boxMap, + fir::FirOpBuilder &builder) { + mlir::Value descriptor = boxMap.getVarPtr(); + if (!fir::isTypeWithDescriptor(boxMap.getVarType())) if (auto addrOp = mlir::dyn_cast_if_present( - op.getVarPtr().getDefiningOp())) { + boxMap.getVarPtr().getDefiningOp())) descriptor = addrOp.getVal(); - } - } // The fir::BoxOffsetOp only works with !fir.ref> types, as // allowing it to access non-reference box operations can cause some @@ -82,104 +132,188 @@ class MapInfoFinalizationPass // perform an alloca and then store to it and retrieve the data from the new // alloca. if (mlir::isa(descriptor.getType())) { - // If we have already created a local allocation for this BoxType, - // we must be sure to re-use it so that we end up with the same - // allocations being utilised for the same descriptor across all map uses, - // this prevents runtime issues such as not appropriately releasing or - // deleting all mapped data. - auto find = localBoxAllocas.find(descriptor.getAsOpaquePointer()); - if (find != localBoxAllocas.end()) { - builder.create(loc, descriptor, find->second); - descriptor = find->second; - } else { - mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint(); - mlir::Block *allocaBlock = builder.getAllocaBlock(); - assert(allocaBlock && "No alloca block found for this top level op"); - builder.setInsertionPointToStart(allocaBlock); - auto alloca = builder.create(loc, descriptor.getType()); - builder.restoreInsertionPoint(insPt); - builder.create(loc, descriptor, alloca); - localBoxAllocas[descriptor.getAsOpaquePointer()] = alloca; - descriptor = alloca; - } + mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint(); + mlir::Block *allocaBlock = builder.getAllocaBlock(); + mlir::Location loc = boxMap->getLoc(); + assert(allocaBlock && "No alloca block found for this top level op"); + builder.setInsertionPointToStart(allocaBlock); + auto alloca = builder.create(loc, descriptor.getType()); + builder.restoreInsertionPoint(insPt); + builder.create(loc, descriptor, alloca); + descriptor = alloca; } + return descriptor; + } + + /// Function that generates a FIR operation accessing the descriptor's + /// base address (BoxOffsetOp) and a MapInfoOp for it. The most + /// important thing to note is that we normally move the bounds from + /// the descriptor map onto the base address map. + mlir::omp::MapInfoOp getBaseAddrMap(mlir::Value descriptor, + mlir::OperandRange bounds, + int64_t mapType, + fir::FirOpBuilder &builder) { + mlir::Location loc = descriptor.getLoc(); mlir::Value baseAddrAddr = builder.create( loc, descriptor, fir::BoxFieldAttr::base_addr); // Member of the descriptor pointing at the allocated data - mlir::Value baseAddr = builder.create( + return builder.create( loc, baseAddrAddr.getType(), descriptor, mlir::TypeAttr::get(llvm::cast( fir::unwrapRefType(baseAddrAddr.getType())) .getElementType()), baseAddrAddr, /*members=*/mlir::SmallVector{}, - /*member_index=*/mlir::DenseIntElementsAttr{}, op.getBounds(), - builder.getIntegerAttr(builder.getIntegerType(64, false), - op.getMapType().value()), + /*membersIndex=*/mlir::ArrayAttr{}, bounds, + builder.getIntegerAttr(builder.getIntegerType(64, false), mapType), builder.getAttr( mlir::omp::VariableCaptureKind::ByRef), /*name=*/builder.getStringAttr(""), /*partial_map=*/builder.getBoolAttr(false)); + } - // TODO: map the addendum segment of the descriptor, similarly to the - // above base address/data pointer member. + /// This function adjusts the member indices vector to include a new + /// base address member. We take the position of the descriptor in + /// the member indices list, which is the index data that the base + /// addresses index will be based off of, as the base address is + /// a member of the descriptor. We must also alter other member's + void adjustMemberIndices( + llvm::SmallVector> &memberIndices, + size_t memberIndex) { + llvm::SmallVector baseAddrIndex = memberIndices[memberIndex]; + baseAddrIndex.push_back(0); - auto addOperands = [&](mlir::OperandRange &operandsArr, - mlir::MutableOperandRange &mutableOpRange, - auto directiveOp) { - llvm::SmallVector newMapOps; - for (size_t i = 0; i < operandsArr.size(); ++i) { - if (operandsArr[i] == op) { - // Push new implicit maps generated for the descriptor. - newMapOps.push_back(baseAddr); - - // for TargetOp's which have IsolatedFromAbove we must align the - // new additional map operand with an appropriate BlockArgument, - // as the printing and later processing currently requires a 1:1 - // mapping of BlockArgs to MapInfoOp's at the same placement in - // each array (BlockArgs and MapOperands). - if (directiveOp) { - directiveOp.getRegion().insertArgument(i, baseAddr.getType(), loc); - } - } - newMapOps.push_back(operandsArr[i]); + // If we find another member that is "derived/a member of" the descriptor + // that is not the descriptor itself, we must insert a 0 for the new base + // address we have just added for the descriptor into the list at the + // appropriate position to maintain correctness of the positional/index data + // for that member. + size_t insertPosition = + std::distance(baseAddrIndex.begin(), std::prev(baseAddrIndex.end())); + for (llvm::SmallVector member : memberIndices) { + if (member.size() > insertPosition && + std::equal(baseAddrIndex.begin(), std::prev(baseAddrIndex.end()), + member.begin())) { + member.insert(std::next(member.begin(), insertPosition), 0); } - mutableOpRange.assign(newMapOps); - }; - if (auto mapClauseOwner = - llvm::dyn_cast(target)) { - mlir::OperandRange mapOperandsArr = mapClauseOwner.getMapVars(); - mlir::MutableOperandRange mapMutableOpRange = - mapClauseOwner.getMapVarsMutable(); - mlir::omp::TargetOp targetOp = - llvm::dyn_cast(target); - addOperands(mapOperandsArr, mapMutableOpRange, targetOp); } - if (auto targetDataOp = llvm::dyn_cast(target)) { - mlir::OperandRange useDevAddrArr = targetDataOp.getUseDeviceAddrVars(); - mlir::MutableOperandRange useDevAddrMutableOpRange = - targetDataOp.getUseDeviceAddrVarsMutable(); - addOperands(useDevAddrArr, useDevAddrMutableOpRange, targetDataOp); + + // Insert our newly created baseAddrIndex into the larger list of indices at + // the correct location. + memberIndices.insert(std::next(memberIndices.begin(), memberIndex + 1), + baseAddrIndex); + } + + /// Adjusts the descriptor's map type. The main alteration that is done + /// currently is transforming the map type to `OMP_MAP_TO` where possible. + /// This is because we will always need to map the descriptor to device + /// (or at the very least it seems to be the case currently with the + /// current lowered kernel IR), as without the appropriate descriptor + /// information on the device there is a risk of the kernel IR + /// requesting for various data that will not have been copied to + /// perform things like indexing. This can cause segfaults and + /// memory access errors. However, we do not need this data mapped + /// back to the host from the device, as per the OpenMP spec we cannot alter + /// the data via resizing or deletion on the device. Discarding any + /// descriptor alterations via no map back is reasonable (and required + /// for certain segments of descriptor data like the type descriptor that are + /// global constants). This alteration is only inapplicable to `target exit` + /// and `target update` currently, and that's due to `target exit` not + /// allowing `to` mappings, and `target update` not allowing both `to` and + /// `from` simultaneously. We currently try to maintain the `implicit` flag + /// where necessary, although it does not seem strictly required. + unsigned long getDescriptorMapType(unsigned long mapTypeFlag, + mlir::Operation *target) { + if (llvm::isa_and_nonnull(target)) + return mapTypeFlag; + + bool hasImplicitMap = + (llvm::omp::OpenMPOffloadMappingFlags(mapTypeFlag) & + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT) == + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT; + + return llvm::to_underlying( + hasImplicitMap + ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT + : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); + } + + mlir::omp::MapInfoOp genDescriptorMemberMaps(mlir::omp::MapInfoOp op, + fir::FirOpBuilder &builder, + mlir::Operation *target) { + llvm::SmallVector mapMemberUsers; + getMemberUserList(op, mapMemberUsers); + + // TODO: map the addendum segment of the descriptor, similarly to the + // base address/data pointer member. + mlir::Value descriptor = getDescriptorFromBoxMap(op, builder); + auto baseAddr = getBaseAddrMap(descriptor, op.getBounds(), + op.getMapType().value_or(0), builder); + mlir::ArrayAttr newMembersAttr; + mlir::SmallVector newMembers; + llvm::SmallVector> memberIndices; + + if (!mapMemberUsers.empty() || !op.getMembers().empty()) + getMemberIndicesAsVectors( + !mapMemberUsers.empty() ? mapMemberUsers[0].parent : op, + memberIndices); + + // If the operation that we are expanding with a descriptor has a user + // (parent), then we have to expand the parent's member indices to reflect + // the adjusted member indices for the base address insertion. However, if + // it does not then we are expanding a MapInfoOp without any pre-existing + // member information to now have one new member for the base address, or + // we are expanding a parent that is a descriptor and we have to adjust + // all of its members to reflect the insertion of the base address. + if (!mapMemberUsers.empty()) { + // Currently, there should only be one user per map when this pass + // is executed. Either a parent map, holding the current map in its + // member list, or a target operation that holds a map clause. This + // may change in the future if we aim to refactor the MLIR for map + // clauses to allow sharing of duplicate maps across target + // operations. + ParentAndPlacement mapUser = mapMemberUsers[0]; + adjustMemberIndices(memberIndices, mapUser.index); + llvm::SmallVector newMemberOps; + for (auto v : mapUser.parent.getMembers()) { + newMemberOps.push_back(v); + if (v == op) + newMemberOps.push_back(baseAddr); + } + mapUser.parent.getMembersMutable().assign(newMemberOps); + mapUser.parent.setMembersIndexAttr( + builder.create2DI64ArrayAttr(memberIndices)); + } else { + newMembers.push_back(baseAddr); + if (!op.getMembers().empty()) { + for (auto &indices : memberIndices) + indices.insert(indices.begin(), 0); + memberIndices.insert(memberIndices.begin(), {0}); + newMembersAttr = builder.create2DI64ArrayAttr(memberIndices); + newMembers.append(op.getMembers().begin(), op.getMembers().end()); + } else { + llvm::SmallVector> memberIdx = {{0}}; + newMembersAttr = builder.create2DI64ArrayAttr(memberIdx); + } } - mlir::Value newDescParentMapOp = builder.create( - op->getLoc(), op.getResult().getType(), descriptor, - mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())), - /*varPtrPtr=*/mlir::Value{}, - /*members=*/mlir::SmallVector{baseAddr}, - /*members_index=*/ - mlir::DenseIntElementsAttr::get( - mlir::VectorType::get( - llvm::ArrayRef({1, 1}), - mlir::IntegerType::get(builder.getContext(), 32)), - llvm::ArrayRef({0})), - /*bounds=*/mlir::SmallVector{}, - builder.getIntegerAttr(builder.getIntegerType(64, false), - op.getMapType().value()), - op.getMapCaptureTypeAttr(), op.getNameAttr(), op.getPartialMapAttr()); - op.replaceAllUsesWith(newDescParentMapOp); + mlir::omp::MapInfoOp newDescParentMapOp = + builder.create( + op->getLoc(), op.getResult().getType(), descriptor, + mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())), + /*varPtrPtr=*/mlir::Value{}, newMembers, newMembersAttr, + /*bounds=*/mlir::SmallVector{}, + builder.getIntegerAttr( + builder.getIntegerType(64, false), + getDescriptorMapType(op.getMapType().value_or(0), target)), + op.getMapCaptureTypeAttr(), op.getNameAttr(), + /*partial_map=*/builder.getBoolAttr(false)); + op.replaceAllUsesWith(newDescParentMapOp.getResult()); op->erase(); + return newDescParentMapOp; } // We add all mapped record members not directly used in the target region @@ -225,32 +359,79 @@ class MapInfoFinalizationPass fir::FirOpBuilder &builder, mlir::Operation *target) { auto mapClauseOwner = - llvm::dyn_cast(target); + llvm::dyn_cast_if_present( + target); + // TargetDataOp is technically a MapClauseOwningOpInterface, so we + // do not need to explicitly check for the extra cases here for use_device + // addr/ptr if (!mapClauseOwner) return; - llvm::SmallVector newMapOps; - mlir::OperandRange mapVarsArr = mapClauseOwner.getMapVars(); - auto targetOp = llvm::dyn_cast(target); - - for (size_t i = 0; i < mapVarsArr.size(); ++i) { - if (mapVarsArr[i] == op) { - for (auto [j, mapMember] : llvm::enumerate(op.getMembers())) { - newMapOps.push_back(mapMember); - // for TargetOp's which have IsolatedFromAbove we must align the - // new additional map operand with an appropriate BlockArgument, - // as the printing and later processing currently requires a 1:1 - // mapping of BlockArgs to MapInfoOp's at the same placement in - // each array (BlockArgs and MapVars). - if (targetOp) { - targetOp.getRegion().insertArgument(i + j, mapMember.getType(), - targetOp->getLoc()); + auto addOperands = [&](mlir::OperandRange &mapVarsArr, + mlir::MutableOperandRange &mutableOpRange, + auto directiveOp) { + llvm::SmallVector newMapOps; + for (size_t i = 0; i < mapVarsArr.size(); ++i) { + if (mapVarsArr[i] == op) { + for (auto [j, mapMember] : llvm::enumerate(op.getMembers())) { + newMapOps.push_back(mapMember); + // for TargetOp's which have IsolatedFromAbove we must align the + // new additional map operand with an appropriate BlockArgument, + // as the printing and later processing currently requires a 1:1 + // mapping of BlockArgs to MapInfoOp's at the same placement in + // each array (BlockArgs and MapVars). + if (directiveOp) { + directiveOp.getRegion().insertArgument(i + j, mapMember.getType(), + directiveOp->getLoc()); + } } } + newMapOps.push_back(mapVarsArr[i]); } - newMapOps.push_back(mapVarsArr[i]); + mutableOpRange.assign(newMapOps); + }; + + if (auto mapClauseOwner = + llvm::dyn_cast(target)) { + mlir::OperandRange mapVarsArr = mapClauseOwner.getMapVars(); + mlir::MutableOperandRange mapMutableOpRange = + mapClauseOwner.getMapVarsMutable(); + mlir::omp::TargetOp targetOp = + llvm::dyn_cast(target); + addOperands(mapVarsArr, mapMutableOpRange, targetOp); + } + + if (auto targetDataOp = llvm::dyn_cast(target)) { + mlir::OperandRange useDevAddrArr = targetDataOp.getUseDeviceAddrVars(); + mlir::MutableOperandRange useDevAddrMutableOpRange = + targetDataOp.getUseDeviceAddrVarsMutable(); + addOperands(useDevAddrArr, useDevAddrMutableOpRange, targetDataOp); } - mapClauseOwner.getMapVarsMutable().assign(newMapOps); + } + + // We retrieve the first user that is a Target operation, of which + // there should only be one currently. Every MapInfoOp can be tied to + // at most one Target operation and at the minimum no operations. + // This may change in the future with IR cleanups/modifications, + // in which case this pass will need updating to support cases + // where a map can have more than one user and more than one of + // those users can be a Target operation. For now, we simply + // return the first target operation encountered, which may + // be on the parent MapInfoOp in the case of a member mapping. + // In that case, we traverse the MapInfoOp chain until we + // find the first TargetOp user. + mlir::Operation *getFirstTargetUser(mlir::omp::MapInfoOp mapOp) { + for (auto *user : mapOp->getUsers()) { + if (llvm::isa(user)) + return user; + + if (auto mapUser = llvm::dyn_cast_if_present(user)) + return getFirstTargetUser(mapUser); + } + + return nullptr; } // This pass executes on omp::MapInfoOp's containing descriptor based types @@ -283,27 +464,35 @@ class MapInfoFinalizationPass localBoxAllocas.clear(); func->walk([&](mlir::omp::MapInfoOp op) { - // TODO: Currently only supports a single user for the MapInfoOp, this - // is fine for the moment as the Fortran Frontend will generate a - // new MapInfoOp per Target operation for the moment. However, when/if - // we optimise/cleanup the IR, it likely isn't too difficult to - // extend this function, it would require some modification to create a - // single new MapInfoOp per new MapInfoOp generated and share it across - // all users appropriately, making sure to only add a single member link - // per new generation for the original originating descriptor MapInfoOp. + // TODO: Currently only supports a single user for the MapInfoOp. This + // is fine for the moment, as the Fortran frontend will generate a + // new MapInfoOp with at most one user currently. In the case of + // members of other objects, like derived types, the user would be the + // parent. In cases where it's a regular non-member map, the user would + // be the target operation it is being mapped by. + // + // However, when/if we optimise/cleanup the IR we will have to extend + // this pass to support multiple users, as I would imagine we may wish + // to have a map be re-used by multiple users (e.g. across multiple + // targets that map the variable and have identical map properties) assert(llvm::hasSingleElement(op->getUsers()) && "OMPMapInfoFinalization currently only supports single users " "of a MapInfoOp"); - if (!op.getMembers().empty()) { - addImplicitMembersToTarget(op, builder, *op->getUsers().begin()); - } else if (fir::isTypeWithDescriptor(op.getVarType()) || - mlir::isa_and_present( - op.getVarPtr().getDefiningOp())) { + if (fir::isTypeWithDescriptor(op.getVarType()) || + mlir::isa_and_present( + op.getVarPtr().getDefiningOp())) { builder.setInsertionPoint(op); - genDescriptorMemberMaps(op, builder, *op->getUsers().begin()); + genDescriptorMemberMaps(op, builder, getFirstTargetUser(op)); } }); + + // Wait until after we have generated all of our maps to add them onto + // the target's block arguments, simplifying the process as there would be + // no need to avoid accidental duplicate additions. + func->walk([&](mlir::omp::MapInfoOp op) { + addImplicitMembersToTarget(op, builder, getFirstTargetUser(op)); + }); }); } }; diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir index aa2f416063fce..898feee1d8505 100644 --- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir +++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir @@ -995,8 +995,8 @@ func.func @omp_map_info_nested_derived_type_explicit_member_conversion(%arg0 : ! %6 = fir.coordinate_of %arg0, %5 : (!fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.field) -> !fir.ref // CHECK: %[[MAP_MEMBER_2:.*]] = omp.map.info var_ptr(%[[GEP_3]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr %7 = omp.map.info var_ptr(%6 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref - // CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFTtop_layer", (array<10 x i32>, struct<"_QFTbottom_layer", (array<10 x f32>, f64)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1,1], [2,-1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true} - %9 = omp.map.info var_ptr(%arg0 : !fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %7 : [1,1], [2,-1] : !fir.ref, !fir.ref) -> !fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>> {partial_map = true} + // CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFTtop_layer", (array<10 x i32>, struct<"_QFTbottom_layer", (array<10 x f32>, f64)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1,1], [2] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true} + %9 = omp.map.info var_ptr(%arg0 : !fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %7 : [1,1], [2] : !fir.ref, !fir.ref) -> !fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>> {partial_map = true} // CHECK: omp.target map_entries(%[[MAP_MEMBER_1]] -> %{{.*}}, %[[MAP_MEMBER_2]] -> %{{.*}}, %[[PARENT_MAP]] -> %{{.*}} : !llvm.ptr, !llvm.ptr, !llvm.ptr) { omp.target map_entries(%4 -> %arg1, %7 -> %arg2, %9 -> %arg3 : !fir.ref, !fir.ref, !fir.ref,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>) { omp.terminator @@ -1032,7 +1032,7 @@ func.func @omp_map_common_block_using_common_block_symbol() { %8 = fir.load %4 : !fir.ref %9 = arith.addi %8, %c20_i32 : i32 fir.store %9 to %7 : !fir.ref - omp.terminator + omp.terminator } return } @@ -1069,9 +1069,175 @@ func.func @omp_map_common_block_using_common_block_members() { %9 = fir.load %arg0 : !fir.ref %10 = arith.muli %9, %c10_i32 : i32 fir.store %10 to %arg1 : !fir.ref - omp.terminator + omp.terminator } return } fir.global common @var_common_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8> + +// ----- + +// NOTE: This test (and the other allocatable member map tests below) uses mock +// bounds to simplify the example, the real bounds generation is more complex +// as it has to access the box information. However, it's not what the test +// aims to check. The test aims to check the parent member bindings and +// acceses are appropriately maintained when lowering to the LLVM dialect. + +// CHECK-LABEL: llvm.func @omp_map_derived_type_allocatable_member +// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr) +func.func @omp_map_derived_type_allocatable_member(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { + %c4 = arith.constant 4 : index + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} + %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true} + // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %1 = fir.coordinate_of %arg0, %c4 : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + // CHECK: %[[BADDR_GEP:.*]] = llvm.getelementptr %[[GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %2 = fir.box_offset %1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> + // CHECK: %[[MAP_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP]] : !llvm.ptr, i32) var_ptr_ptr(%[[BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr {name = ""} + %3 = omp.map.info var_ptr(%1 : !fir.ref>>>, !fir.array) var_ptr_ptr(%2 : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr>> {name = ""} + // CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[GEP]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%array_j"} + %4 = omp.map.info var_ptr(%1 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} + // CHECK: %[[MAP_PARENT_DTYPE:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_DESCRIPTOR]], %[[MAP_MEMBER_BADDR]] : [4], [4,0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l", partial_map = true} + %5 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %3 : [4], [4,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>> {name = "one_l", partial_map = true} + // CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG_1:.*]], %[[MAP_MEMBER_BADDR]] -> %[[ARG_2:.*]], %[[MAP_PARENT_DTYPE]] -> %[[ARG_3:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr) { + omp.target map_entries(%4 -> %arg1, %3 -> %arg2, %5 -> %arg3 : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { + omp.terminator + } + return +} + +// ----- + +// CHECK-LABEL: llvm.func @omp_allocatable_derived_type_member_map +// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr) +func.func @omp_allocatable_derived_type_member_map(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { + // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA_2:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %c5 = arith.constant 5 : index + %c4 = arith.constant 4 : index + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} + %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true} + // CHECK: %[[LOAD_DESCRIPTOR:.*]] = llvm.load %[[ARG_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: llvm.store %[[LOAD_DESCRIPTOR]], %[[DTYPE_ALLOCATABLE_ALOCA]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %1 = fir.load %arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> + // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: %[[LOAD_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr + // CHECK: %[[GEP_DTYPE_MEMBER:.*]] = llvm.getelementptr %[[LOAD_DTYPE_BADDR]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %2 = fir.coordinate_of %1, %c4 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref>>> + // CHECK: %[[DTYPE_MEMBER_BADDR:.*]] = llvm.getelementptr %[[GEP_DTYPE_MEMBER]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %3 = fir.box_offset %2 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> + // CHECK: %[[MAP_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_MEMBER]] : !llvm.ptr, i32) var_ptr_ptr(%[[DTYPE_MEMBER_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr {name = ""} + %4 = omp.map.info var_ptr(%2 : !fir.ref>>>, !fir.array) var_ptr_ptr(%3 : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr>> {name = ""} + // CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_MEMBER]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%array_j"} + %5 = omp.map.info var_ptr(%2 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} + // CHECK: %[[LOAD_DESCRIPTOR:.*]] = llvm.load %[[ARG_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %6 = fir.load %arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> + // CHECK: llvm.store %[[LOAD_DESCRIPTOR]], %[[DTYPE_ALLOCATABLE_ALOCA_2]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA_2]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: %[[LOAD_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr + // CHECK: %[[GEP_DTYPE_REGULAR_MEMBER:.*]] = llvm.getelementptr %[[LOAD_DTYPE_BADDR]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %7 = fir.coordinate_of %6, %c5 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref + // CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_REGULAR_MEMBER]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%k"} + %8 = omp.map.info var_ptr(%7 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%k"} + // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[ARG_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %9 = fir.box_offset %arg0 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> + // CHECK: %[[MAP_DTYPE_PARENT_BADDR:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>) var_ptr_ptr(%[[GEP_DTYPE_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + %10 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) var_ptr_ptr(%9 : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> {name = ""} + // CHECK: %[[MAP_DTYPE_PARENT_DESC:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_DTYPE_PARENT_BADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0,4], [0,4,0], [0,5] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l"} + %11 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) members(%10, %5, %4, %8 : [0], [0,4], [0,4,0], [0,5] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> {name = "one_l"} + // CHECK: omp.target map_entries(%[[MAP_DTYPE_PARENT_BADDR]] -> %[[ARG_1:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG_2:.*]], %[[MAP_MEMBER_BADDR]] -> %[[ARG_3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG_4:.*]], %[[MAP_DTYPE_PARENT_DESC]] -> %[[ARG_5:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) { + omp.target map_entries(%10 -> %arg1, %5 -> %arg2, %4 -> %arg3, %8 -> %arg4, %11 -> %arg5 : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { + omp.terminator + } + return +} + +// ----- + +// CHECK-LABEL: llvm.func @omp_alloca_nested_derived_type_map +// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr) +func.func @omp_alloca_nested_derived_type_map(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { + // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA_2:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %c3 = arith.constant 3 : index + %c4 = arith.constant 4 : index + %c6 = arith.constant 6 : index + %c1 = arith.constant 1 : index + %c2 = arith.constant 2 : index + %c0 = arith.constant 0 : index + // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} + %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true} + // CHECK: %[[LOAD_DESCRIPTOR:.*]] = llvm.load %[[ARG_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: llvm.store %[[LOAD_DESCRIPTOR]], %[[DTYPE_ALLOCATABLE_ALOCA]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %1 = fir.load %arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> + // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: %[[LOAD_GEP_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr + // CHECK: %[[LOAD_NESTED_DTYPE:.*]] = llvm.getelementptr %[[LOAD_GEP_DTYPE_BADDR]][0, 6] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)> + %2 = fir.coordinate_of %1, %c6 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + // CHECK: %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER:.*]] = llvm.getelementptr %[[LOAD_NESTED_DTYPE]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %3 = fir.coordinate_of %2, %c2 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + // CHECK: %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER_BADDR:.*]] = llvm.getelementptr %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %4 = fir.box_offset %3 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> + // CHECK: %[[MAP_NESTED_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]] : !llvm.ptr, i32) var_ptr_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr {name = ""} + %5 = omp.map.info var_ptr(%3 : !fir.ref>>>, !fir.array) var_ptr_ptr(%4 : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr>> {name = ""} + // CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%nest%array_k"} + %6 = omp.map.info var_ptr(%3 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} + // CHECK: %[[LOAD_DESCRIPTOR:.*]] = llvm.load %[[ARG_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: llvm.store %[[LOAD_DESCRIPTOR]], %[[DTYPE_ALLOCATABLE_ALOCA_2]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA_2]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + // CHECK: %[[LOAD_GEP_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr + %7 = fir.load %arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> + // CHECK: %[[LOAD_NESTED_DTYPE:.*]] = llvm.getelementptr %[[LOAD_GEP_DTYPE_BADDR]][0, 6] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)> + %8 = fir.coordinate_of %7, %c6 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + // CHECK: %[[NESTED_DTYPE_REGULAR_MEMBER_GEP:.*]] = llvm.getelementptr %[[LOAD_NESTED_DTYPE]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %9 = fir.coordinate_of %8, %c3 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref + // CHECK: %[[MAP_REGULAR_NESTED_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_DTYPE_REGULAR_MEMBER_GEP]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%nest%k"} + %10 = omp.map.info var_ptr(%9 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%nest%k"} + // CHECK: %[[DTYPE_BADDR_GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %11 = fir.box_offset %arg0 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> + // CHECK: %[[MAP_PARENT_BADDR:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<"_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)>) var_ptr_ptr(%[[DTYPE_BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + %12 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) var_ptr_ptr(%11 : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> {name = ""} + // CHECK: %[[MAP_PARENT_DESC:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_PARENT_BADDR]], %[[MAP_NESTED_MEMBER_DESC]], %[[MAP_NESTED_MEMBER_BADDR]], %[[MAP_REGULAR_NESTED_MEMBER]] : [0], [0,6,2], [0,6,2,0], [0,6,3] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l"} + %13 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) members(%12, %6, %5, %10 : [0], [0,6,2], [0,6,2,0], [0,6,3] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> {name = "one_l"} + // CHECK: omp.target map_entries(%[[MAP_PARENT_BADDR]] -> %[[ARG_1:.*]], %[[MAP_NESTED_MEMBER_DESC]] -> %[[ARG_2:.*]], %[[MAP_NESTED_MEMBER_BADDR]] -> %[[ARG_3:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG_4:.*]], %[[MAP_PARENT_DESC]] -> %[[ARG_5:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) { + omp.target map_entries(%12 -> %arg1, %6 -> %arg2, %5 -> %arg3, %10 -> %arg4, %13 -> %arg5 : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { + omp.terminator + } + return +} + +// ----- + +// CHECK-LABEL: llvm.func @omp_nested_derived_type_alloca_map +// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr) +func.func @omp_nested_derived_type_alloca_map(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { + %c4 = arith.constant 4 : index + %c1 = arith.constant 1 : index + %c2 = arith.constant 2 : index + %c0 = arith.constant 0 : index + %c6 = arith.constant 6 : index + // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} + %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true} + // CHECK: %[[NESTED_DTYPE_MEMBER_GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 6] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<"_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)> + %1 = fir.coordinate_of %arg0, %c6 : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + // CHECK: %[[NESTED_ALLOCATABLE_MEMBER_GEP:.*]] = llvm.getelementptr %[[NESTED_DTYPE_MEMBER_GEP]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)> + %2 = fir.coordinate_of %1, %c2 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + // CHECK: %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP:.*]] = llvm.getelementptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %3 = fir.box_offset %2 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> + // CHECK: %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCATABLE_MEMBER_GEP]] : !llvm.ptr, i32) var_ptr_ptr(%[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr {name = ""} + %4 = omp.map.info var_ptr(%2 : !fir.ref>>>, !fir.array) var_ptr_ptr(%3 : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr>> {name = ""} + // CHECK: %[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCATABLE_MEMBER_GEP]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%nest%array_k"} + %5 = omp.map.info var_ptr(%2 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} + // CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer", (f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<"_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC]], %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR]] : [6,2], [6,2,0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l", partial_map = true} + %6 = omp.map.info var_ptr(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%5, %4 : [6,2], [6,2,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>> {name = "one_l", partial_map = true} + // CHECK: omp.target map_entries(%[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC]] -> %[[ARG_1:.*]], %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR]] -> %[[ARG_2:.*]], %[[MAP_PARENT]] -> %[[ARG_3:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr) { + omp.target map_entries(%5 -> %arg1, %4 -> %arg2, %6 -> %arg3 : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { + omp.terminator + } + return +} diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 index 055fdecc91464..dac4938157a60 100644 --- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 +++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 @@ -30,8 +30,8 @@ subroutine mapType_array !$omp end target end subroutine mapType_array -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976711187] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187] subroutine mapType_ptr integer, pointer :: a !$omp target @@ -39,8 +39,8 @@ subroutine mapType_ptr !$omp end target end subroutine mapType_ptr -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976711187] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187] subroutine mapType_allocatable integer, allocatable :: a allocate(a) @@ -50,8 +50,8 @@ subroutine mapType_allocatable deallocate(a) end subroutine mapType_allocatable -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976710675] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] subroutine mapType_ptr_explicit integer, pointer :: a !$omp target map(tofrom: a) @@ -59,8 +59,8 @@ subroutine mapType_ptr_explicit !$omp end target end subroutine mapType_ptr_explicit -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976710675] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] subroutine mapType_allocatable_explicit integer, allocatable :: a allocate(a) @@ -69,7 +69,7 @@ subroutine mapType_allocatable_explicit !$omp end target deallocate(a) end subroutine mapType_allocatable_explicit - + !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 48] !CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 547] subroutine mapType_derived_implicit @@ -78,8 +78,8 @@ subroutine mapType_derived_implicit integer(4) :: array(10) integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target scalar_arr%int = 1 !$omp end target @@ -93,8 +93,8 @@ subroutine mapType_derived_explicit integer(4) :: array(10) integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr) scalar_arr%int = 1 !$omp end target @@ -108,8 +108,8 @@ subroutine mapType_derived_explicit_single_member integer(4) :: array(10) integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%array) scalar_arr%array(1) = 1 !$omp end target @@ -123,8 +123,8 @@ subroutine mapType_derived_explicit_multiple_members integer(4) :: array(10) integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%int, scalar_arr%real) scalar_arr%int = 1 !$omp end target @@ -138,8 +138,8 @@ subroutine mapType_derived_explicit_member_with_bounds integer(4) :: array(10) integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%array(2:5)) scalar_arr%array(3) = 3 !$omp end target @@ -160,8 +160,8 @@ subroutine mapType_derived_explicit_nested_single_member type(nested) :: nest integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%nest%real) scalar_arr%nest%real = 1 !$omp end target @@ -182,8 +182,8 @@ subroutine mapType_derived_explicit_multiple_nested_members type(nested) :: nest integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%nest%int, scalar_arr%nest%real) scalar_arr%nest%int = 1 !$omp end target @@ -204,13 +204,142 @@ subroutine mapType_derived_explicit_nested_member_with_bounds type(nested) :: nest integer(4) :: int end type scalar_and_array - type(scalar_and_array) :: scalar_arr - + type(scalar_and_array) :: scalar_arr + !$omp target map(tofrom: scalar_arr%nest%array(2:5)) scalar_arr%nest%array(3) = 3 !$omp end target end subroutine mapType_derived_explicit_nested_member_with_bounds +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +subroutine mapType_derived_type_alloca() + type :: one_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + end type one_layer + + type(one_layer) :: one_l + + allocate(one_l%array_j(10)) + + !$omp target map(tofrom: one_l%array_j) + one_l%array_j(1) = 10 + !$omp end target +end subroutine + +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 136, i64 48, i64 8, i64 0, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659] +subroutine mapType_alloca_derived_type() + type :: one_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + end type one_layer + + type(one_layer), allocatable :: one_l + + allocate(one_l) + allocate(one_l%array_j(10)) + + !$omp target map(tofrom: one_l%array_j, one_l%k) + one_l%array_j(1) = 10 + one_l%k = 20 + !$omp end target +end subroutine + +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 240, i64 48, i64 8, i64 0, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659] +subroutine mapType_alloca_nested_derived_type() + type :: middle_layer + real(4) :: i + integer(4) :: array_i(10) + integer, allocatable :: array_k(:) + integer(4) :: k + end type middle_layer + + type :: top_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + type(middle_layer) :: nest + end type top_layer + + type(top_layer), allocatable :: one_l + + allocate(one_l) + allocate(one_l%nest%array_k(10)) + + !$omp target map(tofrom: one_l%nest%array_k, one_l%nest%k) + one_l%nest%array_k(1) = 10 + one_l%nest%k = 20 + !$omp end target +end subroutine + +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +subroutine mapType_nested_derived_type_alloca() + type :: middle_layer + real(4) :: i + integer(4) :: array_i(10) + integer, allocatable :: array_k(:) + integer(4) :: k + end type middle_layer + + type :: top_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + type(middle_layer) :: nest + end type top_layer + + type(top_layer) :: one_l + + allocate(one_l%nest%array_k(10)) + + !$omp target map(tofrom: one_l%nest%array_k) + one_l%nest%array_k(1) = 25 + !$omp end target +end subroutine + +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [7 x i64] [i64 0, i64 64, i64 8, i64 0, i64 48, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [7 x i64] [i64 32, i64 281474976710657, i64 281474976710656, i64 281474976710672, i64 281474976710657, i64 281474976710659, i64 281474976710675] +subroutine mapType_nested_derived_type_member_idx() +type :: vertexes + integer :: test + integer(4), allocatable :: vertexx(:) + integer(4), allocatable :: vertexy(:) +end type vertexes + +type :: dtype + real(4) :: i + type(vertexes), allocatable :: vertexes(:) + integer(4) :: array_i(10) +end type dtype + +type(dtype) :: alloca_dtype + +allocate(alloca_dtype%vertexes(4)) +allocate(alloca_dtype%vertexes(2)%vertexy(10)) + +!$omp target map(tofrom: alloca_dtype%vertexes(2)%vertexy) + alloca_dtype%vertexes(2)%vertexy(5) = 20 +!$omp end target +end subroutine + !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 @@ -263,7 +392,7 @@ end subroutine mapType_common_block_members !CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 !CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]] !CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [3 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_allocatable_explicit_{{.*}} @@ -273,7 +402,7 @@ end subroutine mapType_common_block_members !CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 !CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]] !CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [3 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_derived_implicit_{{.*}} @@ -372,6 +501,294 @@ end subroutine mapType_common_block_members !CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 !CHECK: store ptr %[[ARR_OFF]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_derived_type_alloca_{{.*}} +!CHECK: %[[ALLOCATABLE_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8 +!CHECK: %[[ALLOCA:.*]] = alloca %_QFmaptype_derived_type_allocaTone_layer, i64 1, align 8 +!CHECK: %[[DESC_BOUND_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_DESC_ALLOCA]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[DESC_BOUND_ACCESS_LOAD:.*]] = load i64, ptr %[[DESC_BOUND_ACCESS]], align 8 +!CHECK: %[[OFFSET_UB:.*]] = sub i64 %[[DESC_BOUND_ACCESS_LOAD]], 1 +!CHECK: %[[MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_derived_type_allocaTone_layer, ptr %[[ALLOCA]], i32 0, i32 4 +!CHECK: %[[MEMBER_DESCRIPTOR_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MEMBER_ACCESS]], i32 0, i32 0 +!CHECK: %[[CALCULATE_DIM_SIZE:.*]] = sub i64 %[[OFFSET_UB]], 0 +!CHECK: %[[RESTORE_OFFSET:.*]] = add i64 %[[CALCULATE_DIM_SIZE]], 1 +!CHECK: %[[MEMBER_BASE_ADDR_SIZE:.*]] = mul i64 1, %[[RESTORE_OFFSET]] +!CHECK: %[[DESC_BASE_ADDR_DATA_SIZE:.*]] = mul i64 %[[MEMBER_BASE_ADDR_SIZE]], 4 +!CHECK: %[[MEMBER_ACCESS_ADDR_END:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MEMBER_ACCESS]], i64 1 +!CHECK: %[[MEMBER_ACCESS_ADDR_INT:.*]] = ptrtoint ptr %[[MEMBER_ACCESS_ADDR_END]] to i64 +!CHECK: %[[MEMBER_ACCESS_ADDR_BEGIN:.*]] = ptrtoint ptr %[[MEMBER_ACCESS]] to i64 +!CHECK: %[[DTYPE_SEGMENT_SIZE:.*]] = sub i64 %[[MEMBER_ACCESS_ADDR_INT]], %[[MEMBER_ACCESS_ADDR_BEGIN]] +!CHECK: %[[DTYPE_SIZE_CALC:.*]] = sdiv exact i64 %[[DTYPE_SEGMENT_SIZE]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr %[[MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: store i64 %[[DTYPE_SIZE_CALC]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr %[[MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[MEMBER_DESCRIPTOR_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[MEMBER_DESCRIPTOR_BASE_ADDR]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: store ptr %array_offset, ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 3 +!CHECK: store i64 %[[DESC_BASE_ADDR_DATA_SIZE]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_alloca_derived_type_{{.*}} +!CHECK: %{{.*}} = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[DTYPE_ARRAY_MEMBER_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA_3:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, i64 1, align 8 +!CHECK: %[[ACCESS_DESC_MEMBER_UB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ARRAY_MEMBER_DESC_ALLOCA]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[LOAD_DESC_MEMBER_UB:.*]] = load i64, ptr %[[ACCESS_DESC_MEMBER_UB]], align 8 +!CHECK: %[[OFFSET_MEMBER_UB:.*]] = sub i64 %[[LOAD_DESC_MEMBER_UB]], 1 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_2]], i32 0, i32 0 +!CHECK: %[[DTYPE_BASE_ADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS]], align 8 +!CHECK: %[[DTYPE_ALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_derived_typeTone_layer, ptr %[[DTYPE_BASE_ADDR_LOAD]], i32 0, i32 4 +!CHECK: %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ALLOCA_MEMBER_ACCESS]], i32 0, i32 0 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA]], i32 0, i32 0 +!CHECK: %[[DTYPE_BASE_ADDR_LOAD_2:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS_2]], align 8 +!CHECK: %[[DTYPE_NONALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_derived_typeTone_layer, ptr %[[DTYPE_BASE_ADDR_LOAD_2]], i32 0, i32 5 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_3:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 0, i32 0 +!CHECK: %[[MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[OFFSET_MEMBER_UB]], 0 +!CHECK: %[[MEMBER_SIZE_CALC_2:.*]] = add i64 %[[MEMBER_SIZE_CALC_1]], 1 +!CHECK: %[[MEMBER_SIZE_CALC_3:.*]] = mul i64 1, %[[MEMBER_SIZE_CALC_2]] +!CHECK: %[[MEMBER_SIZE_CALC_4:.*]] = mul i64 %[[MEMBER_SIZE_CALC_3]], 4 +!CHECK: %[[DTYPE_BASE_ADDR_LOAD_3:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], align 8 +!CHECK: %[[LOAD_DTYPE_DESC_MEMBER:.*]] = load ptr, ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], align 8 +!CHECK: %[[MEMBER_ARRAY_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[LOAD_DTYPE_DESC_MEMBER]], i64 0 +!CHECK: %[[DTYPE_END_OFFSET:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1 +!CHECK: %[[DTYPE_END:.*]] = ptrtoint ptr %[[DTYPE_END_OFFSET]] to i64 +!CHECK: %[[DTYPE_BEGIN:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64 +!CHECK: %[[DTYPE_DESC_SZ_CALC:.*]] = sub i64 %[[DTYPE_END]], %[[DTYPE_BEGIN]] +!CHECK: %[[DTYPE_DESC_SZ:.*]] = sdiv exact i64 %[[DTYPE_DESC_SZ_CALC]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: store i64 %[[DTYPE_DESC_SZ]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: store ptr %[[DTYPE_BASE_ADDR_LOAD_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +!CHECK: store ptr %[[MEMBER_ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6 +!CHECK: store i64 %[[MEMBER_SIZE_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +!CHECK: store ptr %[[DTYPE_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_alloca_nested_derived_type{{.*}} +!CHECK: %{{.*}} = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA_1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +!CHECK: %[[DTYPE_DESC_ALLOCA_3:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, i64 1, align 8 +!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA_UB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_MEMBER_ALLOCA]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA_UB_LOAD:.*]] = load i64, ptr %[[ALLOCATABLE_MEMBER_ALLOCA_UB]], align 8 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_ALLOCA_UB_LOAD]], 1 +!CHECK: %[[DTYPE_DESC_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_2]], i32 0, i32 0 +!CHECK: %[[DTYPE_DESC_BASE_ADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR_ACCESS]], align 8 +!CHECK: %[[NESTED_DTYPE_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTtop_layer, ptr %[[DTYPE_DESC_BASE_ADDR_LOAD]], i32 0, i32 6 +!CHECK: %[[MAPPED_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTmiddle_layer, ptr %[[NESTED_DTYPE_ACCESS]], i32 0, i32 2 +!CHECK: %[[MAPPED_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MAPPED_MEMBER_ACCESS]], i32 0, i32 0 +!CHECK: %[[DTYPE_DESC_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_1]], i32 0, i32 0 +!CHECK: %[[DTYPE_DESC_BASE_ADDR_LOAD_2:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR_ACCESS_2]], align 8 +!CHECK: %[[NESTED_DTYPE_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTtop_layer, ptr %[[DTYPE_DESC_BASE_ADDR_LOAD_2]], i32 0, i32 6 +!CHECK: %[[NESTED_NONALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTmiddle_layer, ptr %[[NESTED_DTYPE_ACCESS]], i32 0, i32 3 +!CHECK: %[[DTYPE_DESC_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 0, i32 0 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_2:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_1]], 0 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_3:.*]] = add i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_2]], 1 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_4:.*]] = mul i64 1, %[[ALLOCATABLE_MEMBER_SIZE_CALC_3]] +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_5:.*]] = mul i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_4]], 4 +!CHECK: %[[LOAD_BASE_ADDR:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR]], align 8 +!CHECK: %[[LOAD_DESC_MEMBER_BASE_ADDR:.*]] = load ptr, ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], align 8 +!CHECK: %[[ARRAY_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[LOAD_DESC_MEMBER_BASE_ADDR]], i64 0 +!CHECK: %[[DTYPE_DESC_SIZE_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1 +!CHECK: %[[DTYPE_DESC_SIZE_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_DESC_SIZE_CALC_1]] to i64 +!CHECK: %[[DTYPE_DESC_SIZE_CALC_3:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64 +!CHECK: %[[DTYPE_DESC_SIZE_CALC_4:.*]] = sub i64 %[[DTYPE_DESC_SIZE_CALC_2]], %[[DTYPE_DESC_SIZE_CALC_3]] +!CHECK: %[[DTYPE_DESC_SIZE_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_DESC_SIZE_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: store i64 %[[DTYPE_DESC_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: store ptr %[[LOAD_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +!CHECK: store ptr %[[MAPPED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +!CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +!CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +!CHECK: store ptr %[[ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6 +!CHECK: store i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +!CHECK: store ptr %[[NESTED_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_nested_derived_type_alloca{{.*}} +!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8 +!CHECK: %[[ALLOCA:.*]] = alloca %_QFmaptype_nested_derived_type_allocaTtop_layer, i64 1, align 8 +!CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_MEMBER_ALLOCA]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[ALLOCATABLE_MEMBER_ADDR_LOAD:.*]] = load i64, ptr %[[ALLOCATABLE_MEMBER_BASE_ADDR]], align 8 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_ADDR_LOAD]], 1 +!CHECK: %[[NESTED_DTYPE_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_nested_derived_type_allocaTtop_layer, ptr %[[ALLOCA]], i32 0, i32 6 +!CHECK: %[[NESTED_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_nested_derived_type_allocaTmiddle_layer, ptr %[[NESTED_DTYPE_MEMBER_ACCESS]], i32 0, i32 2 +!CHECK: %[[NESTED_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %{{.*}}, i32 0, i32 0 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_2:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_1]], 0 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_3:.*]] = add i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_2]], 1 +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_4:.*]] = mul i64 1, %[[ALLOCATABLE_MEMBER_SIZE_CALC_3]] +!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_5:.*]] = mul i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_4]], 4 +!CHECK: %[[LOAD_BASE_ADDR:.*]] = load ptr, ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], align 8 +!CHECK: %[[ARR_OFFS:.*]] = getelementptr inbounds i32, ptr %[[LOAD_BASE_ADDR]], i64 0 +!CHECK: %[[NESTED_MEMBER_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[NESTED_MEMBER_ACCESS]], i64 1 +!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_1:.*]] = ptrtoint ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS_2]] to i64 +!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_2:.*]] = ptrtoint ptr %[[NESTED_MEMBER_ACCESS]] to i64 +!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_3:.*]] = sub i64 %[[DTYPE_SEGMENT_SIZE_CALC_1]], %[[DTYPE_SEGMENT_SIZE_CALC_2]] +!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_4:.*]] = sdiv exact i64 %[[DTYPE_SEGMENT_SIZE_CALC_3]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr %[[NESTED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: store i64 %[[DTYPE_SEGMENT_SIZE_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr %[[NESTED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: store ptr %[[ARR_OFFS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 3 +!CHECK: store i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_nested_derived_type_member_idx{{.*}} +!CHECK: %[[ALLOCA_0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, align 8 +!CHECK: %[[ALLOCA_1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8 +!CHECK: %[[ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, align 8 +!CHECK: %[[BASE_PTR_1:.*]] = alloca %_QFmaptype_nested_derived_type_member_idxTdtype, i64 1, align 8 +!CHECK: %{{.*}} = getelementptr %_QFmaptype_nested_derived_type_member_idxTdtype, ptr %[[BASE_PTR_1]], i32 0, i32 1 +!CHECK: %[[BOUNDS_ACC:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[BOUNDS_LD:.*]] = load i64, ptr %[[BOUNDS_ACC]], align 8 +!CHECK: %[[BOUNDS_ACC_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCA_1]], i32 0, i32 7, i64 0, i32 1 +!CHECK: %[[BOUNDS_LD_2:.*]] = load i64, ptr %[[BOUNDS_ACC_2]], align 8 +!CHECK: %[[BOUNDS_CALC:.*]] = sub i64 %[[BOUNDS_LD_2]], 1 +!CHECK: %[[OFF_PTR_1:.*]] = getelementptr %_QFmaptype_nested_derived_type_member_idxTdtype, ptr %[[BASE_PTR_1]], i32 0, i32 1 +!CHECK: %[[OFF_PTR_CALC_0:.*]] = sub i64 %[[BOUNDS_LD]], 1 +!CHECK: %[[OFF_PTR_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[OFF_PTR_1]], i32 0, i32 0 +!CHECK: %[[GEP_DESC_PTR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA_0]], i32 0, i32 0 +!CHECK: %[[LOAD_DESC_PTR:.*]] = load ptr, ptr %[[GEP_DESC_PTR]], align 8 +!CHECK: %[[SZ_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA_0]], i32 0, i32 7, i32 0, i32 2 +!CHECK: %[[SZ_CALC_2:.*]] = load i64, ptr %[[SZ_CALC_1]], align 8 +!CHECK: %[[SZ_CALC_3:.*]] = mul nsw i64 1, %[[SZ_CALC_2]] +!CHECK: %[[SZ_CALC_4:.*]] = add nsw i64 %[[SZ_CALC_3]], 0 +!CHECK: %[[SZ_CALC_5:.*]] = getelementptr i8, ptr %[[LOAD_DESC_PTR]], i64 %[[SZ_CALC_4]] +!CHECK: %[[SZ_CALC_6:.*]] = getelementptr %_QFmaptype_nested_derived_type_member_idxTvertexes, ptr %[[SZ_CALC_5]], i32 0, i32 2 +!CHECK: %[[OFF_PTR_4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[SZ_CALC_6]], i32 0, i32 0 +!CHECK: %[[OFF_PTR_CALC_1:.*]] = sub i64 %[[OFF_PTR_CALC_0]], 0 +!CHECK: %[[OFF_PTR_CALC_2:.*]] = add i64 %[[OFF_PTR_CALC_1]], 1 +!CHECK: %[[OFF_PTR_CALC_3:.*]] = mul i64 1, %[[OFF_PTR_CALC_2]] +!CHECK: %[[OFF_PTR_3:.*]] = mul i64 %[[OFF_PTR_CALC_3]], 104 +!CHECK: %[[SZ_CALC_1_2:.*]] = sub i64 %[[BOUNDS_CALC]], 0 +!CHECK: %[[SZ_CALC_2_2:.*]] = add i64 %[[SZ_CALC_1_2]], 1 +!CHECK: %[[SZ_CALC_3_2:.*]] = mul i64 1, %[[SZ_CALC_2_2]] +!CHECK: %[[SZ_CALC_4_2:.*]] = mul i64 %[[SZ_CALC_3_2]], 4 +!CHECK: %[[LOAD_OFF_PTR:.*]] = load ptr, ptr %[[OFF_PTR_2]], align 8 +!CHECK: %[[ARR_OFFS:.*]] = getelementptr inbounds %_QFmaptype_nested_derived_type_member_idxTvertexes, ptr %[[LOAD_OFF_PTR]], i64 0 +!CHECK: %[[LOAD_ARR_OFFS:.*]] = load ptr, ptr %[[OFF_PTR_4]], align 8 +!CHECK: %[[ARR_OFFS_1:.*]] = getelementptr inbounds i32, ptr %[[LOAD_ARR_OFFS]], i64 0 +!CHECK: %[[SZ_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[OFF_PTR_1]], i64 1 +!CHECK: %[[SZ_CALC_2:.*]] = ptrtoint ptr %[[SZ_CALC_1]] to i64 +!CHECK: %[[SZ_CALC_3:.*]] = ptrtoint ptr %[[OFF_PTR_1]] to i64 +!CHECK: %[[SZ_CALC_4:.*]] = sub i64 %[[SZ_CALC_2]], %[[SZ_CALC_3]] +!CHECK: %[[SZ_CALC_5:.*]] = sdiv exact i64 %[[SZ_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr %[[OFF_PTR_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: store i64 %[[SZ_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr %[[OFF_PTR_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[OFF_PTR_2]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[OFF_PTR_2]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: store ptr %[[ARR_OFFS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 3 +!CHECK: store i64 %[[OFF_PTR_3]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +!CHECK: store ptr %[[SZ_CALC_6]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +!CHECK: store ptr %[[OFF_PTR_4]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +!CHECK: store ptr %[[OFF_PTR_4]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +!CHECK: store ptr %[[ARR_OFFS_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 6 +!CHECK: store i64 %[[SZ_CALC_4_2]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 + !CHECK-LABEL: define {{.*}} @{{.*}}maptype_common_block_{{.*}} !CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 !CHECK: store ptr @var_common_, ptr %[[BASE_PTR_ARR]], align 8 diff --git a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 index 87ca400e82e23..e162c5a2d6d69 100644 --- a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 +++ b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 @@ -24,7 +24,7 @@ !HOST: %[[BOUNDS_1:.*]] = omp.map.bounds lower_bound(%[[LB_1]] : index) upper_bound(%[[UB_1]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_1]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_1]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_read(2:5)"} +!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_read(2:5)"} !HOST: %[[LOAD_3:.*]] = fir.load %[[DECLARE_2]]#0 : !fir.ref>>> !HOST: %[[LOAD_4:.*]] = fir.load %[[DECLARE_2]]#1 : !fir.ref>>> @@ -42,7 +42,7 @@ !HOST: %[[BOUNDS_2:.*]] = omp.map.bounds lower_bound(%[[LB_2]] : index) upper_bound(%[[UB_2]] : index) extent(%[[BOX_5]]#1 : index) stride(%[[BOX_4]]#2 : index) start_idx(%[[BOX_3]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_2]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_2]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_write(2:5)"} +!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_write(2:5)"} subroutine read_write_section() integer, allocatable :: sp_read(:) @@ -81,7 +81,7 @@ module assumed_allocatable_array_routines !HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[LB]] : index) upper_bound(%[[UB]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "arr_read_write(2:5)"} +!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "arr_read_write(2:5)"} subroutine assumed_shape_array(arr_read_write) integer, allocatable, intent(inout) :: arr_read_write(:) diff --git a/flang/test/Lower/OpenMP/allocatable-map.f90 b/flang/test/Lower/OpenMP/allocatable-map.f90 index a9f576a6f0999..5c86d9f69ba39 100644 --- a/flang/test/Lower/OpenMP/allocatable-map.f90 +++ b/flang/test/Lower/OpenMP/allocatable-map.f90 @@ -3,7 +3,7 @@ !HLFIRDIALECT: %[[POINTER:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFpointer_routineEpoint"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) !HLFIRDIALECT: %[[BOX_OFF:.*]] = fir.box_offset %[[POINTER]]#1 base_addr : (!fir.ref>>) -> !fir.llvm_ptr> !HLFIRDIALECT: %[[POINTER_MAP_MEMBER:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, i32) var_ptr_ptr(%[[BOX_OFF]] : !fir.llvm_ptr>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr> {name = ""} -!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, !fir.box>) map_clauses(tofrom) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "point"} +!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "point"} !HLFIRDIALECT: omp.target map_entries(%[[POINTER_MAP_MEMBER]] -> {{.*}}, %[[POINTER_MAP]] -> {{.*}} : !fir.llvm_ptr>, !fir.ref>>) { subroutine pointer_routine() integer, pointer :: point diff --git a/flang/test/Lower/OpenMP/array-bounds.f90 b/flang/test/Lower/OpenMP/array-bounds.f90 index 09498ca6cdde9..ce3d0d4584fc7 100644 --- a/flang/test/Lower/OpenMP/array-bounds.f90 +++ b/flang/test/Lower/OpenMP/array-bounds.f90 @@ -52,7 +52,7 @@ module assumed_array_routines !HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C3]] : index) upper_bound(%[[C4]] : index) extent(%[[DIMS1]]#1 : index) stride(%[[DIMS0]]#2 : index) start_idx(%[[C0]] : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %0 base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, !fir.array) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "arr_read_write(2:5)"} +!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "arr_read_write(2:5)"} !HOST: omp.target map_entries(%[[MAP_INFO_MEMBER]] -> %{{.*}}, %[[MAP]] -> %{{.*}}, {{.*}} -> {{.*}} : !fir.llvm_ptr>>, !fir.ref>, !fir.ref) { subroutine assumed_shape_array(arr_read_write) integer, intent(inout) :: arr_read_write(:) diff --git a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 index 3459be87fea2f..cfdcd9eda82d1 100644 --- a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 +++ b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 @@ -35,7 +35,7 @@ program test_link allocate(test_ptr1) test_ptr1 = 1 - !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, tofrom) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr1"} + !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr1"} !$omp target test_ptr1 = test_ptr1 + 1 !$omp end target @@ -46,7 +46,7 @@ program test_link !$omp end target - !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, tofrom) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr2"} + !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr2"} test_ptr2 => test_target !$omp target test_ptr2 = test_ptr2 + 1 diff --git a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 new file mode 100644 index 0000000000000..4984ce3a80f69 --- /dev/null +++ b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 @@ -0,0 +1,161 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}> {bindc_name = "one_l", uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} +!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) +!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} +!CHECK: %[[MEMBER_INDEX:.*]] = arith.constant 4 : index +!CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[DECLARE]]#0, %[[MEMBER_INDEX]] : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +!CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +!CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} +!CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_DESCRIPTOR]], %[[MAP_MEMBER_BASE_ADDR]] : [4], [4,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>> {name = "one_l", partial_map = true} +!CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG0:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_PARENT]] -> %[[ARG2:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { +!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) +subroutine test_derived_type_allocatable_map_operand_and_block_addition() + type :: one_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + end type one_layer + + type(one_layer) :: one_l + + allocate(one_l%array_j(10)) + + !$omp target map(tofrom: one_l%array_j) + one_l%array_j(1) = 10 + !$omp end target +end subroutine + +!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> {bindc_name = "one_l", uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} +!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) +!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} +!CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> +!CHECK: %[[MEMBER_INDEX:.*]] = arith.constant 4 : index +!CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], %[[MEMBER_INDEX]] : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref>>> +!CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +!CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} +!CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> +!CHECK: %[[MEMBER_COORD:.*]] = arith.constant 5 : index +!CHECK: %[[REGULAR_MEMBER:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], %[[MEMBER_COORD]] : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref +!CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%k"} +!CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> +!CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> {name = ""} +!CHECK: %[[MAP_DTYPE_DESC:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0,4], [0,4,0], [0,5] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> {name = "one_l"} +!CHECK: omp.target map_entries(%[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG0:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG1:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG3:.*]], %[[MAP_DTYPE_DESC]] -> %[[ARG4:.*]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { +!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) +subroutine test_allocatable_derived_type_map_operand_and_block_addition() + type :: one_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + end type one_layer + + type(one_layer), allocatable :: one_l + + allocate(one_l) + allocate(one_l%array_j(10)) + + !$omp target map(tofrom: one_l%array_j, one_l%k) + one_l%array_j(1) = 10 + one_l%k = 20 + !$omp end target +end subroutine + +!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> {bindc_name = "one_l", uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} +!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) +!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} +!CHECK: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> +!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index +!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[LOAD]], %[[NESTED_DTYPE_INDEX]] : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 2 : index +!CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +!CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +!CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +!CHECK: %[[MAP_NESTED_MEMBER_COORD:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} +!CHECK: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> +!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index +!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[LOAD]], %[[NESTED_DTYPE_INDEX]] : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 3 : index +!CHECK: %[[REGULAR_NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref +!CHECK: %[[MAP_REGULAR_NESTED_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_NESTED_MEMBER_COORD]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%nest%k"} +!CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> +!CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> {name = ""} +!CHECK: %[[MAP_DTYPE:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(to) capture(ByRef) members(%75, %69, %68, %73 : [0], [0,6,2], [0,6,2,0], [0,6,3] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> {name = "one_l"} +!CHECK: omp.target map_entries(%[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_COORD]] -> %[[ARG1:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG3:.*]], %[[MAP_DTYPE]] -> %[[ARG4:.*]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { +!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) +subroutine test_alloca_nested_derived_type_map_operand_and_block_addition() + type :: middle_layer + real(4) :: i + integer(4) :: array_i(10) + integer, allocatable :: array_k(:) + integer(4) :: k + end type middle_layer + + type :: top_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + type(middle_layer) :: nest + end type top_layer + + type(top_layer), allocatable :: one_l + + allocate(one_l) + allocate(one_l%nest%array_k(10)) + + !$omp target map(tofrom: one_l%nest%array_k, one_l%nest%k) + one_l%nest%array_k(1) = 10 + one_l%nest%k = 20 + !$omp end target +end subroutine + +!CHECK: %[[ALLOCA]] = fir.alloca !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}> {bindc_name = "one_l", uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} +!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA:.*]] {uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) +!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true} +!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index +!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[DECLARE]]#0, %[[NESTED_DTYPE_INDEX]] : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 2 : index +!CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +!CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +!CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +!CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} +!CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%62, %61 : [6,2], [6,2,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>> {name = "one_l", partial_map = true} +!CHECK: omp.target map_entries(%[[MAP_NESTED_MEMBER_DESC]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_PARENT]] -> %[[ARG2:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { +!CHECK: %{{.*}}:2 = hlfir.declare %arg2 {uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) +subroutine test_nested_derived_type_alloca_map_operand_and_block_addition() + type :: middle_layer + real(4) :: i + integer(4) :: array_i(10) + integer, allocatable :: array_k(:) + integer(4) :: k + end type middle_layer + + type :: top_layer + real(4) :: i + integer, allocatable :: scalar + integer(4) :: array_i(10) + real(4) :: j + integer, allocatable :: array_j(:) + integer(4) :: k + type(middle_layer) :: nest + end type top_layer + + type(top_layer) :: one_l + + allocate(one_l%nest%array_k(10)) + + !$omp target map(tofrom: one_l%nest%array_k) + one_l%nest%array_k(1) = 25 + !$omp end target +end subroutine diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index ab33b6b380831..abb17cc60c24c 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -525,9 +525,9 @@ subroutine omp_target_device_addr !CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box> {bindc_name = "a", uniq_name = "_QFomp_target_device_addrEa"} !CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) !CHECK: %[[MAP_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, i32) var_ptr_ptr({{.*}} : !fir.llvm_ptr>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr> {name = ""} - !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} !CHECK: %[[DEV_ADDR_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, i32) var_ptr_ptr({{.*}} : !fir.llvm_ptr>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr> {name = ""} - !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(tofrom) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} !CHECK: omp.target_data map_entries(%[[MAP_MEMBERS]], %[[MAP]] : {{.*}}) use_device_addr(%[[DEV_ADDR_MEMBERS]] -> %[[ARG_0:.*]], %[[DEV_ADDR]] -> %[[ARG_1:.*]] : !fir.llvm_ptr>, !fir.ref>>) { !$omp target data map(tofrom: a) use_device_addr(a) !CHECK: %[[VAL_1_DECL:.*]]:2 = hlfir.declare %[[ARG_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir index fa7b65d41929b..47c44c00d0a35 100644 --- a/flang/test/Transforms/omp-map-info-finalization.fir +++ b/flang/test/Transforms/omp-map-info-finalization.fir @@ -11,7 +11,7 @@ module attributes {omp.is_target_device = false} { %5 = fir.allocmem i32 {fir.must_be_heap = true} %6 = fir.embox %5 : (!fir.heap) -> !fir.box> fir.store %6 to %4#1 : !fir.ref>> - %c0 = arith.constant 1 : index + %c0 = arith.constant 1 : index %c1 = arith.constant 0 : index %c2 = arith.constant 10 : index %dims:3 = fir.box_dims %2#1, %c1 : (!fir.box>, index) -> (index, index, index) @@ -22,10 +22,10 @@ module attributes {omp.is_target_device = false} { omp.target map_entries(%8 -> %arg1, %9 -> %arg2 : !fir.ref>>, !fir.ref>) { omp.terminator } - return + return } } - + // CHECK: func.func @test_descriptor_expansion_pass(%[[ARG0:.*]]: !fir.box>) { // CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box> // CHECK: %[[ALLOCA2:.*]] = fir.alloca !fir.box> @@ -34,11 +34,11 @@ module attributes {omp.is_target_device = false} { // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true} // CHECK: %[[BASE_ADDR_OFF:.*]] = fir.box_offset %[[DECLARE2]]#1 base_addr : (!fir.ref>>) -> !fir.llvm_ptr> // CHECK: %[[DESC_MEMBER_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, i32) var_ptr_ptr(%[[BASE_ADDR_OFF]] : !fir.llvm_ptr>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr> {name = ""} -// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, !fir.box>) map_clauses(tofrom) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> +// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> // CHECK: fir.store %[[DECLARE1]]#1 to %[[ALLOCA]] : !fir.ref>> // CHECK: %[[BASE_ADDR_OFF_2:.*]] = fir.box_offset %[[ALLOCA]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> // CHECK: %[[DESC_MEMBER_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, !fir.array) var_ptr_ptr(%[[BASE_ADDR_OFF_2]] : !fir.llvm_ptr>>) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(from) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> +// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr>>) -> !fir.ref // CHECK: omp.target map_entries(%[[DESC_MEMBER_MAP]] -> %[[ARG1:.*]], %[[DESC_PARENT_MAP]] -> %[[ARG2:.*]], %[[DESC_MEMBER_MAP_2]] -> %[[ARG3:.*]], %[[DESC_PARENT_MAP_2]] -> %[[ARG4:.*]] : {{.*}}) { // ----- @@ -91,3 +91,216 @@ func.func @test_nested_derived_type_map_operand_and_block_addition(%arg0: !fir.r // CHECK: %[[MAP_MEMBER_2:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref, f32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "sa%n%r"} // CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1,0], [1,1] : !fir.ref, !fir.ref) -> {{.*}} {name = "sa", partial_map = true} // CHECK: omp.target map_entries(%[[MAP_MEMBER_1]] -> %[[ARG1:.*]], %[[MAP_MEMBER_2]] -> %[[ARG2:.*]], %[[MAP_PARENT]] -> %[[ARG3:.*]] : !fir.ref, !fir.ref, {{.*}}) { + +// ----- + +module attributes {omp.is_target_device = false} { + func.func @_QPtest_derived_type_allocatable_map_operand_and_block_addition(%arg0: !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) + %1 = hlfir.designate %0#0{"array_j"} {fortran_attrs = #fir.var_attrs} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> !fir.ref>>> + %2 = fir.load %1 : !fir.ref>>> + %c0_0 = arith.constant 0 : index + %3:3 = fir.box_dims %2, %c0_0 : (!fir.box>>, index) -> (index, index, index) + %c1_9 = arith.constant 1 : index + %c0_1 = arith.constant 0 : index + %4:3 = fir.box_dims %2, %c0_1 : (!fir.box>>, index) -> (index, index, index) + %c0_2 = arith.constant 0 : index + %5 = arith.subi %4#1, %c1_9 : index + %6 = omp.map.bounds lower_bound(%c0_2 : index) upper_bound(%5 : index) extent(%4#1 : index) stride(%4#2 : index) start_idx(%3#0 : index) {stride_in_bytes = true} + %c4 = arith.constant 4 : index + %7 = fir.coordinate_of %0#0, %c4 : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + %8 = omp.map.info var_ptr(%7 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) bounds(%6) -> !fir.ref>>> {name = "one_l%array_j"} + %9 = omp.map.info var_ptr(%0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%8 : [4] : !fir.ref>>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>> {name = "one_l", partial_map = true} + omp.target map_entries(%9 -> %arg1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { + omp.terminator + } + return + } +} + +// CHECK: func.func @_QPtest_derived_type_allocatable_map_operand_and_block_addition(%[[ARG0:.*]]: !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { +// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) +// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true} +// CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[ALLOCA]]#0, %{{.*}} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +// CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD:.*]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +// CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +// CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} +// CHECK: %[[MAP_MEMBER_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>, !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%10, %9 : [4], [4,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>> {name = "one_l", partial_map = true} +// CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_MEMBER_PARENT]] -> %[[ARG3:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) { + +// ----- + +func.func @_QPtest_allocatable_derived_type_map_operand_and_block_addition(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) + %1 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> + %2 = fir.box_addr %1 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) -> !fir.heap>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>> + %3 = hlfir.designate %2{"array_j"} {fortran_attrs = #fir.var_attrs} : (!fir.heap>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>) -> !fir.ref>>> + %4 = fir.load %3 : !fir.ref>>> + %c0_0 = arith.constant 0 : index + %5:3 = fir.box_dims %4, %c0_0 : (!fir.box>>, index) -> (index, index, index) + %c1_0 = arith.constant 1 : index + %c0_1 = arith.constant 0 : index + %6:3 = fir.box_dims %4, %c0_1 : (!fir.box>>, index) -> (index, index, index) + %c0_2 = arith.constant 0 : index + %7 = arith.subi %6#1, %c1_0 : index + %8 = omp.map.bounds lower_bound(%c0_2 : index) upper_bound(%7 : index) extent(%6#1 : index) stride(%6#2 : index) start_idx(%5#0 : index) {stride_in_bytes = true} + %9 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> + %c4 = arith.constant 4 : index + %10 = fir.coordinate_of %9, %c4 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref>>> + %11 = omp.map.info var_ptr(%10 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) bounds(%8) -> !fir.ref>>> {name = "one_l%array_j"} + %12 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> + %c5 = arith.constant 5 : index + %13 = fir.coordinate_of %12, %c5 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref + %14 = omp.map.info var_ptr(%13 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%k"} + %15 = omp.map.info var_ptr(%0#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) members(%11, %14 : [4], [5] : !fir.ref>>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> {name = "one_l", partial_map = true} + omp.target map_entries(%15 -> %arg1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { + omp.terminator + } + return + } + +// CHECK: func.func @_QPtest_allocatable_derived_type_map_operand_and_block_addition(%[[ARG0:.*]]: !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { +// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) +// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}}#1 : index) stride(%{{.*}}#2 : index) start_idx(%{{.*}}#0 : index) {stride_in_bytes = true} +// CHECK: %[[LOAD_ALLOCA:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> +// CHECK: %[[ALLOCATABLE_MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_ALLOCA]], %{{.*}} : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref>>> +// CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +// CHECK: %[[MAP_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +// CHECK: %[[MAP_ALLOCA_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} +// CHECK: %[[LOAD_ALLOCA2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> +// CHECK: %[[REGULAR_MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_ALLOCA2]], %{{.*}} : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, index) -> !fir.ref +// CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER_COORD]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%k"} +// CHECK: %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> +// CHECK: %[[MAP_ALLOCA_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>> {name = ""} +// CHECK: %[[MAP_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>) map_clauses(to) capture(ByRef) members(%18, %13, %12, %16 : [0], [0,4], [0,4,0], [0,5] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>> {name = "one_l"} +// CHECK: omp.target map_entries(%[[MAP_ALLOCA_PARENT_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_ALLOCA_MEMBER_DESCRIPTOR]] -> %[[ARG2:.*]], %[[MAP_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG4:.*]], %[[MAP_PARENT_DESCRIPTOR]] -> %[[ARG5:.*]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>>) { + +// ----- + + func.func @_QPtest_alloca_nested_derived_type_map_operand_and_block_addition(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) + %1 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> + %2 = fir.box_addr %1 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) -> !fir.heap>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>> + %3 = hlfir.designate %2{"nest"} : (!fir.heap>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + %4 = hlfir.designate %3{"array_k"} {fortran_attrs = #fir.var_attrs} : (!fir.ref,array_k:!fir.box>>,k:i32}>>) -> !fir.ref>>> + %5 = fir.load %4 : !fir.ref>>> + %c0_0 = arith.constant 0 : index + %6:3 = fir.box_dims %5, %c0_0 : (!fir.box>>, index) -> (index, index, index) + %c1_0 = arith.constant 1 : index + %c0_1 = arith.constant 0 : index + %7:3 = fir.box_dims %5, %c0_1 : (!fir.box>>, index) -> (index, index, index) + %8 = arith.subi %7#1, %c1_0 : index + %9 = omp.map.bounds lower_bound(%c0_1 : index) upper_bound(%8 : index) extent(%7#1 : index) stride(%7#2 : index) start_idx(%6#0 : index) {stride_in_bytes = true} + %10 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> + %c6 = arith.constant 6 : index + %11 = fir.coordinate_of %10, %c6 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + %c2_0 = arith.constant 2 : index + %12 = fir.coordinate_of %11, %c2_0 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + %13 = omp.map.info var_ptr(%12 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) bounds(%9) -> !fir.ref>>> {name = "one_l%nest%array_k"} + %14 = fir.load %0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> + %15 = fir.coordinate_of %14, %c6 : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + %c3 = arith.constant 3 : index + %16 = fir.coordinate_of %15, %c3 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref + %17 = omp.map.info var_ptr(%16 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%nest%k"} + %18 = omp.map.info var_ptr(%0#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) members(%13, %17 : [6,2], [6,3] : !fir.ref>>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> {name = "one_l", partial_map = true} + omp.target map_entries(%18 -> %arg1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { + omp.terminator + } + return + } + +// CHECK: func.func @_QPtest_alloca_nested_derived_type_map_operand_and_block_addition(%[[ARG0:.*]]: !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { +// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) +// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true} +// CHECK: %[[ALLOCA_LOAD:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> +// CHECK: %[[INTERMEDIATE_DTYPE_NESTED_MEMBER:.*]] = fir.coordinate_of %[[ALLOCA_LOAD]], %{{.*}} : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +// CHECK: %[[NESTED_ALLOCA_MEMBER:.*]] = fir.coordinate_of %[[INTERMEDIATE_DTYPE_NESTED_MEMBER]], %{{.*}} : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +// CHECK: %[[NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_ALLOCA_MEMBER]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[NESTED_ALLOCA_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} +// CHECK: %[[ALLOCA_LOAD2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> +// CHECK: %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2:.*]] = fir.coordinate_of %[[ALLOCA_LOAD2]], %{{.*}} : (!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +// CHECK: %[[NESTED_REGULAR_MEMBER:.*]] = fir.coordinate_of %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2]], %{{.*}} : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref +// CHECK: %[[MAP_NESTED_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_REGULAR_MEMBER:.*]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "one_l%nest%k"} +// CHECK: %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> +// CHECK: %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>> {name = ""} +// CHECK: %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>, !fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>) map_clauses(to) capture(ByRef) members(%21, %15, %14, %19 : [0], [0,6,2], [0,6,2,0], [0,6,3] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>> {name = "one_l"} +// CHECK: omp.target map_entries(%[[MAP_ALLOCATABLE_PARENT_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_NESTED_ALLOCA_MEMBER]] -> %[[ARG2:.*]], %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_NESTED_REGULAR_MEMBER]] -> %[[ARG4:.*]], %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR]] -> %[[ARG5:.*]] : !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>>>) { + +// ----- + + func.func @_QPtest_nested_derived_type_alloca_map_operand_and_block_addition(%arg0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) + %1 = hlfir.designate %0#0{"nest"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + %2 = hlfir.designate %1{"array_k"} {fortran_attrs = #fir.var_attrs} : (!fir.ref,array_k:!fir.box>>,k:i32}>>) -> !fir.ref>>> + %3 = fir.load %2 : !fir.ref>>> + %c0_0 = arith.constant 0 : index + %4:3 = fir.box_dims %3, %c0_0 : (!fir.box>>, index) -> (index, index, index) + %c1_16 = arith.constant 1 : index + %c0_1 = arith.constant 0 : index + %5:3 = fir.box_dims %3, %c0_1 : (!fir.box>>, index) -> (index, index, index) + %c0_18 = arith.constant 0 : index + %6 = arith.subi %5#1, %c1_16 : index + %7 = omp.map.bounds lower_bound(%c0_18 : index) upper_bound(%6 : index) extent(%5#1 : index) stride(%5#2 : index) start_idx(%4#0 : index) {stride_in_bytes = true} + %c6_0 = arith.constant 6 : index + %8 = fir.coordinate_of %0#0, %c6_0 : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> + %c2_0 = arith.constant 2 : index + %9 = fir.coordinate_of %8, %c2_0 : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> + %10 = omp.map.info var_ptr(%9 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) bounds(%7) -> !fir.ref>>> {name = "one_l%nest%array_k"} + %11 = omp.map.info var_ptr(%0#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%10 : [6,2] : !fir.ref>>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>> {name = "one_l", partial_map = true} + omp.target map_entries(%11 -> %arg1 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { + omp.terminator + } + return + } + +// CHECK: func.func @_QPtest_nested_derived_type_alloca_map_operand_and_block_addition(%[[ARG0:.*]]: !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { +// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) -> (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) +// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true} +// CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[ALLOCA]]#0, %{{.*}} : (!fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, index) -> !fir.ref,array_k:!fir.box>>,k:i32}>> +// CHECK: %[[ALLOCATABLE_MEMBER:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %{{.*}} : (!fir.ref,array_k:!fir.box>>,k:i32}>>, index) -> !fir.ref>>> +// CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +// CHECK: %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} +// CHECK: %[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%nest%array_k"} +// CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>, !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%12, %11 : [6,2], [6,2,0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>> {name = "one_l", partial_map = true} +// CHECK: omp.target map_entries(%[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_PARENT]] -> %[[ARG3:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box>>,k:i32}>}>>) { + +// ----- + + func.func @_QPmaptype_nested_derived_type_member_idx(%arg0 : !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFmaptype_nested_derived_type_member_idxEalloca_dtype"} : (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) -> (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) + %c1_15 = arith.constant 1 : index + %1 = omp.map.bounds lower_bound(%c1_15 : index) upper_bound(%c1_15 : index) extent(%c1_15 : index) stride(%c1_15 : index) start_idx(%c1_15 : index) {stride_in_bytes = true} + %2 = fir.coordinate_of %0#0, %c1_15 : (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, index) -> !fir.ref>>,vertexy:!fir.box>>}>>>>> + %3 = omp.map.bounds lower_bound(%c1_15 : index) upper_bound(%c1_15 : index) extent(%c1_15 : index) stride(%c1_15 : index) start_idx(%c1_15 : index) {stride_in_bytes = true} + %4 = omp.map.info var_ptr(%2 : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.box>>,vertexy:!fir.box>>}>>>>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) bounds(%3) -> !fir.ref>>,vertexy:!fir.box>>}>>>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"} + %5 = fir.load %2 : !fir.ref>>,vertexy:!fir.box>>}>>>>> + %c2_i64 = arith.constant 2 : i64 + %c1_20 = arith.constant 1 : index + %6 = fir.convert %c2_i64 : (i64) -> index + %7 = arith.subi %6, %c1_20 : index + %8 = fir.coordinate_of %5, %7 : (!fir.box>>,vertexy:!fir.box>>}>>>>, index) -> !fir.ref>>,vertexy:!fir.box>>}>> + %c2_21 = arith.constant 2 : index + %9 = fir.coordinate_of %8, %c2_21 : (!fir.ref>>,vertexy:!fir.box>>}>>, index) -> !fir.ref>>> + %10 = omp.map.info var_ptr(%9 : !fir.ref>>>, !fir.box>>) map_clauses(tofrom) capture(ByRef) bounds(%1) -> !fir.ref>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"} + %11 = omp.map.info var_ptr(%0#1 : !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) members(%4, %10 : [1], [1,2] : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.ref>>>) -> !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>> {name = "alloca_dtype", partial_map = true} + omp.target map_entries(%11 -> %arg1 : !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) { + omp.terminator + } + return + } + +// CHECK: func.func @_QPmaptype_nested_derived_type_member_idx(%[[ARG0:.*]]: !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) { +// CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFmaptype_nested_derived_type_member_idxEalloca_dtype"} : (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) -> (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) +// CHECK: %[[DESC_1:.*]] = fir.coordinate_of %[[DECLARE]]#0, %{{.*}} : (!fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, index) -> !fir.ref>>,vertexy:!fir.box>>}>>>>> +// CHECK: %[[BASE_ADDR_1:.*]] = fir.box_offset %[[DESC_1]] base_addr : (!fir.ref>>,vertexy:!fir.box>>}>>>>>) -> !fir.llvm_ptr>>,vertexy:!fir.box>>}>>>> +// CHECK: %[[BASE_ADDR_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.array>>,vertexy:!fir.box>>}>>) var_ptr_ptr(%[[BASE_ADDR_1]] : !fir.llvm_ptr>>,vertexy:!fir.box>>}>>>>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) bounds(%{{.*}}) -> !fir.llvm_ptr>>,vertexy:!fir.box>>}>>>> {name = ""} +// CHECK: %[[DESC_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.box>>,vertexy:!fir.box>>}>>>>) map_clauses(to) capture(ByRef) -> !fir.ref>>,vertexy:!fir.box>>}>>>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"} +// CHECK: %[[DESC_LD_1:.*]] = fir.load %[[DESC_1]] : !fir.ref>>,vertexy:!fir.box>>}>>>>> +// CHECK: %[[MEMBER_ACCESS_1:.*]] = fir.coordinate_of %[[DESC_LD_1]], %{{.*}} : (!fir.box>>,vertexy:!fir.box>>}>>>>, index) -> !fir.ref>>,vertexy:!fir.box>>}>> +// CHECK: %[[DESC_2:.*]] = fir.coordinate_of %[[MEMBER_ACCESS_1]], %{{.*}} : (!fir.ref>>,vertexy:!fir.box>>}>>, index) -> !fir.ref>>> +// CHECK: %[[BASE_ADDR_2:.*]] = fir.box_offset %[[DESC_2]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +// CHECK: %[[BASE_ADDR_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref>>>, !fir.array) var_ptr_ptr(%[[BASE_ADDR_2]] : !fir.llvm_ptr>>) map_clauses(tofrom) capture(ByRef) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} +// CHECK: %[[DESC_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"} +// CHECK: %[[TOP_PARENT_MAP:.*]] = omp.map.info var_ptr(%0#1 : !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) members(%6, %5, %14, %13 : [1], [1,0], [1,2], [1,2,0] : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.llvm_ptr>>,vertexy:!fir.box>>}>>>>, !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>> {name = "alloca_dtype", partial_map = true} +// CHECK: omp.target map_entries(%[[DESC_MAP_1]] -> %{{.*}}, %[[BASE_ADDR_MAP_1]] -> %{{.*}}, %[[DESC_MAP_2]] -> %{{.*}}, %[[BASE_ADDR_MAP_2]] -> %{{.*}}, %[[TOP_PARENT_MAP]] -> %{{.*}} : !fir.ref>>,vertexy:!fir.box>>}>>>>>, !fir.llvm_ptr>>,vertexy:!fir.box>>}>>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>>,vertexy:!fir.box>>}>>>>,array_i:!fir.array<10xi32>}>>) {