diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index e56d7f7ed9b6f..387b0c67952a7 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -164,14 +164,13 @@ createDataEntryOp(fir::FirOpBuilder &builder, mlir::Location loc, op.setStructured(structured); op.setImplicit(implicit); op.setDataClause(dataClause); - if (auto mappableTy = - mlir::dyn_cast(baseAddr.getType())) { - op.setVarType(baseAddr.getType()); + if (auto pointerLikeTy = + mlir::dyn_cast(baseAddr.getType())) { + op.setVarType(pointerLikeTy.getElementType()); } else { - assert(mlir::isa(baseAddr.getType()) && - "expected pointer-like"); - op.setVarType(mlir::cast(baseAddr.getType()) - .getElementType()); + assert(mlir::isa(baseAddr.getType()) && + "expected mappable"); + op.setVarType(baseAddr.getType()); } op->setAttr(Op::getOperandSegmentSizeAttr(), diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index 2ff1d6d945ba3..4a9579cfde37c 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -1533,7 +1533,9 @@ std::optional> fir::getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty, const mlir::DataLayout &dl, const fir::KindMapping &kindMap) { - if (mlir::isa(ty)) { + if (ty.isIntOrIndexOrFloat() || + mlir::isa(ty)) { llvm::TypeSize size = dl.getTypeSize(ty); unsigned short alignment = dl.getTypeABIAlignment(ty); return std::pair{size, alignment}; diff --git a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp index 317a41a2129c3..0767733f53728 100644 --- a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp +++ b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp @@ -29,8 +29,9 @@ namespace fir::acc { -static mlir::TypedValue -getPtrFromVar(mlir::Value var) { +template +mlir::TypedValue +OpenACCMappableModel::getVarPtr(mlir::Type type, mlir::Value var) const { if (auto ptr = mlir::dyn_cast>(var)) return ptr; @@ -44,34 +45,51 @@ getPtrFromVar(mlir::Value var) { return {}; } -template <> -mlir::TypedValue -OpenACCMappableModel::getVarPtr(mlir::Type type, - mlir::Value var) const { - return getPtrFromVar(var); -} - -template <> -mlir::TypedValue +template mlir::TypedValue OpenACCMappableModel::getVarPtr(mlir::Type type, - mlir::Value var) const { - return getPtrFromVar(var); -} + mlir::Value var) const; -template <> -std::optional -OpenACCMappableModel::getSizeInBytes( +template mlir::TypedValue +OpenACCMappableModel::getVarPtr(mlir::Type type, + mlir::Value var) const; + +template mlir::TypedValue +OpenACCMappableModel::getVarPtr(mlir::Type type, + mlir::Value var) const; + +template mlir::TypedValue +OpenACCMappableModel::getVarPtr(mlir::Type type, + mlir::Value var) const; + +template +std::optional OpenACCMappableModel::getSizeInBytes( mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, const mlir::DataLayout &dataLayout) const { - // TODO: Bounds operation affect the total size - add support to take them + // TODO: Bounds operation affect the size - add support to take them // into account. if (!accBounds.empty()) return {}; + // Class-type is either a polymorphic or unlimited polymorphic. In the latter + // case, the size is not computable. But in the former it should be - however, + // fir::getTypeSizeAndAlignment does not support polymorphic types. + if (mlir::isa(type)) { + return {}; + } + + // When requesting the size of a box entity or a reference, the intent + // is to get the size of the data that it is referring to. + mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); + assert(eleTy && "expect to be able to unwrap the element type"); + + // If the type enclosed is a mappable type, then have it provide the size. + if (auto mappableTy = mlir::dyn_cast(eleTy)) + return mappableTy.getSizeInBytes(var, accBounds, dataLayout); + // Dynamic extents or unknown ranks generally do not have compile-time // computable dimensions. - auto seqType = mlir::cast(type); - if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) + auto seqType = mlir::dyn_cast(eleTy); + if (seqType && (seqType.hasDynamicExtents() || seqType.hasUnknownShape())) return {}; // Attempt to find an operation that a lookup for KindMapping can be done @@ -85,99 +103,113 @@ OpenACCMappableModel::getSizeInBytes( auto kindMap = fir::getKindMapping(kindMapSrcOp); auto sizeAndAlignment = - fir::getTypeSizeAndAlignment(var.getLoc(), type, dataLayout, kindMap); + fir::getTypeSizeAndAlignment(var.getLoc(), eleTy, dataLayout, kindMap); if (!sizeAndAlignment.has_value()) return {}; return {llvm::TypeSize::getFixed(sizeAndAlignment->first)}; } -template <> -std::optional +template std::optional OpenACCMappableModel::getSizeInBytes( mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, - const mlir::DataLayout &dataLayout) const { - // If we have a box value instead of box reference, the intent is to - // get the size of the data not the box itself. - if (auto boxTy = mlir::dyn_cast(var.getType())) { - if (auto mappableTy = mlir::dyn_cast( - fir::unwrapRefType(boxTy.getEleTy()))) { - return mappableTy.getSizeInBytes(var, accBounds, dataLayout); - } - } - // Size for boxes is not computable until it gets materialized. - return {}; -} + const mlir::DataLayout &dataLayout) const; -template <> -std::optional -OpenACCMappableModel::getOffsetInBytes( +template std::optional +OpenACCMappableModel::getSizeInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +template std::optional +OpenACCMappableModel::getSizeInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +template std::optional +OpenACCMappableModel::getSizeInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +template +std::optional OpenACCMappableModel::getOffsetInBytes( mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, const mlir::DataLayout &dataLayout) const { - // TODO: Bounds operation affect the offset- add support to take them + // TODO: Bounds operation affect the offset - add support to take them // into account. if (!accBounds.empty()) return {}; + // Class-type does not behave like a normal box because it does not hold an + // element type. Thus special handle it here. + if (mlir::isa(type)) { + // The pointer to the class-type is always at the start address. + return {0}; + } + + mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); + assert(eleTy && "expect to be able to unwrap the element type"); + + // If the type enclosed is a mappable type, then have it provide the offset. + if (auto mappableTy = mlir::dyn_cast(eleTy)) + return mappableTy.getOffsetInBytes(var, accBounds, dataLayout); + // Dynamic extents (aka descriptor-based arrays) - may have a offset. // For example, a negative stride may mean a negative offset to compute the // start of array. - auto seqType = mlir::cast(type); - if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) + auto seqType = mlir::dyn_cast(eleTy); + if (seqType && (seqType.hasDynamicExtents() || seqType.hasUnknownShape())) return {}; - // We have non-dynamic extents - but if for some reason the size is not - // computable - assume offset is not either. Otherwise, it is an offset of - // zero. + // If the size is computable and since there are no bounds or dynamic extents, + // then the offset relative to pointer must be zero. if (getSizeInBytes(type, var, accBounds, dataLayout).has_value()) { return {0}; } + + // The offset is not evident because it is relative to the pointer being held. + // And we don't have any further details about this type. return {}; } -template <> -std::optional OpenACCMappableModel::getOffsetInBytes( +template std::optional +OpenACCMappableModel::getOffsetInBytes( mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, - const mlir::DataLayout &dataLayout) const { - // If we have a box value instead of box reference, the intent is to - // get the offset of the data not the offset of the box itself. - if (auto boxTy = mlir::dyn_cast(var.getType())) { - if (auto mappableTy = mlir::dyn_cast( - fir::unwrapRefType(boxTy.getEleTy()))) { - return mappableTy.getOffsetInBytes(var, accBounds, dataLayout); - } - } - // Until boxes get materialized, the offset is not evident because it is - // relative to the pointer being held. - return {}; -} + const mlir::DataLayout &dataLayout) const; -template <> -llvm::SmallVector -OpenACCMappableModel::generateAccBounds( - mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const { +template std::optional +OpenACCMappableModel::getOffsetInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +template std::optional +OpenACCMappableModel::getOffsetInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +template std::optional +OpenACCMappableModel::getOffsetInBytes( + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, + const mlir::DataLayout &dataLayout) const; + +static llvm::SmallVector +generateSeqTyAccBounds(fir::SequenceType seqType, mlir::Value var, + mlir::OpBuilder &builder) { assert((mlir::isa(var.getType()) || mlir::isa(var.getType())) && "must be pointer-like or mappable"); - fir::FirOpBuilder firBuilder(builder, var.getDefiningOp()); - auto seqType = mlir::cast(type); mlir::Location loc = var.getLoc(); - mlir::Value varPtr = - mlir::isa(var.getType()) - ? var - : mlir::cast(var.getType()).getVarPtr(var); - if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) { if (auto boxAddr = - mlir::dyn_cast_if_present(varPtr.getDefiningOp())) { + mlir::dyn_cast_if_present(var.getDefiningOp())) { mlir::Value box = boxAddr.getVal(); auto res = hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(box)); fir::ExtendedValue exv = res.first; mlir::Value boxRef = box; - if (auto boxPtr = getPtrFromVar(box)) { + if (auto boxPtr = mlir::cast(box.getType()) + .getVarPtr(box)) { boxRef = boxPtr; } // TODO: Handle Fortran optional. @@ -189,7 +221,7 @@ OpenACCMappableModel::generateAccBounds( firBuilder, loc, exv, info); } - if (mlir::isa(varPtr.getDefiningOp())) { + if (mlir::isa(var.getDefiningOp())) { mlir::Value zero = firBuilder.createIntegerConstant(loc, builder.getIndexType(), 0); mlir::Value one = @@ -197,10 +229,10 @@ OpenACCMappableModel::generateAccBounds( mlir::Value shape; if (auto declareOp = - mlir::dyn_cast_if_present(varPtr.getDefiningOp())) + mlir::dyn_cast_if_present(var.getDefiningOp())) shape = declareOp.getShape(); else if (auto declareOp = mlir::dyn_cast_if_present( - varPtr.getDefiningOp())) + var.getDefiningOp())) shape = declareOp.getShape(); const bool strideIncludeLowerExtent = true; @@ -265,9 +297,9 @@ OpenACCMappableModel::generateAccBounds( // TODO: Detect assumed-size case. const bool isAssumedSize = false; - auto valToCheck = varPtr; + auto valToCheck = var; if (auto boxAddr = - mlir::dyn_cast_if_present(varPtr.getDefiningOp())) { + mlir::dyn_cast_if_present(var.getDefiningOp())) { valToCheck = boxAddr.getVal(); } auto res = hlfir::translateToExtendedValue(loc, firBuilder, @@ -279,86 +311,34 @@ OpenACCMappableModel::generateAccBounds( /*isAssumedSize=*/isAssumedSize); } -template <> +template llvm::SmallVector -OpenACCMappableModel::generateAccBounds( - mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const { - // If we have a box value instead of box reference, the intent is to - // get the bounds of the data not the bounds of the box itself. - if (auto boxTy = mlir::dyn_cast(var.getType())) { - if (auto mappableTy = mlir::dyn_cast( - fir::unwrapRefType(boxTy.getEleTy()))) { - mlir::Value data = builder.create(var.getLoc(), var); - return mappableTy.generateAccBounds(data, builder); - } +OpenACCMappableModel::generateAccBounds(mlir::Type type, mlir::Value var, + mlir::OpBuilder &builder) const { + // acc bounds only make sense for arrays - thus look for sequence type. + mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); + if (auto seqTy = mlir::dyn_cast_if_present(eleTy)) { + return generateSeqTyAccBounds(seqTy, var, builder); } - // Box references are not arrays - thus generating acc.bounds does not make - // sense. - return {}; -} - -static bool isScalarLike(mlir::Type type) { - return fir::isa_trivial(type) || fir::isa_ref_type(type); -} - -static bool isArrayLike(mlir::Type type) { - return mlir::isa(type); -} -static bool isCompositeLike(mlir::Type type) { - // class(*) is not a composite type since it does not have a determined type. - if (fir::isUnlimitedPolymorphicType(type)) - return false; - - return mlir::isa(type); -} - -template <> -mlir::acc::VariableTypeCategory -OpenACCMappableModel::getTypeCategory( - mlir::Type type, mlir::Value var) const { - return mlir::acc::VariableTypeCategory::array; + return {}; } -template <> -mlir::acc::VariableTypeCategory -OpenACCMappableModel::getTypeCategory(mlir::Type type, - mlir::Value var) const { - // Class-type does not behave like a normal box because it does not hold an - // element type. Thus special handle it here. - if (mlir::isa(type)) { - // class(*) is not a composite type since it does not have a determined - // type. - if (fir::isUnlimitedPolymorphicType(type)) - return mlir::acc::VariableTypeCategory::uncategorized; - return mlir::acc::VariableTypeCategory::composite; - } - - mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); - assert(eleTy && "expect to be able to unwrap the element type"); +template llvm::SmallVector +OpenACCMappableModel::generateAccBounds( + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const; - // If the type enclosed by the box is a mappable type, then have it - // provide the type category. - if (auto mappableTy = mlir::dyn_cast(eleTy)) - return mappableTy.getTypeCategory(var); +template llvm::SmallVector +OpenACCMappableModel::generateAccBounds( + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const; - // For all arrays, despite whether they are allocatable, pointer, assumed, - // etc, we'd like to categorize them as "array". - if (isArrayLike(eleTy)) - return mlir::acc::VariableTypeCategory::array; - - // We got here because we don't have an array nor a mappable type. At this - // point, we know we have a type that fits the "aggregate" definition since it - // is a type with a descriptor. Try to refine it by checking if it matches the - // "composite" definition. - if (isCompositeLike(eleTy)) - return mlir::acc::VariableTypeCategory::composite; +template llvm::SmallVector +OpenACCMappableModel::generateAccBounds( + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const; - // Even if we have a scalar type - simply because it is wrapped in a box - // we want to categorize it as "nonscalar". Anything else would've been - // non-scalar anyway. - return mlir::acc::VariableTypeCategory::nonscalar; -} +template llvm::SmallVector +OpenACCMappableModel::generateAccBounds( + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const; static mlir::Value getBaseRef(mlir::TypedValue varPtr) { @@ -389,33 +369,44 @@ getBaseRef(mlir::TypedValue varPtr) { return baseRef; } -static mlir::acc::VariableTypeCategory -categorizePointee(mlir::Type pointer, - mlir::TypedValue varPtr, - mlir::Type varType) { - // FIR uses operations to compute interior pointers. - // So for example, an array element or composite field access to a float - // value would both be represented as !fir.ref. We do not want to treat - // such a reference as a scalar. Thus unwrap interior pointer calculations. - auto baseRef = getBaseRef(varPtr); +static bool isScalarLike(mlir::Type type) { + return fir::isa_trivial(type) || fir::isa_ref_type(type); +} - if (auto mappableTy = - mlir::dyn_cast(baseRef.getType())) - return mappableTy.getTypeCategory(baseRef); +static bool isArrayLike(mlir::Type type) { + return mlir::isa(type); +} - // It must be a pointer-like type since it is not a MappableType. - auto ptrLikeTy = mlir::cast(baseRef.getType()); - mlir::Type eleTy = ptrLikeTy.getElementType(); +static bool isCompositeLike(mlir::Type type) { + // class(*) is not a composite type since it does not have a determined type. + if (fir::isUnlimitedPolymorphicType(type)) + return false; - if (auto mappableEleTy = mlir::dyn_cast(eleTy)) - return mappableEleTy.getTypeCategory(varPtr); + return mlir::isa(type); +} - if (isScalarLike(eleTy)) - return mlir::acc::VariableTypeCategory::scalar; +static mlir::acc::VariableTypeCategory +categorizeElemType(mlir::Type enclosingTy, mlir::Type eleTy, mlir::Value var) { + // If the type enclosed is a mappable type, then have it provide the type + // category. + if (auto mappableTy = mlir::dyn_cast(eleTy)) + return mappableTy.getTypeCategory(var); + + // For all arrays, despite whether they are allocatable, pointer, assumed, + // etc, we'd like to categorize them as "array". if (isArrayLike(eleTy)) return mlir::acc::VariableTypeCategory::array; + if (isCompositeLike(eleTy)) return mlir::acc::VariableTypeCategory::composite; + if (mlir::isa(enclosingTy)) { + // Even if we have a scalar type - simply because it is wrapped in a box + // we want to categorize it as "nonscalar". Anything else would've been + // non-scalar anyway. + return mlir::acc::VariableTypeCategory::nonscalar; + } + if (isScalarLike(eleTy)) + return mlir::acc::VariableTypeCategory::scalar; if (mlir::isa(eleTy)) return mlir::acc::VariableTypeCategory::nonscalar; // Assumed-type (type(*))does not have a determined type that can be @@ -431,6 +422,77 @@ categorizePointee(mlir::Type pointer, return mlir::acc::VariableTypeCategory::uncategorized; } +template +mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory(mlir::Type type, + mlir::Value var) const { + // FIR uses operations to compute interior pointers. + // So for example, an array element or composite field access to a float + // value would both be represented as !fir.ref. We do not want to treat + // such a reference as a scalar. Thus unwrap interior pointer calculations. + mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); + if (eleTy && isScalarLike(eleTy)) { + if (auto ptrLikeVar = mlir::dyn_cast_if_present< + mlir::TypedValue>(var)) { + auto baseRef = getBaseRef(ptrLikeVar); + if (baseRef != var) { + type = baseRef.getType(); + if (auto mappableTy = mlir::dyn_cast(type)) + return mappableTy.getTypeCategory(baseRef); + } + } + } + + // Class-type does not behave like a normal box because it does not hold an + // element type. Thus special handle it here. + if (mlir::isa(type)) { + // class(*) is not a composite type since it does not have a determined + // type. + if (fir::isUnlimitedPolymorphicType(type)) + return mlir::acc::VariableTypeCategory::uncategorized; + return mlir::acc::VariableTypeCategory::composite; + } + + assert(eleTy && "expect to be able to unwrap the element type"); + return categorizeElemType(type, eleTy, var); +} + +template mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory(mlir::Type type, + mlir::Value var) const; + +template mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory( + mlir::Type type, mlir::Value var) const; + +template mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory(mlir::Type type, + mlir::Value var) const; + +template mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory(mlir::Type type, + mlir::Value var) const; + +static mlir::acc::VariableTypeCategory +categorizePointee(mlir::Type pointer, + mlir::TypedValue varPtr, + mlir::Type varType) { + // FIR uses operations to compute interior pointers. + // So for example, an array element or composite field access to a float + // value would both be represented as !fir.ref. We do not want to treat + // such a reference as a scalar. Thus unwrap interior pointer calculations. + auto baseRef = getBaseRef(varPtr); + + if (auto mappableTy = + mlir::dyn_cast(baseRef.getType())) + return mappableTy.getTypeCategory(baseRef); + + // It must be a pointer-like type since it is not a MappableType. + auto ptrLikeTy = mlir::cast(baseRef.getType()); + mlir::Type eleTy = ptrLikeTy.getElementType(); + return categorizeElemType(pointer, eleTy, varPtr); +} + template <> mlir::acc::VariableTypeCategory OpenACCPointerLikeModel::getPointeeTypeCategory( diff --git a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp index 5f174ad4b40fe..869f9c2429aa0 100644 --- a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp +++ b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp @@ -19,11 +19,14 @@ namespace fir::acc { void registerOpenACCExtensions(mlir::DialectRegistry ®istry) { registry.addExtension(+[](mlir::MLIRContext *ctx, fir::FIROpsDialect *dialect) { - fir::SequenceType::attachInterface>( - *ctx); fir::BoxType::attachInterface>(*ctx); fir::ClassType::attachInterface>( *ctx); + fir::ReferenceType::attachInterface< + OpenACCMappableModel>(*ctx); + fir::PointerType::attachInterface>( + *ctx); + fir::HeapType::attachInterface>(*ctx); fir::ReferenceType::attachInterface< OpenACCPointerLikeModel>(*ctx); @@ -31,6 +34,7 @@ void registerOpenACCExtensions(mlir::DialectRegistry ®istry) { OpenACCPointerLikeModel>(*ctx); fir::HeapType::attachInterface>( *ctx); + fir::LLVMPointerType::attachInterface< OpenACCPointerLikeModel>(*ctx); }); diff --git a/flang/test/Fir/OpenACC/openacc-mappable.fir b/flang/test/Fir/OpenACC/openacc-mappable.fir index 3e3e455469f69..71576f4b71075 100644 --- a/flang/test/Fir/OpenACC/openacc-mappable.fir +++ b/flang/test/Fir/OpenACC/openacc-mappable.fir @@ -23,7 +23,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec : vector<2xi64>, // CHECK: Size: 40 // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "arr", structured = false} - // CHECK: Mappable: !fir.array<10xf32> + // CHECK: Pointer-like and Mappable: !fir.ref> // CHECK: Type category: array // CHECK: Size: 40 @@ -60,20 +60,17 @@ module attributes {dlti.dl_spec = #dlti.dl_spec : vector<2xi64>, } // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "arr1", structured = false} - // CHECK: Pointer-like: !fir.ref> - // CHECK: Mappable: !fir.array + // CHECK: Pointer-like and Mappable: !fir.ref> // CHECK: Type category: array // CHECK: Bound[0]: %{{.*}} = acc.bounds lowerbound(%c0{{.*}} : index) upperbound(%{{.*}} : index) extent(%{{.*}} : index) stride(%c1{{.*}} : index) startIdx(%c1{{.*}} : index) // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "arr2", structured = false} - // CHECK: Pointer-like: !fir.ref> - // CHECK: Mappable: !fir.array + // CHECK: Pointer-like and Mappable: !fir.ref> // CHECK: Type category: array // CHECK: Bound[0]: %{{.*}} = acc.bounds lowerbound(%c0{{.*}} : index) upperbound(%{{.*}} : index) extent(%{{.*}} : index) stride(%c1{{.*}} : index) startIdx(%c2{{.*}} : index) // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "arr3", structured = false} - // CHECK: Pointer-like: !fir.ref> - // CHECK: Mappable: !fir.array<10xf32> + // CHECK: Pointer-like and Mappable: !fir.ref> // CHECK: Type category: array // CHECK: Size: 40 // CHECK: Offset: 0 diff --git a/flang/test/Fir/OpenACC/openacc-type-categories-class.f90 b/flang/test/Fir/OpenACC/openacc-type-categories-class.f90 index 58025bfa556a5..e8951cceeeaeb 100644 --- a/flang/test/Fir/OpenACC/openacc-type-categories-class.f90 +++ b/flang/test/Fir/OpenACC/openacc-type-categories-class.f90 @@ -29,13 +29,13 @@ subroutine init_unlimited(this) ! CHECK: Mappable: !fir.class> ! CHECK: Type category: composite ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "this%field", structured = false} -! CHECK: Pointer-like: !fir.ref +! CHECK: Pointer-like and Mappable: !fir.ref ! CHECK: Type category: composite ! For unlimited polymorphic entities and assumed types - they effectively have ! no declared type. Thus the type categorizer cannot categorize it. ! CHECK: Visiting: {{.*}} = acc.copyin {{.*}} {name = "var", structured = false} -! CHECK: Pointer-like: !fir.ref +! CHECK: Pointer-like and Mappable: !fir.ref ! CHECK: Type category: uncategorized ! CHECK: Visiting: {{.*}} = acc.copyin {{.*}} {name = "this", structured = false} ! CHECK: Mappable: !fir.class diff --git a/flang/test/Fir/OpenACC/openacc-type-categories.f90 b/flang/test/Fir/OpenACC/openacc-type-categories.f90 index c25c38422b755..3d6067db8224d 100644 --- a/flang/test/Fir/OpenACC/openacc-type-categories.f90 +++ b/flang/test/Fir/OpenACC/openacc-type-categories.f90 @@ -18,32 +18,32 @@ program main end program ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "scalar", structured = false} -! CHECK: Pointer-like: !fir.ref +! CHECK: Pointer-like and Mappable: !fir.ref ! CHECK: Type category: scalar ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "scalaralloc", structured = false} -! CHECK: Pointer-like: !fir.ref>> +! CHECK: Pointer-like and Mappable: !fir.ref>> ! CHECK: Type category: nonscalar ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar", structured = false} -! CHECK: Pointer-like: !fir.ref}>> +! CHECK: Pointer-like and Mappable: !fir.ref}>> ! CHECK: Type category: composite ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayconstsize", structured = false} -! CHECK: Pointer-like: !fir.ref> +! CHECK: Pointer-like and Mappable: !fir.ref> ! CHECK: Type category: array ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayalloc", structured = false} -! CHECK: Pointer-like: !fir.ref>>> +! CHECK: Pointer-like and Mappable: !fir.ref>>> ! CHECK: Type category: array ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "complexvar", structured = false} -! CHECK: Pointer-like: !fir.ref> +! CHECK: Pointer-like and Mappable: !fir.ref> ! CHECK: Type category: scalar ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "charvar", structured = false} -! CHECK: Pointer-like: !fir.ref> +! CHECK: Pointer-like and Mappable: !fir.ref> ! CHECK: Type category: nonscalar ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar%field", structured = false} -! CHECK: Pointer-like: !fir.ref +! CHECK: Pointer-like and Mappable: !fir.ref ! CHECK: Type category: composite ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar%fieldarray", structured = false} -! CHECK: Pointer-like: !fir.ref> +! CHECK: Pointer-like and Mappable: !fir.ref> ! CHECK: Type category: array ! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayconstsize(1)", structured = false} -! CHECK: Pointer-like: !fir.ref> +! CHECK: Pointer-like and Mappable: !fir.ref> ! CHECK: Type category: array diff --git a/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp index e72b96fe7cd10..de6cb1d09080d 100644 --- a/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp +++ b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp @@ -58,8 +58,18 @@ struct TestFIROpenACCInterfaces llvm::errs() << "Visiting: " << *op << "\n"; llvm::errs() << "\tVar: " << var << "\n"; - if (auto ptrTy = dyn_cast_if_present(typeOfVar)) { + if (mlir::isa(typeOfVar) && + mlir::isa(typeOfVar)) { + llvm::errs() << "\tPointer-like and Mappable: " << typeOfVar << "\n"; + } else if (mlir::isa(typeOfVar)) { llvm::errs() << "\tPointer-like: " << typeOfVar << "\n"; + } else { + assert( + mlir::isa(typeOfVar) && "expected mappable"); + llvm::errs() << "\tMappable: " << typeOfVar << "\n"; + } + + if (auto ptrTy = dyn_cast_if_present(typeOfVar)) { // If the pointee is not mappable, print details about it. Otherwise, // we defer to the mappable printing below to print those details. if (!mappableTy) { @@ -72,8 +82,6 @@ struct TestFIROpenACCInterfaces } if (mappableTy) { - llvm::errs() << "\tMappable: " << mappableTy << "\n"; - acc::VariableTypeCategory typeCategory = mappableTy.getTypeCategory(var); llvm::errs() << "\t\tType category: " << typeCategory << "\n"; diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp index 80c807e774a7e..f2eab62b286af 100644 --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -293,22 +293,15 @@ static LogicalResult checkVarAndVarType(Op op) { if (!op.getVar()) return op.emitError("must have var operand"); - if (mlir::isa(op.getVar().getType()) && - mlir::isa(op.getVar().getType())) { - // TODO: If a type implements both interfaces (mappable and pointer-like), - // it is unclear which semantics to apply without additional info which - // would need captured in the data operation. For now restrict this case - // unless a compelling reason to support disambiguating between the two. - return op.emitError("var must be mappable or pointer-like (not both)"); - } - + // A variable must have a type that is either pointer-like or mappable. if (!mlir::isa(op.getVar().getType()) && !mlir::isa(op.getVar().getType())) return op.emitError("var must be mappable or pointer-like"); - if (mlir::isa(op.getVar().getType()) && - op.getVarType() != op.getVar().getType()) - return op.emitError("varType must match when var is mappable"); + // When it is a pointer-like type, the varType must capture the target type. + if (mlir::isa(op.getVar().getType()) && + op.getVarType() == op.getVar().getType()) + return op.emitError("varType must capture the element type of var"); return success(); }