diff --git a/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h index c1bea32a2236..3e343f347e4a 100644 --- a/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h +++ b/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h @@ -18,6 +18,19 @@ namespace fir::acc { +template +struct OpenACCPointerLikeModel + : public mlir::acc::PointerLikeType::ExternalModel< + OpenACCPointerLikeModel, T> { + mlir::Type getElementType(mlir::Type pointer) const { + return mlir::cast(pointer).getElementType(); + } + mlir::acc::VariableTypeCategory + getPointeeTypeCategory(mlir::Type pointer, + mlir::TypedValue varPtr, + mlir::Type varType) const; +}; + template struct OpenACCMappableModel : public mlir::acc::MappableType::ExternalModel, @@ -36,6 +49,9 @@ struct OpenACCMappableModel llvm::SmallVector generateAccBounds(mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const; + + mlir::acc::VariableTypeCategory getTypeCategory(mlir::Type type, + mlir::Value var) const; }; } // namespace fir::acc diff --git a/flang/include/flang/Tools/PointerModels.h b/flang/include/flang/Tools/PointerModels.h index c3c0977d6e54..0d22ed3ca7f4 100644 --- a/flang/include/flang/Tools/PointerModels.h +++ b/flang/include/flang/Tools/PointerModels.h @@ -9,7 +9,6 @@ #ifndef FORTRAN_TOOLS_POINTER_MODELS_H #define FORTRAN_TOOLS_POINTER_MODELS_H -#include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" /// models for FIR pointer like types that already provide a `getElementType` @@ -24,13 +23,4 @@ struct OpenMPPointerLikeModel } }; -template -struct OpenACCPointerLikeModel - : public mlir::acc::PointerLikeType::ExternalModel< - OpenACCPointerLikeModel, T> { - mlir::Type getElementType(mlir::Type pointer) const { - return mlir::cast(pointer).getElementType(); - } -}; - #endif // FORTRAN_TOOLS_POINTER_MODELS_H diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index b7674bd093f6..622848eac2dd 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -261,12 +261,12 @@ bool CodeGenAction::beginSourceFileAction() { } // Load the MLIR dialects required by Flang - mlir::DialectRegistry registry; - mlirCtx = std::make_unique(registry); - fir::support::registerNonCodegenDialects(registry); - fir::support::loadNonCodegenDialects(*mlirCtx); + mlirCtx = std::make_unique(); fir::support::loadDialects(*mlirCtx); fir::support::registerLLVMTranslation(*mlirCtx); + mlir::DialectRegistry registry; + fir::acc::registerOpenACCExtensions(registry); + mlirCtx->appendDialectRegistry(registry); const llvm::TargetMachine &targetMachine = ci.getTargetMachine(); diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index 49f0e53fa113..719cb1b9d75a 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -1370,23 +1370,12 @@ void FIROpsDialect::registerTypes() { TypeDescType, fir::VectorType, fir::DummyScopeType>(); fir::ReferenceType::attachInterface< OpenMPPointerLikeModel>(*getContext()); - fir::ReferenceType::attachInterface< - OpenACCPointerLikeModel>(*getContext()); - fir::PointerType::attachInterface>( *getContext()); - fir::PointerType::attachInterface>( - *getContext()); - fir::HeapType::attachInterface>( *getContext()); - fir::HeapType::attachInterface>( - *getContext()); - fir::LLVMPointerType::attachInterface< OpenMPPointerLikeModel>(*getContext()); - fir::LLVMPointerType::attachInterface< - OpenACCPointerLikeModel>(*getContext()); } std::optional> diff --git a/flang/lib/Optimizer/OpenACC/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/CMakeLists.txt index 04d351ac265d..1bfae603fd80 100644 --- a/flang/lib/Optimizer/OpenACC/CMakeLists.txt +++ b/flang/lib/Optimizer/OpenACC/CMakeLists.txt @@ -6,6 +6,7 @@ add_flang_library(FIROpenACCSupport DEPENDS FIRBuilder + FIRCodeGen FIRDialect FIRDialectSupport FIRSupport @@ -14,6 +15,7 @@ add_flang_library(FIROpenACCSupport LINK_LIBS FIRBuilder + FIRCodeGen FIRDialect FIRDialectSupport FIRSupport diff --git a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp index 94ab31de1763..0ebc62e7f2fd 100644 --- a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp +++ b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp @@ -15,6 +15,7 @@ #include "flang/Optimizer/Builder/DirectivesCommon.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" +#include "flang/Optimizer/CodeGen/CGOps.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Dialect/FIRType.h" @@ -24,6 +25,7 @@ #include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/Support/LLVM.h" +#include "llvm/ADT/TypeSwitch.h" namespace fir::acc { @@ -224,4 +226,145 @@ OpenACCMappableModel::generateAccBounds( 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) { + return mlir::isa(type); +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory( + mlir::Type type, mlir::Value var) const { + return mlir::acc::VariableTypeCategory::array; +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCMappableModel::getTypeCategory(mlir::Type type, + mlir::Value var) const { + + mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type); + + // 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); + + // 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; + + // 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; +} + +static mlir::TypedValue +getBaseRef(mlir::TypedValue varPtr) { + // If there is no defining op - the unwrapped reference is the base one. + mlir::Operation *op = varPtr.getDefiningOp(); + if (!op) + return varPtr; + + // Look to find if this value originates from an interior pointer + // calculation op. + mlir::Value baseRef = + llvm::TypeSwitch(op) + .Case([&](auto op) { + // Get the base object. + return op.getMemref(); + }) + .Case([&](auto op) { + // Get the base array on which the coordinate is being applied. + return op.getMemref(); + }) + .Case([&](auto op) { + // For coordinate operation which is applied on derived type + // object, get the base object. + return op.getRef(); + }) + .Default([&](mlir::Operation *) { return varPtr; }); + + return mlir::cast>(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); + mlir::Type eleTy = baseRef.getType().getElementType(); + + if (auto mappableTy = mlir::dyn_cast(eleTy)) + return mappableTy.getTypeCategory(varPtr); + + if (isScalarLike(eleTy)) + return mlir::acc::VariableTypeCategory::scalar; + if (isArrayLike(eleTy)) + return mlir::acc::VariableTypeCategory::array; + if (isCompositeLike(eleTy)) + return mlir::acc::VariableTypeCategory::composite; + if (mlir::isa(eleTy)) + return mlir::acc::VariableTypeCategory::nonscalar; + // "pointers" - in the sense of raw address point-of-view, are considered + // scalars. However + if (mlir::isa(eleTy)) + return mlir::acc::VariableTypeCategory::scalar; + + // Without further checking, this type cannot be categorized. + return mlir::acc::VariableTypeCategory::uncategorized; +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCPointerLikeModel::getPointeeTypeCategory( + mlir::Type pointer, mlir::TypedValue varPtr, + mlir::Type varType) const { + return categorizePointee(pointer, varPtr, varType); +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCPointerLikeModel::getPointeeTypeCategory( + mlir::Type pointer, mlir::TypedValue varPtr, + mlir::Type varType) const { + return categorizePointee(pointer, varPtr, varType); +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCPointerLikeModel::getPointeeTypeCategory( + mlir::Type pointer, mlir::TypedValue varPtr, + mlir::Type varType) const { + return categorizePointee(pointer, varPtr, varType); +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCPointerLikeModel::getPointeeTypeCategory( + mlir::Type pointer, mlir::TypedValue varPtr, + mlir::Type varType) const { + return categorizePointee(pointer, varPtr, varType); +} + } // namespace fir::acc diff --git a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp index 34ea122f6b99..184a264c6432 100644 --- a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp +++ b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp @@ -22,6 +22,15 @@ void registerOpenACCExtensions(mlir::DialectRegistry ®istry) { fir::SequenceType::attachInterface>( *ctx); fir::BoxType::attachInterface>(*ctx); + + fir::ReferenceType::attachInterface< + OpenACCPointerLikeModel>(*ctx); + fir::PointerType::attachInterface< + 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 438cb29b991c..005f002c491a 100644 --- a/flang/test/Fir/OpenACC/openacc-mappable.fir +++ b/flang/test/Fir/OpenACC/openacc-mappable.fir @@ -19,7 +19,9 @@ module attributes {dlti.dl_spec = #dlti.dl_spec : vector<2xi64>, // CHECK: Visiting: %{{.*}} = acc.copyin var(%{{.*}} : !fir.box>) -> !fir.box> {name = "arr", structured = false} // CHECK: Mappable: !fir.box> +// CHECK: Type category: array // CHECK: Size: 40 // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "arr", structured = false} // CHECK: Mappable: !fir.array<10xf32> +// CHECK: Type category: array // CHECK: Size: 40 diff --git a/flang/test/Fir/OpenACC/openacc-type-categories.f90 b/flang/test/Fir/OpenACC/openacc-type-categories.f90 new file mode 100644 index 000000000000..c25c38422b75 --- /dev/null +++ b/flang/test/Fir/OpenACC/openacc-type-categories.f90 @@ -0,0 +1,49 @@ +! RUN: bbc -fopenacc -emit-hlfir %s -o - | fir-opt -pass-pipeline='builtin.module(test-fir-openacc-interfaces)' --mlir-disable-threading 2>&1 | FileCheck %s + +program main + real :: scalar + real, allocatable :: scalaralloc + type tt + real :: field + real :: fieldarray(10) + end type tt + type(tt) :: ttvar + real :: arrayconstsize(10) + real, allocatable :: arrayalloc(:) + complex :: complexvar + character*1 :: charvar + + !$acc enter data copyin(scalar, scalaralloc, ttvar, arrayconstsize, arrayalloc) + !$acc enter data copyin(complexvar, charvar, ttvar%field, ttvar%fieldarray, arrayconstsize(1)) +end program + +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "scalar", structured = false} +! CHECK: Pointer-like: !fir.ref +! CHECK: Type category: scalar +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "scalaralloc", structured = false} +! CHECK: Pointer-like: !fir.ref>> +! CHECK: Type category: nonscalar +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar", structured = false} +! CHECK: Pointer-like: !fir.ref}>> +! CHECK: Type category: composite +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayconstsize", structured = false} +! CHECK: Pointer-like: !fir.ref> +! CHECK: Type category: array +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayalloc", structured = false} +! CHECK: Pointer-like: !fir.ref>>> +! CHECK: Type category: array +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "complexvar", structured = false} +! CHECK: Pointer-like: !fir.ref> +! CHECK: Type category: scalar +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "charvar", structured = false} +! CHECK: Pointer-like: !fir.ref> +! CHECK: Type category: nonscalar +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar%field", structured = false} +! CHECK: Pointer-like: !fir.ref +! CHECK: Type category: composite +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "ttvar%fieldarray", structured = false} +! CHECK: Pointer-like: !fir.ref> +! CHECK: Type category: array +! CHECK: Visiting: {{.*}} acc.copyin {{.*}} {name = "arrayconstsize(1)", structured = false} +! CHECK: Pointer-like: !fir.ref> +! CHECK: Type category: array diff --git a/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp index 5c14809a265e..90aabd7d40d4 100644 --- a/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp +++ b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp @@ -32,15 +32,43 @@ struct TestFIROpenACCInterfaces mlir::OpBuilder builder(mod); getOperation().walk([&](Operation *op) { if (isa(op)) { - Type typeOfVar = acc::getVar(op).getType(); - llvm::errs() << "Visiting: " << *op << "\n"; + Value var = acc::getVar(op); + Type typeOfVar = var.getType(); + + // Attempt to determine if the variable is mappable-like or if + // the pointee itself is mappable-like. For example, if the variable is + // of type !fir.ref>, we want to print both the details about + // the !fir.ref since it is pointer-like, and about !fir.box since it + // is mappable. auto mappableTy = dyn_cast_if_present(typeOfVar); if (!mappableTy) { mappableTy = dyn_cast_if_present(acc::getVarType(op)); } + + llvm::errs() << "Visiting: " << *op << "\n"; + llvm::errs() << "\tVar: " << var << "\n"; + + if (auto ptrTy = dyn_cast_if_present(typeOfVar)) { + llvm::errs() << "\tPointer-like: " << typeOfVar << "\n"; + // If the pointee is not mappable, print details about it. Otherwise, + // we defer to the mappable printing below to print those details. + if (!mappableTy) { + acc::VariableTypeCategory typeCategory = + ptrTy.getPointeeTypeCategory( + cast>(var), + acc::getVarType(op)); + llvm::errs() << "\t\tType category: " << typeCategory << "\n"; + } + } + if (mappableTy) { llvm::errs() << "\tMappable: " << mappableTy << "\n"; + + acc::VariableTypeCategory typeCategory = + mappableTy.getTypeCategory(var); + llvm::errs() << "\t\tType category: " << typeCategory << "\n"; + if (datalayout.has_value()) { auto size = mappableTy.getSizeInBytes( acc::getVar(op), acc::getBounds(op), datalayout.value()); @@ -61,10 +89,6 @@ struct TestFIROpenACCInterfaces llvm::errs() << "\t\tBound[" << idx << "]: " << bound << "\n"; } } - } else { - assert(acc::isPointerLikeType(typeOfVar) && - "expected to be pointer-like"); - llvm::errs() << "\tPointer-like: " << typeOfVar << "\n"; } } });