diff --git a/flang/include/flang/Lower/OpenMP/Clauses.h b/flang/include/flang/Lower/OpenMP/Clauses.h index 51bf0eab0f8d07..34639673a1bd5b 100644 --- a/flang/include/flang/Lower/OpenMP/Clauses.h +++ b/flang/include/flang/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/include/flang/Lower/OpenMP/Utils.h b/flang/include/flang/Lower/OpenMP/Utils.h index be504b8cc9a18a..800683a464b1a1 100644 --- a/flang/include/flang/Lower/OpenMP/Utils.h +++ b/flang/include/flang/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,111 @@ 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; + + // The list of associated parent object symbols. used to track data we + // need for various parent processing tasks when performing member + // mapping, the main example currently being re-evaluating the parent + // maps bounds at the final step of map processing, where we need to + // keep a hold of all of the omp::Object's which contain array bounds + // for the respective parent to calculate the final bounds from. + // + // As an Example: + // + // !$omp target map(tofrom: alloca_dtype_arr(2)%array_i, + // alloca_dtype_arr(3)%array_i) + // + // parentObjList will contain alloca_dtype_arr(3) as well as + // alloca_dtype_arr(2). + ObjectList parentObjList; }; -mlir::omp::MapInfoOp -createMapInfoOp(mlir::OpBuilder &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); +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::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); + +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); + +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 *mapSymbols); mlir::Type getLoopVarType(lower::AbstractConverter &converter, std::size_t loopVarTypeSize); @@ -94,8 +169,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/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index 180e2c8ab33ea2..747ae3be969a1b 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -212,6 +212,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 create2DIntegerArrayAttr( + 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/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index eab5355273a6ec..ea590b6c5d6e28 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -372,6 +372,7 @@ bool CodeGenAction::beginSourceFileAction() { return false; } + // Print initial full MLIR module, before lowering or transformations, if // -save-temps has been specified. if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(), diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h index d2060e77ce5305..f59adc73f08fbd 100644 --- a/flang/lib/Lower/DirectivesCommon.h +++ b/flang/lib/Lower/DirectivesCommon.h @@ -1026,7 +1026,10 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, // If it is a scalar subscript, then the upper bound // is equal to the lower bound, and the extent is one. ubound = lbound; - extent = one; + if (treatIndexAsSection) + extent = fir::factory::readExtent(builder, loc, dataExv, dimension); + else + extent = one; } else { asFortran << ':'; Fortran::semantics::MaybeExpr upper = diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index a24c8b6d3e5a07..148aa68f74feaf 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]; + auto insert = parentMemberIndices.emplace(parentObj.value(), + OmpMapParentAndMemberData{}); + insert.first->second.parentObjList.push_back(parentObj.value()); + + 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 +969,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) { @@ -997,23 +1015,22 @@ bool ClauseProcessor::processMap( mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; } + processMapObjects(stmtCtx, clauseLocation, std::get(clause.t), mapTypeBits, parentMemberIndices, result.mapVars, ptrMapSyms, 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 +1051,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 +1127,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 +1140,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 +1151,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 +1165,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 774b5b35f525c6..aeace91084c44c 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/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 60de97936880cc..9c3535ef8a3b17 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -1302,7 +1302,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), @@ -2224,7 +2224,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 64b6334edbf395..7291d5b7920790 100644 --- a/flang/lib/Lower/OpenMP/Utils.cpp +++ b/flang/lib/Lower/OpenMP/Utils.cpp @@ -12,18 +12,24 @@ #include +#include + +#include #include #include +#include #include #include +#include +#include #include #include #include #include #include +#include #include -#include #include llvm::cl::opt treatIndexAsSection( @@ -117,14 +123,12 @@ void gatherFuncAndVarSyms( symbolAndClause.emplace_back(clause, *object.sym()); } -mlir::omp::MapInfoOp -createMapInfoOp(mlir::OpBuilder &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, llvm::ArrayRef bounds, + llvm::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 +149,231 @@ createMapInfoOp(mlir::OpBuilder &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)); + } + } + } + } +} + +static mlir::Value generateBoundsComparisonBranch(fir::FirOpBuilder &firOpBuilder, + mlir::Location clauseLocation, + mlir::arith::CmpIPredicate pred, + mlir::Value index, + mlir::Value bound) { + auto cmp = firOpBuilder.create(clauseLocation, pred, + index, bound); + return firOpBuilder + .genIfOp(clauseLocation, {firOpBuilder.getIndexType()}, cmp, + /*withElseRegion=*/true) + .genThen( + [&]() { firOpBuilder.create(clauseLocation, index); }) + .genElse([&] { + firOpBuilder.create(clauseLocation, + mlir::ValueRange{bound}); + }) + .getResults()[0]; +} + +static void extendBoundsFromMultipleSubscripts( + lower::AbstractConverter &converter, lower::StatementContext &stmtCtx, + mlir::omp::MapInfoOp mapOp, omp::ObjectList objList) { + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + if (!mapOp.getBounds().empty()) { + for (omp::Object v : objList) { + llvm::SmallVector indices; + generateArrayIndices(converter, firOpBuilder, stmtCtx, mapOp.getLoc(), + indices, v); + + for (size_t i = 0; i < mapOp.getBounds().size(); ++i) { + if (auto boundOp = mlir::dyn_cast_if_present( + mapOp.getBounds()[i].getDefiningOp())) { + boundOp.getUpperBoundMutable().assign(generateBoundsComparisonBranch( + firOpBuilder, mapOp.getLoc(), mlir::arith::CmpIPredicate::ugt, + indices[i], boundOp.getUpperBoundMutable().begin()->get())); + boundOp.getLowerBoundMutable().assign(generateBoundsComparisonBranch( + firOpBuilder, mapOp.getLoc(), mlir::arith::CmpIPredicate::ult, + indices[i], boundOp.getLowerBoundMutable().begin()->get())); + } + } + } + } + + // reorder all SSA's we may have generated to make sure we maintain ordering. + sortTopologically(mapOp->getBlock()); +} + +// 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); + } else if (objectList[i].sym()->IsObjectArray() && + arrayExprWithSubscript(objectList[i])) { + auto *it = std::find(parentMemberIndices.memberPlacementIndices.begin(), + parentMemberIndices.memberPlacementIndices.end(), + interimIndices); + auto v = std::distance( + parentMemberIndices.memberPlacementIndices.begin(), it); + extendBoundsFromMultipleSubscripts(converter, stmtCtx, + parentMemberIndices.memberMap[v], + {objectList[i]}); + } + + curValue = firOpBuilder.create(clauseLocation, curValue); + currentIndex++; + } + } + + return curValue; +} + +static int64_t getComponentPlacementInParent(const semantics::Symbol *componentSym) { const auto *derived = componentSym->owner() .derivedTypeSpec() @@ -183,180 +407,133 @@ 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) { 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( mapOperands[parentIdx].getDefiningOp()); - // NOTE: To maintain appropriate SSA ordering, we move the parent map - // which will now have references to its children after the last - // of its members to be generated. This is necessary when a user - // 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); - - for (auto memberIndicesData : indices.second) - mapOp.getMembersMutable().append( - memberIndicesData.memberMap.getResult()); - - mapOp.setMembersIndexAttr(createDenseElementsAttrFromIndices( - indices.second, converter.getFirOpBuilder())); + for (mlir::omp::MapInfoOp memberMap : indices.second.memberMap) + mapOp.getMembersMutable().append(memberMap.getResult()); + + mapOp.setMembersIndexAttr(firOpBuilder.create2DIntegerArrayAttr( + indices.second.memberPlacementIndices)); + + // Not only does this extend bounds if multiple subscripts are + // defined for a map parent, but it also performs a topological + // sort, re-ordering SSA values so everything maintains correct + // ordering, this by extension shuffles the parent map, into the + // correct position after it's member definitions, as when we fall + // into this segment of the if statement, the parent map information + // has been generated prior to it's members in most cases. + extendBoundsFromMultipleSubscripts(converter, stmtCtx, mapOp, + indices.second.parentObjList); } 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.create2DIntegerArrayAttr( + indices.second.memberPlacementIndices), + mapType, mlir::omp::VariableCaptureKind::ByRef, + info.rawInput.getType(), /*partialMap=*/true); + extendBoundsFromMultipleSubscripts(converter, stmtCtx, mapOp, + indices.second.parentObjList); 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; -} - mlir::Value calculateTripCount(fir::FirOpBuilder &builder, mlir::Location loc, const mlir::omp::LoopRelatedClauseOps &ops) { using namespace mlir::arith; diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 539235f01f5f74..8c58bb2b45ee19 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -269,6 +269,24 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() { return getEntryBlock(); } +static mlir::ArrayAttr makeI64ArrayAttr(llvm::ArrayRef values, + mlir::MLIRContext *context) { + llvm::SmallVector attrs; + 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::create2DIntegerArrayAttr( + llvm::SmallVectorImpl> &intData) { + llvm::SmallVector arrayAttr; + 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/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp index b72f9dbe81047b..9c4b694bded926 100644 --- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp +++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp @@ -50,7 +50,7 @@ createMapInfoOp(mlir::OpBuilder &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::ArrayAttr membersIndex, uint64_t mapType, mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy, bool partialMap = false) { if (auto boxTy = llvm::dyn_cast(baseAddr.getType())) { @@ -195,7 +195,7 @@ void cloneOrMapRegionOutsiders(fir::FirOpBuilder &builder, builder, 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), @@ -797,7 +797,7 @@ class DoConcurrentConversion : public mlir::OpConversionPattern { rewriter, liveIn.getLoc(), rawAddr, /*varPtrPtr=*/{}, declareOp.getUniqName().str(), boundsOps, /*members=*/{}, - /*membersIndex=*/mlir::DenseIntElementsAttr{}, + /*membersIndex=*/mlir::ArrayAttr{}, static_cast< std::underlying_type_t>( mapFlag), diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index 31786479604ad1..8faffa20bb942a 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,49 +67,64 @@ class MapInfoFinalizationPass /*corresponding local alloca=*/fir::AllocaOp> localBoxAllocas; - unsigned long getDescriptorMapType(unsigned long mapTypeFlag, - mlir::Operation *target) { - auto newDescFlag = llvm::omp::OpenMPOffloadMappingFlags(mapTypeFlag); - - if ((llvm::isa_and_nonnull(target) || - llvm::isa_and_nonnull(target)) && - static_cast< - std::underlying_type_t>( - (newDescFlag & - llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM)) && - static_cast< - std::underlying_type_t>( - (newDescFlag & llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO) != - llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO)) - return static_cast< - std::underlying_type_t>( - newDescFlag | llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); - - if ((llvm::isa_and_nonnull(target) || - llvm::isa_and_nonnull(target)) && - mapTypeFlag == 0) - return static_cast< - std::underlying_type_t>( - llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); - - return mapTypeFlag; + /// 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}); } - void genDescriptorMemberMaps(mlir::omp::MapInfoOp op, - fir::FirOpBuilder &builder, - mlir::Operation *target) { - mlir::Location loc = op.getLoc(); - mlir::Value descriptor = op.getVarPtr(); + /// Returns the integer numbers contained within the mlir::Attributes within + /// the values array. + 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 @@ -109,13 +133,14 @@ class MapInfoFinalizationPass // !fir.ref> to access the data we need to map we must // perform an alloca and then store to it and retrieve the data from the new // alloca. + // If we have already created a local allocation for this BoxType, + // we must be sure to re-use it so that we end up with the same + // allocations being utilised for the same descriptor across all map uses, + // this prevents runtime issues such as not appropriately releasing or + // deleting all mapped data. 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()); + mlir::Location loc = boxMap->getLoc(); if (find != localBoxAllocas.end()) { builder.create(loc, descriptor, find->second); descriptor = find->second; @@ -132,85 +157,192 @@ class MapInfoFinalizationPass } } + return descriptor; + } + + /// Simple function that will generate a FIR operation accessing + /// the descriptors base address (BoxOffsetOp) and then generate 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 members + /// indices in the list to account for this new addition. This + /// requires inserting into the middle of a member index vector + /// in some cases (i.e. we could be accessing the member of a + /// descriptor type with a subsequent map, so we must be sure to + /// adjust any of these cases with the addition of the new base + /// address index value). + 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 (size_t i = 0; i < memberIndices.size(); ++i) { + if (memberIndices[i].size() > insertPosition && + std::equal(baseAddrIndex.begin(), std::prev(baseAddrIndex.end()), + memberIndices[i].begin())) { + memberIndices[i].insert( + std::next(memberIndices[i].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 descriptors 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 we cannot alter the data + /// via resizing or deletion on the device, this is specified in the + /// OpenMP specification, so 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 unapplicable 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 neccesary, although, it + /// does not seem strictly required. + unsigned long getDescriptorMapType(unsigned long mapTypeFlag, + mlir::Operation *target) { + if (llvm::isa_and_nonnull(target) || + 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 parents 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 + // it's 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.create2DIntegerArrayAttr(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.create2DIntegerArrayAttr(memberIndices); + newMembers.append(op.getMembers().begin(), op.getMembers().end()); + } else { + llvm::SmallVector> memberIdx = {{0}}; + newMembersAttr = builder.create2DIntegerArrayAttr(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), - getDescriptorMapType(op.getMapType().value(), target)), - 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 // to the block arguments in front of their parent and we place them into // the map operands list for consistency. @@ -254,32 +386,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, there + // should only be one currently, every MapInfoOp can be tied to + // at most 1 Target operation and at the minimum no operation, + // this may change in the future with IR cleanups/modifications + // in which case this pass will need updated 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 which case we must 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 @@ -310,26 +489,31 @@ class MapInfoFinalizationPass 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. + // 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)); } }); + + 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 4b9afd5675ea31..ef613c1a7b76c4 100644 --- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir +++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir @@ -998,8 +998,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) { // CHECK: ^bb0(%{{.*}}: !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}>>) { @@ -1039,7 +1039,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 } @@ -1078,9 +1078,183 @@ 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) { + // CHECK: ^bb0(%[[ARG_1]]: !llvm.ptr, %[[ARG_2]]: !llvm.ptr, %[[ARG_3]]: !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}>>) { + ^bb0(%arg1: !fir.ref>>>, %arg2: !fir.llvm_ptr>>, %arg3: !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) { + // CHECK: ^bb0(%[[ARG_1]]: !llvm.ptr, %[[ARG_2]]: !llvm.ptr, %[[ARG_3]]: !llvm.ptr, %[[ARG_4]]: !llvm.ptr, %[[ARG_5]]: !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}>>>>) { + ^bb0(%arg1: !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, %arg2: !fir.ref>>>, %arg3: !fir.llvm_ptr>>, %arg4: !fir.ref, %arg5: !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) { + // CHECK: ^bb0(%[[ARG_1]]: !llvm.ptr, %[[ARG_2]]: !llvm.ptr, %[[ARG_3]]: !llvm.ptr, %[[ARG_4]]: !llvm.ptr, %[[ARG_5]]: !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}>}>>>>) { + ^bb0(%arg1: !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}>}>>>, %arg2: !fir.ref>>>, %arg3: !fir.llvm_ptr>>, %arg4: !fir.ref, %arg5: !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) { + // CHECK: ^bb0(%[[ARG_1]]: !llvm.ptr, %[[ARG_2]]: !llvm.ptr, %[[ARG_3]]: !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}>}>>) { + ^bb0(%arg1: !fir.ref>>>, %arg2: !fir.llvm_ptr>>, %arg3: !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 52ce5e1412af31..fa6596126e4760 100644 --- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 +++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 @@ -31,7 +31,7 @@ subroutine mapType_array end subroutine mapType_array !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 281474976711171, i64 281474976711171, i64 281474976711187] +!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 @@ -40,7 +40,7 @@ subroutine mapType_ptr end subroutine mapType_ptr !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 281474976711171, i64 281474976711171, i64 281474976711187] +!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) @@ -51,7 +51,7 @@ subroutine mapType_allocatable end subroutine mapType_allocatable !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 281474976710659, i64 281474976710659, i64 281474976710675] +!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) @@ -60,7 +60,7 @@ subroutine mapType_ptr_explicit end subroutine mapType_ptr_explicit !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 281474976710659, i64 281474976710659, i64 281474976710675] +!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,117 @@ 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 [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 @@ -372,6 +476,217 @@ 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 %20, 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: %[[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 %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 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]], 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/OpenACC/acc-enter-data.f90 b/flang/test/Lower/OpenACC/acc-enter-data.f90 index 80326a1012376e..ee33e0304f290e 100644 --- a/flang/test/Lower/OpenACC/acc-enter-data.f90 +++ b/flang/test/Lower/OpenACC/acc-enter-data.f90 @@ -808,10 +808,10 @@ subroutine acc_enter_data_single_array_element() !CHECK: %[[VAL_42:.*]] = arith.constant 1 : index !CHECK: %[[VAL_43:.*]] = arith.constant 1 : index !CHECK: %[[VAL_44:.*]] = arith.subi %[[VAL_43]], %[[VAL_38]]#0 : index -!CHECK: %[[VAL_45:.*]] = acc.bounds lowerbound(%[[VAL_44]] : index) upperbound(%[[VAL_44]] : index) extent(%[[VAL_42]] : index) stride(%[[VAL_42]] : index) startIdx(%[[VAL_38]]#0 : index) +!CHECK: %[[VAL_45:.*]] = acc.bounds lowerbound(%[[VAL_44]] : index) upperbound(%[[VAL_44]] : index) extent(%[[VAL_38]]#1 : index) stride(%[[VAL_42]] : index) startIdx(%[[VAL_38]]#0 : index) !CHECK: %[[VAL_46:.*]] = arith.constant 2 : index !CHECK: %[[VAL_47:.*]] = arith.subi %[[VAL_46]], %[[VAL_40]]#0 : index -!CHECK: %[[VAL_48:.*]] = acc.bounds lowerbound(%[[VAL_47]] : index) upperbound(%[[VAL_47]] : index) extent(%[[VAL_42]] : index) stride(%[[VAL_42]] : index) startIdx(%[[VAL_40]]#0 : index) +!CHECK: %[[VAL_48:.*]] = acc.bounds lowerbound(%[[VAL_47]] : index) upperbound(%[[VAL_47]] : index) extent(%[[VAL_40]]#1 : index) stride(%[[VAL_42]] : index) startIdx(%[[VAL_40]]#0 : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[VAL_41]] : !fir.heap>) bounds(%[[VAL_45]], %[[VAL_48]]) -> !fir.heap> {name = "e(2_8)%a(1,2)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.heap>) diff --git a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 index 87ca400e82e23f..e162c5a2d6d69f 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 a9f576a6f09992..5c86d9f69ba39e 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 020e228dccecef..ae11426ba477d9 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 3459be87fea2f0..cfdcd9eda82d1d 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 00000000000000..93719fdd20b0b8 --- /dev/null +++ b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 @@ -0,0 +1,166 @@ +!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: ^bb0(%[[ARG0]]: !fir.ref>>>, %[[ARG1]]: !fir.llvm_ptr>>, %[[ARG2]]: !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: ^bb0(%[[ARG0]]: !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, %[[ARG1]]: !fir.ref>>>, %[[ARG2]]: !fir.llvm_ptr>>, %[[ARG3]]: !fir.ref, %[[ARG4]]: !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: ^bb0(%[[ARG0]]: !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}>}>>>, %[[ARG1]]: !fir.ref>>>, %[[ARG2]]: !fir.llvm_ptr>>, %[[ARG3]]: !fir.ref, %[[ARG4]]: !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: ^bb0(%[[ARG0]]: !fir.ref>>>, %[[ARG1]]: !fir.llvm_ptr>>, %[[ARG2]]: !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 2ad26a62873a06..e7a463e4816cf7 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -531,9 +531,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]], %[[DEV_ADDR]] : {{.*}}) { !$omp target data map(tofrom: a) use_device_addr(a) !CHECK: ^bb0(%[[ARG_0:.*]]: !fir.llvm_ptr>, %[[ARG_1:.*]]: !fir.ref>>): diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir index 417ea22ce1d487..fb95cd96f14bf7 100644 --- a/flang/test/Transforms/omp-map-info-finalization.fir +++ b/flang/test/Transforms/omp-map-info-finalization.fir @@ -35,11 +35,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(tofrom) 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:.*]] : {{.*}}) { // CHECK: ^bb0(%[[ARG1]]: !fir.llvm_ptr>, %[[ARG2]]: !fir.ref>>, %[[ARG3]]: !fir.llvm_ptr>>, %[[ARG4]]: !fir.ref>): @@ -97,3 +97,186 @@ func.func @test_nested_derived_type_map_operand_and_block_addition(%arg0: !fir.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, {{.*}}) { // CHECK: ^bb0(%[[ARG1]]: !fir.ref, %[[ARG2]]: !fir.ref, %[[ARG3]]: {{.*}}): + +// ----- + +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}>>) { + ^bb0(%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}>>) { +// CHECK: ^bb0(%[[ARG1]]: !fir.ref>>>, %[[ARG2]]: !fir.llvm_ptr>>, %[[ARG3]]: !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}>>>>) { + ^bb0(%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}>>>>) { +// CHECK: ^bb0(%[[ARG1]]: !fir.llvm_ptr>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box>>,k:i32}>>>, %[[ARG2]]: !fir.ref>>>, %[[ARG3]]: !fir.llvm_ptr>>, %[[ARG4]]: !fir.ref, %[[ARG5]]: !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}>}>>>>) { + ^bb0(%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}>}>>>>) { +// CHECK: ^bb0(%[[ARG1]]: !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}>}>>>, %[[ARG2]]: !fir.ref>>>, %[[ARG3]]: !fir.llvm_ptr>>, %[[ARG4]]: !fir.ref, %[[ARG5]]: !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}>}>>) { + ^bb0(%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}>}>>) { +// CHECK: ^bb0(%[[ARG1]]: !fir.ref>>>, %[[ARG2]]: !fir.llvm_ptr>>, %[[ARG3]]: !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}>}>>): + +// ----- diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index aeed1ddf7ea9cf..48d6838f08fc11 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -827,7 +827,7 @@ def MapInfoOp : OpenMP_Op<"map.info", [AttrSizedOperandSegments]> { TypeAttr:$var_type, Optional:$var_ptr_ptr, Variadic:$members, - OptionalAttr:$members_index, + OptionalAttr:$members_index, Variadic:$bounds, /* rank-0 to rank-{n-1} */ OptionalAttr:$map_type, OptionalAttr:$map_capture_type, diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp index 5dfe27327e8357..00951017a2aef7 100644 --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -1063,16 +1063,15 @@ static void printMapClause(OpAsmPrinter &p, Operation *op, } static ParseResult parseMembersIndex(OpAsmParser &parser, - DenseIntElementsAttr &membersIdx) { - SmallVector values; + ArrayAttr &membersIdx) { + SmallVector values, memberIdxs; int64_t value; - int64_t shape[2] = {0, 0}; - unsigned shapeTmp = 0; + auto parseIndices = [&]() -> ParseResult { if (parser.parseInteger(value)) return failure(); - shapeTmp++; - values.push_back(APInt(32, value)); + values.push_back(IntegerAttr::get(parser.getBuilder().getIntegerType(64), + mlir::APInt(64, value))); return success(); }; @@ -1086,50 +1085,31 @@ static ParseResult parseMembersIndex(OpAsmParser &parser, if (failed(parser.parseRSquare())) return failure(); - // Only set once, if any indices are not the same size - // we error out in the next check as that's unsupported - if (shape[1] == 0) - shape[1] = shapeTmp; - - // Verify that the recently parsed list is equal to the - // first one we parsed, they must be equal lengths to - // keep the rectangular shape DenseIntElementsAttr - // requires - if (shapeTmp != shape[1]) - return failure(); - - shapeTmp = 0; - shape[0]++; + memberIdxs.push_back(ArrayAttr::get(parser.getContext(), values)); + values.clear(); } while (succeeded(parser.parseOptionalComma())); - if (!values.empty()) { - ShapedType valueType = - VectorType::get(shape, IntegerType::get(parser.getContext(), 32)); - membersIdx = DenseIntElementsAttr::get(valueType, values); - } + if (!memberIdxs.empty()) + membersIdx = ArrayAttr::get(parser.getContext(), memberIdxs); return success(); } static void printMembersIndex(OpAsmPrinter &p, MapInfoOp op, - DenseIntElementsAttr membersIdx) { - llvm::ArrayRef shape = membersIdx.getShapedType().getShape(); - assert(shape.size() <= 2); - + ArrayAttr membersIdx) { if (!membersIdx) return; - for (int i = 0; i < shape[0]; ++i) { + for (size_t i = 0; i < membersIdx.getValue().size(); i++) { + auto memberIdx = mlir::cast(membersIdx.getValue()[i]); p << "["; - int rowOffset = i * shape[1]; - for (int j = 0; j < shape[1]; ++j) { - p << membersIdx.getValues()[rowOffset + j]; - if ((j + 1) < shape[1]) + for (size_t j = 0; j < memberIdx.getValue().size(); j++) { + p << mlir::cast(memberIdx.getValue()[j]).getInt(); + if ((j + 1) < memberIdx.getValue().size()) p << ","; } p << "]"; - - if ((i + 1) < shape[0]) + if ((i + 1) < membersIdx.getValue().size()) p << ", "; } } diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index b0fd4c362ac21f..8a1911bb50ebcd 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -2621,49 +2621,49 @@ static int getMapDataMemberIdx(MapInfoData &mapData, omp::MapInfoOp memberOp) { return std::distance(mapData.MapClause.begin(), res); } -static omp::MapInfoOp getFirstOrLastMappedMemberPtr(omp::MapInfoOp mapInfo, - bool first) { - DenseIntElementsAttr indexAttr = mapInfo.getMembersIndexAttr(); - +static mlir::omp::MapInfoOp +getFirstOrLastMappedMemberPtr(mlir::omp::MapInfoOp mapInfo, bool first) { + mlir::ArrayAttr indexAttr = mapInfo.getMembersIndexAttr(); // Only 1 member has been mapped, we can return it. if (indexAttr.size() == 1) if (auto mapOp = dyn_cast(mapInfo.getMembers()[0].getDefiningOp())) return mapOp; - llvm::ArrayRef shape = indexAttr.getShapedType().getShape(); - llvm::SmallVector indices(shape[0]); + llvm::SmallVector indices(indexAttr.size()); std::iota(indices.begin(), indices.end(), 0); - llvm::sort(indices.begin(), indices.end(), - [&](const size_t a, const size_t b) { - auto indexValues = indexAttr.getValues(); - for (int i = 0; i < shape[1]; ++i) { - int aIndex = indexValues[a * shape[1] + i]; - int bIndex = indexValues[b * shape[1] + i]; - - if (aIndex == bIndex) - continue; - - if (aIndex != -1 && bIndex == -1) - return false; - - if (aIndex == -1 && bIndex != -1) - return true; + llvm::sort( + indices.begin(), indices.end(), [&](const size_t a, const size_t b) { + auto memberIndicesA = mlir::cast(indexAttr[a]); + auto memberIndicesB = mlir::cast(indexAttr[b]); + + size_t smallestMember = memberIndicesA.size() < memberIndicesB.size() + ? memberIndicesA.size() + : memberIndicesB.size(); + for (size_t i = 0; i < smallestMember; ++i) { + int64_t aIndex = + mlir::cast(memberIndicesA.getValue()[i]) + .getInt(); + int64_t bIndex = + mlir::cast(memberIndicesB.getValue()[i]) + .getInt(); + + if (aIndex == bIndex) + continue; - // A is earlier in the record type layout than B - if (aIndex < bIndex) - return first; + if (aIndex < bIndex) + return first; - if (bIndex < aIndex) - return !first; - } + if (aIndex > bIndex) + return !first; + } - // Iterated the entire list and couldn't make a decision, all - // elements were likely the same. Return false, since the sort - // comparator should return false for equal elements. - return false; - }); + // Iterated up until the end of the smallest member and + // they were found to be equal up to that point, so select + // the member with the lowest index count, so the "parent" + return memberIndicesA.size() < memberIndicesB.size(); + }); return llvm::cast( mapInfo.getMembers()[indices.front()].getDefiningOp()); diff --git a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-record-type-mapping-host.mlir b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-record-type-mapping-host.mlir new file mode 100644 index 00000000000000..1560ab7ed42a9a --- /dev/null +++ b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-record-type-mapping-host.mlir @@ -0,0 +1,333 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +// This test checks the offload sizes, map types and base pointers and pointers +// provided to the OpenMP kernel argument structure are correct when lowering +// to LLVM-IR from MLIR when performing explicit member mapping of a record type +// that includes fortran allocatables in various locations of the record types +// hierarchy. + +module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"]} { + llvm.func @omp_map_derived_type_allocatable_member(%arg0: !llvm.ptr) { + %0 = llvm.mlir.constant(4 : index) : i64 + %1 = llvm.mlir.constant(1 : index) : i64 + %2 = llvm.mlir.constant(0 : index) : i64 + %3 = omp.map.bounds lower_bound(%2 : i64) upper_bound(%0 : i64) extent(%0 : i64) stride(%1 : i64) start_idx(%2 : i64) {stride_in_bytes = true} + %4 = llvm.getelementptr %arg0[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)> + %5 = llvm.getelementptr %4[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %6 = omp.map.info var_ptr(%4 : !llvm.ptr, i32) var_ptr_ptr(%5 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%3) -> !llvm.ptr {name = ""} + %7 = omp.map.info var_ptr(%4 : !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"} + %8 = omp.map.info var_ptr(%arg0 : !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(%7, %6 : [4,-1], [4,0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l", partial_map = true} + omp.target map_entries(%7 -> %arg1, %6 -> %arg2, %8 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr) { + ^bb0(%arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr): + omp.terminator + } + llvm.return + } + + llvm.func @omp_allocatable_derived_type_member_map(%arg0: !llvm.ptr) { + %0 = llvm.mlir.constant(1 : i32) : i32 + %1 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %2 = llvm.mlir.constant(1 : i32) : i32 + %3 = llvm.alloca %2 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %4 = llvm.mlir.constant(5 : index) : i64 + %5 = llvm.mlir.constant(4 : index) : i64 + %6 = llvm.mlir.constant(1 : index) : i64 + %7 = llvm.mlir.constant(0 : index) : i64 + %8 = omp.map.bounds lower_bound(%7 : i64) upper_bound(%5 : i64) extent(%5 : i64) stride(%6 : i64) start_idx(%7 : i64) {stride_in_bytes = true} + %9 = llvm.load %arg0 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + llvm.store %9, %3 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %10 = llvm.getelementptr %3[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %11 = llvm.load %10 : !llvm.ptr -> !llvm.ptr + %12 = llvm.getelementptr %11[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)> + %13 = llvm.getelementptr %12[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %14 = omp.map.info var_ptr(%12 : !llvm.ptr, i32) var_ptr_ptr(%13 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%8) -> !llvm.ptr {name = ""} + %15 = omp.map.info var_ptr(%12 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%array_j"} + %16 = llvm.load %arg0 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + llvm.store %16, %1 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %17 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %18 = llvm.load %17 : !llvm.ptr -> !llvm.ptr + %19 = llvm.getelementptr %18[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)> + %20 = omp.map.info var_ptr(%19 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%k"} + %21 = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %22 = omp.map.info var_ptr(%arg0 : !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(%21 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + %23 = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>) map_clauses(tofrom) capture(ByRef) members(%22, %15, %14, %20 : [0,-1,-1], [0,4,-1], [0,4,0], [0,5,-1] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l"} + omp.target map_entries(%22 -> %arg1, %15 -> %arg2, %14 -> %arg3, %20 -> %arg4, %23 -> %arg5 : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) { + ^bb0(%arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr, %arg4: !llvm.ptr, %arg5: !llvm.ptr): + omp.terminator + } + llvm.return + } + + llvm.func @omp_alloca_nested_derived_type_map(%arg0: !llvm.ptr) { + %0 = llvm.mlir.constant(1 : i32) : i32 + %1 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %2 = llvm.mlir.constant(1 : i32) : i32 + %3 = llvm.alloca %2 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %4 = llvm.mlir.constant(3 : index) : i64 + %5 = llvm.mlir.constant(4 : index) : i64 + %6 = llvm.mlir.constant(6 : index) : i64 + %7 = llvm.mlir.constant(1 : index) : i64 + %8 = llvm.mlir.constant(2 : index) : i64 + %9 = llvm.mlir.constant(0 : index) : i64 + %10 = omp.map.bounds lower_bound(%9 : i64) upper_bound(%5 : i64) extent(%5 : i64) stride(%7 : i64) start_idx(%9 : i64) {stride_in_bytes = true} + %11 = llvm.load %arg0 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + llvm.store %11, %3 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %12 = llvm.getelementptr %3[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %13 = llvm.load %12 : !llvm.ptr -> !llvm.ptr + %14 = llvm.getelementptr %13[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)>)> + %15 = llvm.getelementptr %14[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)> + %16 = llvm.getelementptr %15[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %17 = omp.map.info var_ptr(%15 : !llvm.ptr, i32) var_ptr_ptr(%16 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%10) -> !llvm.ptr {name = ""} + %18 = omp.map.info var_ptr(%15 : !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"} + %19 = llvm.load %arg0 : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + llvm.store %19, %1 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr + %20 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %21 = llvm.load %20 : !llvm.ptr -> !llvm.ptr + %22 = llvm.getelementptr %21[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)>)> + %23 = llvm.getelementptr %22[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)> + %24 = omp.map.info var_ptr(%23 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%nest%k"} + %25 = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)> + %26 = omp.map.info var_ptr(%arg0 : !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(%25 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + %27 = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>) map_clauses(tofrom) capture(ByRef) members(%26, %18, %17, %24 : [0,-1,-1,-1], [0,6,2,-1], [0,6,2,0], [0,6,3,-1] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l"} + omp.target map_entries(%26 -> %arg1, %18 -> %arg2, %17 -> %arg3, %24 -> %arg4, %27 -> %arg5 : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) { + ^bb0(%arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr, %arg4: !llvm.ptr, %arg5: !llvm.ptr): + omp.terminator + } + llvm.return + } + + llvm.func @omp_nested_derived_type_alloca_map(%arg0: !llvm.ptr) { + %0 = llvm.mlir.constant(4 : index) : i64 + %1 = llvm.mlir.constant(1 : index) : i64 + %2 = llvm.mlir.constant(2 : index) : i64 + %3 = llvm.mlir.constant(0 : index) : i64 + %4 = llvm.mlir.constant(6 : index) : i64 + %5 = omp.map.bounds lower_bound(%3 : i64) upper_bound(%0 : i64) extent(%0 : i64) stride(%1 : i64) start_idx(%3 : i64) {stride_in_bytes = true} + %6 = llvm.getelementptr %arg0[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)>)> + %7 = llvm.getelementptr %6[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)> + %8 = llvm.getelementptr %7[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %9 = omp.map.info var_ptr(%7 : !llvm.ptr, i32) var_ptr_ptr(%8 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%5) -> !llvm.ptr {name = ""} + %10 = omp.map.info var_ptr(%7 : !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"} + %11 = omp.map.info var_ptr(%arg0 : !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(%10, %9 : [6,2,-1], [6,2,0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l", partial_map = true} + omp.target map_entries(%10 -> %arg1, %9 -> %arg2, %11 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr) { + ^bb0(%arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr): + omp.terminator + } + llvm.return + } +} + +// CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 20] +// CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675] +// CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 136, i64 48, i64 8, i64 20, i64 4] +// CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 281474976710659] +// CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 240, i64 48, i64 8, i64 20, i64 4] +// CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 281474976710659] +// CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 20] +// CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675] + +// CHECK: define void @omp_map_derived_type_allocatable_member(ptr %[[ARG:.*]]) { + +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_GEP:.*]] = getelementptr %_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer, ptr %[[ARG]], i32 0, i32 4 +// CHECK: %[[ALLOCATABLE_MEMBER_BADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ALLOCATABLE_MEMBER_GEP]], i32 0, i32 0 + +// CHECK: %[[LOAD_ALLOCATABLE_MEMBER_BADDR:.*]] = load ptr, ptr %[[ALLOCATABLE_MEMBER_BADDR]], align 8 +// CHECK: %[[ARR_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[LOAD_ALLOCATABLE_MEMBER_BADDR]], i64 0 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_1:.*]] = getelementptr i32, ptr %[[ARR_OFFSET]], i64 1 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_SIZE_SEGMENT_CALC_1]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_3:.*]] = ptrtoint ptr %[[DTYPE_ALLOCATABLE_MEMBER_GEP]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_4:.*]] = sub i64 %[[DTYPE_SIZE_SEGMENT_CALC_2]], %[[DTYPE_SIZE_SEGMENT_CALC_3]] +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_SIZE_SEGMENT_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 +// CHECK: %[[OFFLOAD_SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: store i64 %[[DTYPE_SIZE_SEGMENT_CALC_5]], ptr %[[OFFLOAD_SIZES]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr %[[ALLOCATABLE_MEMBER_BADDR]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: store ptr %[[ALLOCATABLE_MEMBER_BADDR]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: store ptr %[[ARR_OFFSET]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: define void @omp_allocatable_derived_type_member_map(ptr %[[ARG:.*]]) { + +// CHECK: %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +// CHECK: %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +// CHECK: %[[LOAD_DTYPE_ALLOCATABLE_ARG:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], align 8 +// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_DTYPE_ALLOCATABLE_ARG]], ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA]], align 8 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA]], i32 0, i32 0 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_ALLOCATABLE_BADDR_GEP]], align 8 +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_ACCESS:.*]] = getelementptr %_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer, ptr %[[DTYPE_ALLOCATABLE_BADDR_LOAD]], i32 0, i32 4 +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_BADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ALLOCATABLE_MEMBER_ACCESS]], i32 0, i32 0 +// CHECK: %[[LOAD_DTYPE_ALLOCATABLE_ARG:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], align 8 +// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_DTYPE_ALLOCATABLE_ARG]], ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2]], align 8 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2]], i32 0, i32 0 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_ALLOCATABLE_BADDR_GEP]], align 8 +// CHECK: %[[DTYPE_REGULAR_MEMBER_ACCESS:.*]] = getelementptr %_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer, ptr %[[DTYPE_ALLOCATABLE_BADDR_LOAD]], i32 0, i32 5 +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], i32 0, i32 0 +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2_LOAD:.*]] = load ptr, ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2]], align 8 +// CHECK: %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR]], align 8 +// CHECK: %[[ARR_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_LOAD]], i64 0 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], i32 1 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_SIZE_SEGMENT_CALC_1]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_3:.*]] = ptrtoint ptr %[[ARG]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_4:.*]] = sub i64 %[[DTYPE_SIZE_SEGMENT_CALC_2]], %[[DTYPE_SIZE_SEGMENT_CALC_3]] +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_SIZE_SEGMENT_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[OFFLOAD_PTRS]], align 8 +// CHECK: %[[OFFLOAD_SIZES:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: store i64 %[[DTYPE_SIZE_SEGMENT_CALC_5]], ptr %[[OFFLOAD_SIZES]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR_2_LOAD]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_MEMBER_BADDR]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +// CHECK: store ptr %[[ARR_OFFSET]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +// CHECK: store ptr %[[DTYPE_REGULAR_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: define void @omp_alloca_nested_derived_type_map(ptr %[[ARG:.*]]) { + +// CHECK: %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +// CHECK: %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8 +// CHECK: %[[LOAD_DTYPE_ALLOCATABLE_ARG:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], align 8 +// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_DTYPE_ALLOCATABLE_ARG]], ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA]], align 8 +// CHECK: %[[DTYPE_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA]], i32 0, i32 0 +// CHECK: %[[DTYPE_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_BADDR_GEP]], align 8 +// CHECK: %[[DTYPE_NESTED_DTYPE_MEMBER_GEP:.*]] = getelementptr %_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer, ptr %[[DTYPE_BADDR_LOAD]], i32 0, i32 6 +// CHECK: %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_GEP:.*]] = getelementptr %_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer, ptr %[[DTYPE_NESTED_DTYPE_MEMBER_GEP]], i32 0, i32 2 +// CHECK: %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_GEP]], i32 0, i32 0 +// CHECK: %[[LOAD_DTYPE_ALLOCATABLE_ARG:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], align 8 +// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_DTYPE_ALLOCATABLE_ARG]], ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2]], align 8 +// CHECK: %[[DTYPE_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[LOCAL_ALLOCATABLE_DTYPE_ALLOCA_2]], i32 0, i32 0 +// CHECK: %[[DTYPE_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_BADDR_GEP]], align 8 +// CHECK: %[[DTYPE_NESTED_DTYPE_MEMBER_GEP:.*]] = getelementptr %_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer, ptr %[[DTYPE_BADDR_LOAD]], i32 0, i32 6 +// CHECK: %[[DTYPE_NESTED_REGULAR_MEMBER_GEP:.*]] = getelementptr %_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer, ptr %[[DTYPE_NESTED_DTYPE_MEMBER_GEP]], i32 0, i32 3 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], i32 0, i32 0 +// CHECK: %[[DTYPE_ALLOCATABLE_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_ALLOCATABLE_BADDR_GEP]], align 8 +// CHECK: %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], align 8 +// CHECK: %[[ARR_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_LOAD]], i64 0 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[ARG]], i32 1 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_SIZE_SEGMENT_CALC_1]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_3:.*]] = ptrtoint ptr %[[ARG]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_4:.*]] = sub i64 %[[DTYPE_SIZE_SEGMENT_CALC_2]], %[[DTYPE_SIZE_SEGMENT_CALC_3]] +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_SIZE_SEGMENT_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[OFFLOAD_PTRS]], align 8 +// CHECK: %[[OFFLOAD_SIZES:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: store i64 %[[DTYPE_SIZE_SEGMENT_CALC_5]], ptr %[[OFFLOAD_SIZES]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_BADDR_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_BADDR_GEP]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: store ptr %[[DTYPE_ALLOCATABLE_BADDR_LOAD]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +// CHECK: store ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +// CHECK: store ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +// CHECK: store ptr %[[DTYPE_NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +// CHECK: store ptr %[[ARR_OFFSET]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +// CHECK: store ptr %[[DTYPE_NESTED_REGULAR_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: define void @omp_nested_derived_type_alloca_map(ptr %[[ARG:.*]]) { + +// CHECK: %[[NESTED_DTYPE_MEMBER_GEP:.*]] = getelementptr %_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer, ptr %[[ARG]], i32 0, i32 6 +// CHECK: %[[NESTED_ALLOCATABLE_MEMBER_GEP:.*]] = getelementptr %_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer, ptr %[[NESTED_DTYPE_MEMBER_GEP]], i32 0, i32 2 +// CHECK: %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]], i32 0, i32 0 +// CHECK: %[[NESTED_ALLOCATABLE_MEMBER_BADDR_LOAD:.*]] = load ptr, ptr %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], align 8 +// CHECK: %[[ARR_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[NESTED_ALLOCATABLE_MEMBER_BADDR_LOAD]], i64 0 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_1:.*]] = getelementptr i32, ptr %[[ARR_OFFSET]], i64 1 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_SIZE_SEGMENT_CALC_1]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_3:.*]] = ptrtoint ptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]] to i64 +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_4:.*]] = sub i64 %[[DTYPE_SIZE_SEGMENT_CALC_2]], %[[DTYPE_SIZE_SEGMENT_CALC_3]] +// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_SIZE_SEGMENT_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: store ptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 +// CHECK: %[[OFFLOAD_SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: store i64 %[[DTYPE_SIZE_SEGMENT_CALC_5]], ptr %[[OFFLOAD_SIZES]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: store ptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], ptr %[[OFFLOAD_PTRS]], align 8 + +// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: store ptr %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]], ptr %[[BASE_PTRS]], align 8 +// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: store ptr %[[ARR_OFFSET]], ptr %[[OFFLOAD_PTRS]], align 8 diff --git a/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir b/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir index 8cec94abf968b5..66478fc8dbf15d 100644 --- a/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir @@ -21,7 +21,7 @@ llvm.func @_QQmain() { %9 = llvm.getelementptr %4[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)> %10 = omp.map.bounds lower_bound(%2 : i64) upper_bound(%1 : i64) extent(%0 : i64) stride(%2 : i64) start_idx(%2 : i64) %11 = omp.map.info var_ptr(%9 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(tofrom) capture(ByRef) bounds(%10) -> !llvm.ptr - %12 = omp.map.info var_ptr(%4 : !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%6, %8, %11 : [3, -1], [2, 1], [1, -1] : !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true} + %12 = omp.map.info var_ptr(%4 : !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%6, %8, %11 : [3], [2, 1], [1] : !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true} omp.target map_entries(%6 -> %arg0, %8 -> %arg1, %11 -> %arg2, %12 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) { ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr): omp.terminator diff --git a/offload/test/offloading/fortran/target_private.f90 b/offload/test/offloading/fortran/target_private.f90 index 486c23ec2ec8d2..cd1d0c984d15b8 100644 --- a/offload/test/offloading/fortran/target_private.f90 +++ b/offload/test/offloading/fortran/target_private.f90 @@ -1,13 +1,7 @@ ! Basic offloading test with a target region -! REQUIRES: flang -! UNSUPPORTED: nvptx64-nvidia-cuda-LTO -! UNSUPPORTED: aarch64-unknown-linux-gnu -! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO -! UNSUPPORTED: x86_64-pc-linux-gnu -! UNSUPPORTED: x86_64-pc-linux-gnu-LTO +! REQUIRES: flang, amdgpu -! RUN: %libomptarget-compile-fortran-generic -! RUN: env LIBOMPTARGET_INFO=16 %libomptarget-run-generic 2>&1 | %fcheck-generic +! RUN: %libomptarget-compile-fortran-run-and-check-generic program target_update implicit none integer :: x(1) @@ -24,6 +18,6 @@ program target_update print *, "y =", y(1) end program target_update -! CHECK: "PluginInterface" device {{[0-9]+}} info: Launching kernel {{.*}} + ! CHECK: x = 42 ! CHECK: y = 84