diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h index 8e0f3da22ba9..745c8686457f 100644 --- a/flang/include/flang/Lower/OpenACC.h +++ b/flang/include/flang/Lower/OpenACC.h @@ -86,26 +86,6 @@ void genOpenACCRoutineConstruct( AbstractConverter &, mlir::ModuleOp, mlir::func::FuncOp, const std::vector &); -/// Get a acc.private.recipe op for the given type or create it if it does not -/// exist yet. -mlir::acc::PrivateRecipeOp -createOrGetPrivateRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location, - mlir::Type, - llvm::SmallVector &dataOperationBounds); - -/// Get a acc.reduction.recipe op for the given type or create it if it does not -/// exist yet. -mlir::acc::ReductionRecipeOp -createOrGetReductionRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location, - mlir::Type, mlir::acc::ReductionOperator, - llvm::SmallVector &dataOperationBounds); - -/// Get a acc.firstprivate.recipe op for the given type or create it if it does -/// not exist yet. -mlir::acc::FirstprivateRecipeOp createOrGetFirstprivateRecipe( - fir::FirOpBuilder &, llvm::StringRef, mlir::Location, mlir::Type, - llvm::SmallVector &dataOperationBounds); - void attachDeclarePostAllocAction(AbstractConverter &, fir::FirOpBuilder &, const Fortran::semantics::Symbol &); void attachDeclarePreDeallocAction(AbstractConverter &, fir::FirOpBuilder &, diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.h b/flang/include/flang/Optimizer/Dialect/FIRAttr.h index 06ec1f57173c..ec6b7ff48329 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h @@ -13,6 +13,7 @@ #ifndef FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H #define FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H +#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h" #include "mlir/IR/BuiltinAttributes.h" namespace mlir { diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td index b23d28fdde55..3bb1f443f3a5 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td @@ -14,6 +14,7 @@ #define FIR_DIALECT_FIR_ATTRS include "flang/Optimizer/Dialect/FIRDialect.td" +include "mlir/Dialect/OpenACC/OpenACCAttributes.td" include "mlir/IR/EnumAttr.td" class fir_Attr : AttrDef; @@ -262,4 +263,16 @@ def fir_UseRenameAttr : fir_Attr<"UseRename"> { let assemblyFormat = "`<` $local_name `,` $symbol `>`"; } +// Fortran-specific variable information for OpenACC. +// Carries metadata that cannot be recovered from the FIR type system alone +// and is required in the FIR implementation of OpenACC type interfaces. +def fir_OpenACCFortranVariableInfoAttr + : AttrDef { + let mnemonic = "acc_var_info"; + let parameters = (ins "bool":$mayBeOptional); + let assemblyFormat = "`<` struct(params) `>`"; +} + #endif // FIR_DIALECT_FIR_ATTRS diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h index 9d952a6130f0..01a1e19afd74 100644 --- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h +++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h @@ -80,22 +80,29 @@ struct OpenACCMappableModel mlir::acc::VariableTypeCategory getTypeCategory(mlir::Type type, mlir::Value var) const; + mlir::acc::VariableInfoAttr + genPrivateVariableInfo(mlir::Type type, + mlir::TypedValue var) const; + mlir::Value generatePrivateInit(mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, mlir::ValueRange extents, mlir::Value initVal, + mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const; bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::Value privatized, - mlir::ValueRange bounds) const; + mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; bool generateCopy(mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::TypedValue source, mlir::TypedValue dest, - mlir::ValueRange bounds) const; + mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; bool generateCombiner(mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc, diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h index 360f4eb000a9..a8b9bcf5cfd4 100644 --- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h +++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h @@ -60,7 +60,7 @@ bool areAllBoundsConstant(llvm::ArrayRef bounds); /// \return The existing or created PrivateRecipeOp symbol mlir::SymbolRefAttr createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::Location loc, - mlir::Type ty, + mlir::Value var, llvm::SmallVector &dataBoundOps); /// Create or get a firstprivate recipe for the given type and name. @@ -71,7 +71,7 @@ createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::Location loc, /// \return The existing or created FirstprivateRecipeOp symbol mlir::SymbolRefAttr createOrGetFirstprivateRecipe(mlir::OpBuilder &builder, mlir::Location loc, - mlir::Type ty, + mlir::Value var, llvm::SmallVector &dataBoundOps); /// Create or get a reduction recipe for the given type, name and operator. @@ -84,7 +84,7 @@ createOrGetFirstprivateRecipe(mlir::OpBuilder &builder, mlir::Location loc, /// \return The existing or created ReductionRecipeOp symbol mlir::SymbolRefAttr createOrGetReductionRecipe(mlir::OpBuilder &builder, mlir::Location loc, - mlir::Type ty, mlir::acc::ReductionOperator op, + mlir::Value var, mlir::acc::ReductionOperator op, llvm::SmallVector &dataBoundOps, mlir::Attribute fastMathAttr = {}); diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 51bc7597b5c9..2154f38dca56 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -789,11 +789,11 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList, // For private/firstprivate, attach (and optionally record) the recipe. if constexpr (std::is_same_v) { mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetPrivateRecipe( - builder, operandLocation, baseAddr.getType(), bounds); + builder, operandLocation, baseAddr, bounds); op.setRecipeAttr(recipeAttr); } else if constexpr (std::is_same_v) { mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetFirstprivateRecipe( - builder, operandLocation, baseAddr.getType(), bounds); + builder, operandLocation, baseAddr, bounds); op.setRecipeAttr(recipeAttr); } } @@ -1176,13 +1176,12 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, /*structured=*/true, /*implicit=*/false, mlir::acc::DataClause::acc_reduction, info.addr.getType(), async, asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true); - mlir::Type ty = op.getAccVar().getType(); mlir::Attribute fastMathAttr; if (builder.getFastMathFlags() != mlir::arith::FastMathFlags::none) fastMathAttr = mlir::arith::FastMathFlagsAttr::get( builder.getContext(), builder.getFastMathFlags()); mlir::SymbolRefAttr recipe = fir::acc::createOrGetReductionRecipe( - builder, operandLocation, ty, mlirOp, bounds, fastMathAttr); + builder, operandLocation, info.addr, mlirOp, bounds, fastMathAttr); op.setRecipeAttr(recipe); reductionOperands.push_back(op.getAccVar()); // Track the symbol and its corresponding mlir::Value if requested so that @@ -1427,8 +1426,8 @@ static void privatizeIv( if (privateOp == nullptr) { llvm::SmallVector noBounds; - mlir::SymbolRefAttr recipe = fir::acc::createOrGetPrivateRecipe( - builder, loc, ivValue.getType(), noBounds); + mlir::SymbolRefAttr recipe = + fir::acc::createOrGetPrivateRecipe(builder, loc, ivValue, noBounds); std::stringstream asFortran; asFortran << Fortran::lower::mangle::demangleName(toStringRef(sym.name())); diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp index 5d427c9aab8a..25af35513d18 100644 --- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp +++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp @@ -542,6 +542,30 @@ template mlir::acc::VariableTypeCategory OpenACCMappableModel::getTypeCategory(mlir::Type type, mlir::Value var) const; +template +mlir::acc::VariableInfoAttr OpenACCMappableModel::genPrivateVariableInfo( + mlir::Type type, mlir::TypedValue var) const { + hlfir::Entity entity{var}; + return fir::OpenACCFortranVariableInfoAttr::get(var.getContext(), + entity.mayBeOptional()); +} + +template mlir::acc::VariableInfoAttr +OpenACCMappableModel::genPrivateVariableInfo( + mlir::Type type, mlir::TypedValue var) const; + +template mlir::acc::VariableInfoAttr +OpenACCMappableModel::genPrivateVariableInfo( + mlir::Type type, mlir::TypedValue var) const; + +template mlir::acc::VariableInfoAttr +OpenACCMappableModel::genPrivateVariableInfo( + mlir::Type type, mlir::TypedValue var) const; + +template mlir::acc::VariableInfoAttr +OpenACCMappableModel::genPrivateVariableInfo( + mlir::Type type, mlir::TypedValue var) const; + static mlir::acc::VariableTypeCategory categorizePointee(mlir::Type pointer, mlir::TypedValue varPtr, @@ -717,7 +741,8 @@ template mlir::Value OpenACCMappableModel::generatePrivateInit( mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, - mlir::ValueRange bounds, mlir::Value initVal, bool &needsDestroy) const { + mlir::ValueRange bounds, mlir::Value initVal, mlir::acc::VariableInfoAttr, + bool &needsDestroy) const { mlir::ModuleOp mod = mlirBuilder.getInsertionBlock() ->getParent() ->getParentOfType(); @@ -900,31 +925,35 @@ template mlir::Value OpenACCMappableModel::generatePrivateInit( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, - mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const; + mlir::ValueRange extents, mlir::Value initVal, + mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const; template mlir::Value OpenACCMappableModel::generatePrivateInit( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, - mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const; + mlir::ValueRange extents, mlir::Value initVal, + mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const; template mlir::Value OpenACCMappableModel::generatePrivateInit( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, - mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const; + mlir::ValueRange extents, mlir::Value initVal, + mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const; template mlir::Value OpenACCMappableModel::generatePrivateInit( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, mlir::TypedValue var, llvm::StringRef varName, - mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const; + mlir::ValueRange extents, mlir::Value initVal, + mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const; template bool OpenACCMappableModel::generateCopy( mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::TypedValue src, - mlir::TypedValue dest, - mlir::ValueRange bounds) const { + mlir::TypedValue dest, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const { mlir::ModuleOp mod = mlirBuilder.getBlock()->getParent()->getParentOfType(); assert(mod && "failed to retrieve parent module"); @@ -961,19 +990,23 @@ bool OpenACCMappableModel::generateCopy( template bool OpenACCMappableModel::generateCopy( mlir::Type, mlir::OpBuilder &, mlir::Location, mlir::TypedValue, - mlir::TypedValue, mlir::ValueRange) const; + mlir::TypedValue, mlir::ValueRange, + mlir::acc::VariableInfoAttr) const; template bool OpenACCMappableModel::generateCopy( mlir::Type, mlir::OpBuilder &, mlir::Location, mlir::TypedValue, - mlir::TypedValue, mlir::ValueRange) const; + mlir::TypedValue, mlir::ValueRange, + mlir::acc::VariableInfoAttr) const; template bool OpenACCMappableModel::generateCopy( mlir::Type, mlir::OpBuilder &, mlir::Location, mlir::TypedValue, - mlir::TypedValue, mlir::ValueRange) const; + mlir::TypedValue, mlir::ValueRange, + mlir::acc::VariableInfoAttr) const; template bool OpenACCMappableModel::generateCopy( mlir::Type, mlir::OpBuilder &, mlir::Location, mlir::TypedValue, - mlir::TypedValue, mlir::ValueRange) const; + mlir::TypedValue, mlir::ValueRange, + mlir::acc::VariableInfoAttr) const; template static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder, @@ -1175,7 +1208,8 @@ template bool OpenACCMappableModel::generateCombiner( template bool OpenACCMappableModel::generatePrivateDestroy( mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc, - mlir::Value privatized, mlir::ValueRange bounds) const { + mlir::Value privatized, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const { hlfir::Entity inputVar = hlfir::Entity{privatized}; mlir::ModuleOp mod = mlirBuilder.getBlock()->getParent()->getParentOfType(); @@ -1210,16 +1244,20 @@ bool OpenACCMappableModel::generatePrivateDestroy( template bool OpenACCMappableModel::generatePrivateDestroy( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, - mlir::Value privatized, mlir::ValueRange bounds) const; + mlir::Value privatized, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; template bool OpenACCMappableModel::generatePrivateDestroy( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, - mlir::Value privatized, mlir::ValueRange bounds) const; + mlir::Value privatized, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; template bool OpenACCMappableModel::generatePrivateDestroy( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, - mlir::Value privatized, mlir::ValueRange bounds) const; + mlir::Value privatized, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; template bool OpenACCMappableModel::generatePrivateDestroy( mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc, - mlir::Value privatized, mlir::ValueRange bounds) const; + mlir::Value privatized, mlir::ValueRange bounds, + mlir::acc::VariableInfoAttr varInfo) const; template mlir::Value OpenACCPointerLikeModel::genAllocate( diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp index 3a8f548fefdf..519978dba1af 100644 --- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp +++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp @@ -14,6 +14,7 @@ #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Dialect/FIRType.h" @@ -229,6 +230,7 @@ static std::string getBoundsString(llvm::ArrayRef bounds) { } static std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, + mlir::acc::VariableInfoAttr varInfo, const fir::KindMapping &kindMap, llvm::ArrayRef bounds, mlir::acc::ReductionOperator reductionOp = @@ -256,19 +258,33 @@ static std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, break; } + if (auto fortranVarInfo = + mlir::dyn_cast_if_present( + varInfo)) + if (fortranVarInfo.getMayBeOptional()) + prefixOS << "_optional"; + if (!bounds.empty()) prefixOS << getBoundsString(bounds); return fir::getTypeAsString(type, kindMap, prefixOS.str()); } +using MappableValue = mlir::TypedValue; + std::string fir::acc::getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var, llvm::ArrayRef bounds, mlir::acc::ReductionOperator reductionOp) { auto kindMap = var && var.getDefiningOp() ? fir::getKindMapping(var.getDefiningOp()) : fir::KindMapping(type.getContext()); - return ::getRecipeName(kind, type, kindMap, bounds, reductionOp); + mlir::acc::VariableInfoAttr varInfo; + if (var) + if (auto mappableTy = + mlir::dyn_cast(var.getType())) + varInfo = + mappableTy.genPrivateVariableInfo(mlir::cast(var)); + return ::getRecipeName(kind, type, varInfo, kindMap, bounds, reductionOp); } /// Map acc::ReductionOperator to arith::AtomicRMWKind for identity value @@ -397,8 +413,6 @@ static void addRecipeBoundsArgs(llvm::SmallVector &bounds, } } -using MappableValue = mlir::TypedValue; - // Generate the combiner or copy region block and block arguments and return the // source and destination entities. static std::pair @@ -420,7 +434,7 @@ genRecipeCombinerOrCopyRegion(fir::FirOpBuilder &builder, mlir::Location loc, template static RecipeOp genRecipeOp( fir::FirOpBuilder &builder, mlir::ModuleOp mod, llvm::StringRef recipeName, - mlir::Location loc, mlir::Type ty, + mlir::Location loc, mlir::Type ty, mlir::acc::VariableInfoAttr varInfo, llvm::SmallVector &dataOperationBounds, bool allConstantBound, mlir::acc::ReductionOperator op = mlir::acc::ReductionOperator::AccNone) { mlir::OpBuilder modBuilder(mod.getBodyRegion()); @@ -459,13 +473,14 @@ static RecipeOp genRecipeOp( auto mappableTy = mlir::dyn_cast(ty); assert(mappableTy && "Expected that all variable types are considered mappable"); + auto initArg = mlir::cast(initBlock->getArgument(0)); bool needsDestroy = false; llvm::SmallVector initBounds = getRecipeBounds(builder, loc, dataOperationBounds, initBlock->getArguments().drop_front(1)); mlir::Value retVal = mappableTy.generatePrivateInit( - builder, loc, mlir::cast(initBlock->getArgument(0)), - initName, initBounds, initValue, needsDestroy); + builder, loc, initArg, initName, initBounds, initValue, varInfo, + needsDestroy); mlir::acc::YieldOp::create(builder, loc, retVal); // Create destroy region and generate destruction if requested. if (needsDestroy) { @@ -491,7 +506,7 @@ static RecipeOp genRecipeOp( getRecipeBounds(builder, loc, dataOperationBounds, destroyBlock->getArguments().drop_front(2)); [[maybe_unused]] bool success = mappableTy.generatePrivateDestroy( - builder, loc, destroyBlock->getArgument(1), destroyBounds); + builder, loc, destroyBlock->getArgument(1), destroyBounds, varInfo); assert(success && "failed to generate destroy region"); mlir::acc::TerminatorOp::create(builder, loc); } @@ -500,31 +515,44 @@ static RecipeOp genRecipeOp( mlir::SymbolRefAttr fir::acc::createOrGetPrivateRecipe(mlir::OpBuilder &mlirBuilder, - mlir::Location loc, mlir::Type ty, + mlir::Location loc, mlir::Value var, llvm::SmallVector &bounds) { + mlir::Type ty = var.getType(); mlir::ModuleOp mod = mlirBuilder.getBlock()->getParent()->getParentOfType(); fir::FirOpBuilder builder(mlirBuilder, mod); - std::string recipeName = ::getRecipeName( - mlir::acc::RecipeKind::private_recipe, ty, builder.getKindMap(), bounds); + auto mappableTy = mlir::dyn_cast(ty); + assert(mappableTy && + "Expected that all variable types are considered mappable"); + mlir::acc::VariableInfoAttr varInfo = + mappableTy.genPrivateVariableInfo(mlir::cast(var)); + std::string recipeName = + ::getRecipeName(mlir::acc::RecipeKind::private_recipe, ty, varInfo, + builder.getKindMap(), bounds); if (auto recipe = mod.lookupSymbol(recipeName)) return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); mlir::OpBuilder::InsertionGuard guard(builder); bool allConstantBound = fir::acc::areAllBoundsConstant(bounds); auto recipe = genRecipeOp( - builder, mod, recipeName, loc, ty, bounds, allConstantBound); + builder, mod, recipeName, loc, ty, varInfo, bounds, allConstantBound); return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); } mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe( - mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty, + mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Value var, llvm::SmallVector &dataBoundOps) { + mlir::Type ty = var.getType(); mlir::ModuleOp mod = mlirBuilder.getBlock()->getParent()->getParentOfType(); fir::FirOpBuilder builder(mlirBuilder, mod); + auto mappableTy = mlir::dyn_cast(ty); + assert(mappableTy && + "Expected that all variable types are considered mappable"); + mlir::acc::VariableInfoAttr varInfo = + mappableTy.genPrivateVariableInfo(mlir::cast(var)); std::string recipeName = - ::getRecipeName(mlir::acc::RecipeKind::firstprivate_recipe, ty, + ::getRecipeName(mlir::acc::RecipeKind::firstprivate_recipe, ty, varInfo, builder.getKindMap(), dataBoundOps); if (auto recipe = mod.lookupSymbol(recipeName)) @@ -533,33 +561,37 @@ mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe( mlir::OpBuilder::InsertionGuard guard(builder); bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps); auto recipe = genRecipeOp( - builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound); + builder, mod, recipeName, loc, ty, varInfo, dataBoundOps, + allConstantBound); auto [source, destination] = genRecipeCombinerOrCopyRegion( builder, loc, ty, recipe.getCopyRegion(), dataBoundOps, allConstantBound); llvm::SmallVector copyBounds = getRecipeBounds(builder, loc, dataBoundOps, recipe.getCopyRegion().getArguments().drop_front(2)); - auto mappableTy = mlir::dyn_cast(ty); - assert(mappableTy && - "Expected that all variable types are considered mappable"); - [[maybe_unused]] bool success = - mappableTy.generateCopy(builder, loc, source, destination, copyBounds); + [[maybe_unused]] bool success = mappableTy.generateCopy( + builder, loc, source, destination, copyBounds, varInfo); assert(success && "failed to generate copy"); mlir::acc::TerminatorOp::create(builder, loc); return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); } mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe( - mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty, + mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Value var, mlir::acc::ReductionOperator op, llvm::SmallVector &dataBoundOps, mlir::Attribute fastMathAttr) { + mlir::Type ty = var.getType(); mlir::ModuleOp mod = mlirBuilder.getBlock()->getParent()->getParentOfType(); fir::FirOpBuilder builder(mlirBuilder, mod); + auto mappableTy = mlir::dyn_cast(ty); + assert(mappableTy && + "Expected that all variable types are considered mappable"); + mlir::acc::VariableInfoAttr varInfo = + mappableTy.genPrivateVariableInfo(mlir::cast(var)); std::string recipeName = - ::getRecipeName(mlir::acc::RecipeKind::reduction_recipe, ty, + ::getRecipeName(mlir::acc::RecipeKind::reduction_recipe, ty, varInfo, builder.getKindMap(), dataBoundOps, op); if (auto recipe = mod.lookupSymbol(recipeName)) return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); @@ -567,7 +599,8 @@ mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe( mlir::OpBuilder::InsertionGuard guard(builder); bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps); auto recipe = genRecipeOp( - builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound, op); + builder, mod, recipeName, loc, ty, varInfo, dataBoundOps, + allConstantBound, op); auto [dest, source] = genRecipeCombinerOrCopyRegion( builder, loc, ty, recipe.getCombinerRegion(), dataBoundOps, @@ -576,9 +609,6 @@ mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe( getRecipeBounds(builder, loc, dataBoundOps, recipe.getCombinerRegion().getArguments().drop_front(2)); - auto mappableTy = mlir::dyn_cast(ty); - assert(mappableTy && - "Expected that all variable types are considered mappable"); [[maybe_unused]] bool success = mappableTy.generateCombiner( builder, loc, dest, source, combinerBounds, op, fastMathAttr); assert(success && "failed to generate combiner"); diff --git a/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90 b/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90 new file mode 100644 index 000000000000..876495bebaab --- /dev/null +++ b/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90 @@ -0,0 +1,13 @@ +! Test handling of OPTIONAL in data directives +! RUN: %flang_fc1 -fopenacc -emit-hlfir %s -o - | FileCheck %s + +subroutine test(x) + real, optional :: x(100) + !$acc parallel firstprivate(x) + call foo(x) + !$acc end parallel +end subroutine + +! CHECK: acc.firstprivate.recipe @firstprivatization_optional_ref_100xf32 + +! TODO: generate conditional copy diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h index 55fc8251a9bb..9e7a15feb2e7 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h @@ -13,6 +13,7 @@ #ifndef MLIR_DIALECT_OPENACC_OPENACC_H_ #define MLIR_DIALECT_OPENACC_OPENACC_H_ +#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/OpDefinition.h" diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td new file mode 100644 index 000000000000..f533fb42546f --- /dev/null +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td @@ -0,0 +1,24 @@ +//===- OpenACCAttributes.td - OpenACC Attributes -----------*- tablegen -*-===// +// +// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines OpenACC Attributes that can be extended by the dialects outside of +// of OpenACC. +// +//===----------------------------------------------------------------------===// + +#ifndef OPENACC_ATTRIBUTES +#define OPENACC_ATTRIBUTES + +include "mlir/IR/AttrTypeBase.td" + +// Trait for attributes that carry OpenACC variable information. +def OpenACC_IsVariableInfoAttr : NativeAttrTrait<"IsVariableInfo"> { + let cppNamespace = "::mlir::acc::AttributeTrait"; +} + +#endif // OPENACC_ATTRIBUTES diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td index c8030b14e96c..32ecaa6bc2d4 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -20,6 +20,7 @@ include "mlir/IR/BuiltinTypes.td" include "mlir/IR/EnumAttr.td" include "mlir/IR/OpBase.td" include "mlir/IR/SymbolInterfaces.td" +include "mlir/Dialect/OpenACC/OpenACCAttributes.td" include "mlir/Dialect/OpenACC/OpenACCBase.td" include "mlir/Dialect/OpenACC/OpenACCOpsTypes.td" include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.td" @@ -1444,11 +1445,13 @@ def OpenACC_PrivateRecipeOp /// and it must be a valid place for this operation to be inserted. The /// `recipeName` must be a unique name to prevent "redefinition of symbol" /// IR errors. + /// The `hostVar` is the original host variable from which the type and + /// language-specific metadata are derived. static std::optional createAndPopulate( ::mlir::OpBuilder &builder, ::mlir::Location loc, ::llvm::StringRef recipeName, - ::mlir::Type varType, + ::mlir::Value hostVar, ::llvm::StringRef varName = "", ::mlir::ValueRange bounds = {}); @@ -1569,11 +1572,13 @@ def OpenACC_FirstprivateRecipeOp /// and it must be a valid place for this operation to be inserted. The /// `recipeName` must be a unique name to prevent "redefinition of symbol" /// IR errors. + /// The `hostVar` is the original host variable from which the type and + /// language-specific metadata are derived. static std::optional createAndPopulate( ::mlir::OpBuilder &builder, ::mlir::Location loc, ::llvm::StringRef recipeName, - ::mlir::Type varType, + ::mlir::Value hostVar, ::llvm::StringRef varName = "", ::mlir::ValueRange bounds = {}); }]; diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td index 97def012990c..3bd4e5c67965 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td @@ -354,6 +354,26 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { return ::mlir::acc::VariableTypeCategory::uncategorized; }] >, + InterfaceMethod< + /*description=*/[{ + Produces a `VariableInfo` for a host variable. This enables passing + language-specific metadata (that is not captured in the type system) + to recipe code-generation helpers such as `generatePrivateInit`, + `generateCopy`, and `generatePrivateDestroy`. + + The `var` is the host variable from which to extract information. + Implementations may use `getDefiningOp()` on this value. + + The default implementation returns a null `VariableInfo`. + }], + /*retTy=*/"::mlir::acc::VariableInfoAttr", + /*methodName=*/"genPrivateVariableInfo", + /*args=*/(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return ::mlir::acc::VariableInfoAttr(); + }] + >, InterfaceMethod< /*description=*/[{ Generates the operations that would be normally placed in a recipe's @@ -368,6 +388,10 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { The `initVal` can be empty - it is primarily needed for reductions to ensure the variable is also initialized with appropriate value. + The `varInfo` carries language-specific metadata about the original + host variable (produced by `genPrivateVariableInfo`). Implementations + can `dyn_cast` to their language-specific subclass. + The `needsDestroy` out-parameter is set by implementations to indicate that destruction code must be generated after the returned private variable usages, typically in the destroy region of recipe operations @@ -387,6 +411,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { "::llvm::StringRef":$varName, "::mlir::ValueRange":$extents, "::mlir::Value":$initVal, + "::mlir::acc::VariableInfoAttr":$varInfo, "bool &":$needsDestroy), /*methodBody=*/"", /*defaultImplementation=*/[{ @@ -395,6 +420,12 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { >, InterfaceMethod< /*description=*/[{ + Generates copy operations from one mappable variable to another. + Typically used to implement firstprivate initialization. + + The `varInfo` carries language-specific metadata about the original + host variable (produced by `genPrivateVariableInfo`). Implementations + can `dyn_cast` to their language-specific subclass. }], /*retTy=*/"bool", /*methodName=*/"generateCopy", @@ -402,7 +433,8 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { "::mlir::Location":$loc, "::mlir::TypedValue<::mlir::acc::MappableType>":$from, "::mlir::TypedValue<::mlir::acc::MappableType>":$to, - "::mlir::ValueRange":$bounds), + "::mlir::ValueRange":$bounds, + "::mlir::acc::VariableInfoAttr":$varInfo), /*methodBody=*/"", /*defaultImplementation=*/[{ return false; @@ -438,7 +470,11 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { this function should be a no-op and return `true`. The `bounds` must be passed when only a section of the variable was - privatized. + privatized. + + The `varInfo` carries language-specific metadata about the original + host variable (produced by `genPrivateVariableInfo`). Implementations + can `dyn_cast` to their language-specific subclass. Returns true if destruction was successfully generated or deemed not necessary, false otherwise. @@ -448,7 +484,8 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> { /*args=*/(ins "::mlir::OpBuilder &":$builder, "::mlir::Location":$loc, "::mlir::Value":$privatized, - "::mlir::ValueRange":$extents), + "::mlir::ValueRange":$extents, + "::mlir::acc::VariableInfoAttr":$varInfo), /*methodBody=*/"", /*defaultImplementation=*/[{ return true; diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h new file mode 100644 index 000000000000..95009fdb53fb --- /dev/null +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h @@ -0,0 +1,46 @@ +//===- OpenACCVariableInfo.h - OpenACC Variable Info Attr -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the VariableInfoAttr base class and the IsVariableInfo +// trait. +// +// Any dialect can define Language-specific variable metadata attribute by +// manually attaching the IsVariableInfo trait and using VariableInfoAttr as +// the baseCppClass. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H +#define MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H + +#include "mlir/IR/Attributes.h" + +namespace mlir { +namespace acc { +namespace AttributeTrait { +/// Trait attached to attributes that are OpenACC variable info attributes. +template +struct IsVariableInfo + : public mlir::AttributeTrait::TraitBase {}; +} // namespace AttributeTrait + +/// Base attribute class for language-specific variable information carried +/// through the OpenACC type interface helpers. +class VariableInfoAttr : public mlir::Attribute { +public: + using Attribute::Attribute; + + static bool classof(mlir::Attribute attr) { + return attr.hasTrait<::mlir::acc::AttributeTrait::IsVariableInfo>(); + } +}; + +} // namespace acc +} // namespace mlir + +#endif // MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp index 0709b9ebb95a..28138fd906d6 100644 --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -1543,10 +1543,16 @@ struct RemoveConstantIfConditionWithRegion : public OpRewritePattern { /// Create and populate an init region for privatization recipes. /// Returns success if the region is populated, failure otherwise. /// Sets needsFree to indicate if the allocated memory requires deallocation. +/// The `hostVar` is the original host variable used to derive +/// language-specific metadata via `genPrivateVariableInfo`. +/// The `varInfo` output parameter is set to the variable info produced. static LogicalResult createInitRegion(OpBuilder &builder, Location loc, - Region &initRegion, Type varType, + Region &initRegion, Value hostVar, StringRef varName, ValueRange bounds, - bool &needsFree) { + bool &needsFree, + acc::VariableInfoAttr &varInfo) { + Type varType = hostVar.getType(); + // Create init block with arguments: original value + bounds SmallVector argTypes{varType}; SmallVector argLocs{loc}; @@ -1568,8 +1574,10 @@ static LogicalResult createInitRegion(OpBuilder &builder, Location loc, if (isa(varType)) { auto mappableTy = cast(varType); auto typedVar = cast>(blockArgVar); + auto typedHostVar = cast>(hostVar); + varInfo = mappableTy.genPrivateVariableInfo(typedHostVar); privatizedValue = mappableTy.generatePrivateInit( - builder, loc, typedVar, varName, bounds, {}, needsFree); + builder, loc, typedVar, varName, bounds, {}, varInfo, needsFree); if (!privatizedValue) return failure(); } else { @@ -1635,9 +1643,12 @@ static LogicalResult createCopyRegion(OpBuilder &builder, Location loc, /// Create and populate a destroy region for privatization recipes. /// Returns success if the region is populated, failure otherwise. +/// The `varInfo` carries language-specific metadata produced by +/// `createInitRegion`. static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc, Region &destroyRegion, Type varType, - Value allocRes, ValueRange bounds) { + Value allocRes, ValueRange bounds, + acc::VariableInfoAttr varInfo) { // Create destroy block with arguments: original value + privatized value + // bounds SmallVector destroyArgTypes{varType, varType}; @@ -1655,7 +1666,8 @@ static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc, cast>(destroyBlock->getArgument(1)); if (isa(varType)) { auto mappableTy = cast(varType); - if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds)) + if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds, + varInfo)) return failure(); } else { assert(isa(varType) && "Expected PointerLikeType"); @@ -1717,8 +1729,10 @@ LogicalResult acc::PrivateRecipeOp::verifyRegions() { std::optional PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, - StringRef recipeName, Type varType, + StringRef recipeName, Value hostVar, StringRef varName, ValueRange bounds) { + Type varType = hostVar.getType(); + // First, validate that we can handle this variable type bool isMappable = isa(varType); bool isPointerLike = isa(varType); @@ -1734,8 +1748,9 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, // Populate the init region bool needsFree = false; - if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), varType, - varName, bounds, needsFree))) { + acc::VariableInfoAttr varInfo; + if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar, + varName, bounds, needsFree, varInfo))) { recipe.erase(); return std::nullopt; } @@ -1748,7 +1763,7 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, Value allocRes = yieldOp.getOperand(0); if (failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(), - varType, allocRes, bounds))) { + varType, allocRes, bounds, varInfo))) { recipe.erase(); return std::nullopt; } @@ -1811,8 +1826,10 @@ LogicalResult acc::FirstprivateRecipeOp::verifyRegions() { std::optional FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, - StringRef recipeName, Type varType, + StringRef recipeName, Value hostVar, StringRef varName, ValueRange bounds) { + Type varType = hostVar.getType(); + // First, validate that we can handle this variable type bool isMappable = isa(varType); bool isPointerLike = isa(varType); @@ -1828,8 +1845,9 @@ FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, // Populate the init region bool needsFree = false; - if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), varType, - varName, bounds, needsFree))) { + acc::VariableInfoAttr varInfo; + if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar, + varName, bounds, needsFree, varInfo))) { recipe.erase(); return std::nullopt; } @@ -1849,7 +1867,7 @@ FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc, Value allocRes = yieldOp.getOperand(0); if (failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(), - varType, allocRes, bounds))) { + varType, allocRes, bounds, varInfo))) { recipe.erase(); return std::nullopt; } diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp index 3b83a2542923..95c8d1076ccb 100644 --- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp +++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp @@ -365,7 +365,7 @@ ACCImplicitData::generatePrivateRecipe(ModuleOp &module, Value var, builder.setInsertionPointToStart(module.getBody()); auto recipe = - acc::PrivateRecipeOp::createAndPopulate(builder, loc, recipeName, type); + acc::PrivateRecipeOp::createAndPopulate(builder, loc, recipeName, var); if (!recipe.has_value()) return accSupport.emitNYI(loc, "implicit private"), nullptr; return recipe.value(); @@ -390,7 +390,7 @@ ACCImplicitData::generateFirstprivateRecipe(ModuleOp &module, Value var, builder.setInsertionPointToStart(module.getBody()); auto recipe = acc::FirstprivateRecipeOp::createAndPopulate(builder, loc, - recipeName, type); + recipeName, var); if (!recipe.has_value()) return accSupport.emitNYI(loc, "implicit firstprivate"), nullptr; return recipe.value(); diff --git a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp index 2506ca4fc39c..7b71f2c5f3b2 100644 --- a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp +++ b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp @@ -80,15 +80,15 @@ void TestRecipePopulatePass::runOnOperation() { ValueRange bounds; // No bounds for memref tests if (recipeType == "private") { - auto recipe = PrivateRecipeOp::createAndPopulate( - builder, loc, recipeName, var.getType(), varName, bounds); + auto recipe = PrivateRecipeOp::createAndPopulate(builder, loc, recipeName, + var, varName, bounds); if (!recipe) { op->emitError("Failed to create private recipe for ") << varName; } } else if (recipeType == "firstprivate") { auto recipe = FirstprivateRecipeOp::createAndPopulate( - builder, loc, recipeName, var.getType(), varName, bounds); + builder, loc, recipeName, var, varName, bounds); if (!recipe) { op->emitError("Failed to create firstprivate recipe for ") << varName; @@ -101,7 +101,7 @@ void TestRecipePopulatePass::runOnOperation() { std::string privName = "private_from_firstprivate_" + varName; auto firstpriv = FirstprivateRecipeOp::createAndPopulate( - builder, loc, firstprivName, var.getType(), varName, bounds); + builder, loc, firstprivName, var, varName, bounds); if (!firstpriv) { op->emitError("Failed to create firstprivate recipe for ") << varName;