Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===- FIROpenACCSupportAnalysis.h - FIR OpenACCSupport Analysis ----------===//
//
// 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 FIR-specific implementation of OpenACCSupport analysis.
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
#define FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H

#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/IR/Value.h"
#include <string>

namespace fir {
namespace acc {

/// FIR-specific implementation for the OpenACCSupport analysis interface.
///
/// This class provides the custom implementations of the OpenACCSupport
/// interface methods that are tailored to FIR's requirements and
/// can handle FIR dialect operations and types.
/// Its primary intent is to be registered with the OpenACCSupport analysis
/// using setImplementation()
///
/// Usage:
/// auto &support = getAnalysis<mlir::acc::OpenACCSupport>();
/// support.setImplementation(fir::acc::FIROpenACCSupportAnalysis());
///
class FIROpenACCSupportAnalysis {
public:
FIROpenACCSupportAnalysis() = default;

std::string getVariableName(mlir::Value v);

std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type,
mlir::Value var);

mlir::InFlightDiagnostic emitNYI(mlir::Location loc,
const mlir::Twine &message);
};

} // namespace acc
} // namespace fir

#endif // FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/OpenACC/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifndef FORTRAN_OPTIMIZER_OPENACC_PASSES_H
#define FORTRAN_OPTIMIZER_OPENACC_PASSES_H

#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassRegistry.h"
Expand All @@ -25,6 +28,7 @@ namespace acc {
#define GEN_PASS_REGISTRATION
#include "flang/Optimizer/OpenACC/Passes.h.inc"

std::unique_ptr<mlir::Pass> createACCInitializeFIRAnalysesPass();
std::unique_ptr<mlir::Pass> createACCRecipeBufferizationPass();

} // namespace acc
Expand Down
16 changes: 16 additions & 0 deletions flang/include/flang/Optimizer/OpenACC/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@

include "mlir/Pass/PassBase.td"

def ACCInitializeFIRAnalyses
: Pass<"acc-initialize-fir-analyses", "mlir::ModuleOp"> {
let summary = "Initialize FIR analyses for OpenACC passes";
let description = [{
This pass initializes analyses that can be used by subsequent OpenACC passes
in the pipeline. It creates and caches the OpenACCSupport analysis with a
FIR-specific implementation that can handle FIR types and operations.
It also initializes FIR's AliasAnalysis for use in OpenACC passes.
This pass needs to rerun if any analyses were invalidated by MLIR's framework.
}];
// In addition to pre-registering the needed analyses, this pass also
// pre-registers the dialects that various OpenACC passes may generate.
let dependentDialects = ["fir::FIROpsDialect", "hlfir::hlfirDialect",
"mlir::acc::OpenACCDialect"];
}

def ACCRecipeBufferization
: Pass<"fir-acc-recipe-bufferization", "mlir::ModuleOp"> {
let summary = "Rewrite acc.*.recipe box values to ref<box> and update uses";
Expand Down
57 changes: 57 additions & 0 deletions flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===- FIROpenACCUtils.h - FIR OpenACC Utilities ----------------*- 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 declares utility functions for FIR OpenACC support.
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
#define FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H

#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/IR/Value.h"
#include <string>

namespace fir {
namespace acc {

/// Attempts to extract the variable name from a value by walking through
/// FIR operations and looking for variable names.
/// \param v The value to extract the variable name from
/// \param preferDemangledName If true, prefers demangled/bindc names over
/// mangled/unique names. If false, prefers mangled names.
/// Returns empty string if no name is found.
std::string getVariableName(mlir::Value v, bool preferDemangledName = true);

/// Get the recipe name for a given recipe kind, FIR type, and optional
/// variable. Uses FIR's type string representation with appropriate prefix. For
/// firstprivate and reduction recipes, handles bounds suffix when all bounds
/// are constant. For reduction recipes, embeds the operator name in the recipe.
/// \param kind The recipe kind (private, firstprivate, or reduction)
/// \param type The FIR type (must be a FIR type)
/// \param var Optional variable value
/// \param bounds Optional bounds for array sections (used for suffix
/// generation)
/// \param reductionOp Optional reduction operator (required for reduction
/// recipes)
/// \return The complete recipe name with all necessary suffixes
std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type,
mlir::Value var = nullptr,
llvm::ArrayRef<mlir::Value> bounds = {},
mlir::acc::ReductionOperator reductionOp =
mlir::acc::ReductionOperator::AccNone);

/// Check if all bounds are expressed with constant values.
/// \param bounds Array of DataBoundsOp values to check
/// \return true if all bounds have constant lowerbound/upperbound or extent
bool areAllBoundsConstant(llvm::ArrayRef<mlir::Value> bounds);

} // namespace acc
} // namespace fir

#endif // FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
69 changes: 12 additions & 57 deletions flang/lib/Lower/OpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "flang/Optimizer/Builder/IntrinsicCall.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/tools.h"
Expand Down Expand Up @@ -1159,18 +1160,6 @@ bool isConstantBound(mlir::acc::DataBoundsOp &op) {
return false;
}

/// Return true iff all the bounds are expressed with constant values.
bool areAllBoundConstant(const llvm::SmallVector<mlir::Value> &bounds) {
for (auto bound : bounds) {
auto dataBound =
mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
assert(dataBound && "Must be DataBoundOp operation");
if (!isConstantBound(dataBound))
return false;
}
return true;
}

static llvm::SmallVector<mlir::Value>
genConstantBounds(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::acc::DataBoundsOp &dataBound) {
Expand Down Expand Up @@ -1324,7 +1313,7 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
mlir::OpBuilder::InsertionGuard guard(builder);
auto recipe = genRecipeOp<mlir::acc::FirstprivateRecipeOp>(
builder, mod, recipeName, loc, ty);
bool allConstantBound = areAllBoundConstant(bounds);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
auto [source, destination] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCopyRegion(), bounds, allConstantBound);

Expand Down Expand Up @@ -1358,33 +1347,6 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
return recipe;
}

/// Get a string representation of the bounds.
std::string getBoundsString(llvm::SmallVector<mlir::Value> &bounds) {
std::stringstream boundStr;
if (!bounds.empty())
boundStr << "_section_";
llvm::interleave(
bounds,
[&](mlir::Value bound) {
auto boundsOp =
mlir::cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
if (boundsOp.getLowerbound() &&
fir::getIntIfConstant(boundsOp.getLowerbound()) &&
boundsOp.getUpperbound() &&
fir::getIntIfConstant(boundsOp.getUpperbound())) {
boundStr << "lb" << *fir::getIntIfConstant(boundsOp.getLowerbound())
<< ".ub" << *fir::getIntIfConstant(boundsOp.getUpperbound());
} else if (boundsOp.getExtent() &&
fir::getIntIfConstant(boundsOp.getExtent())) {
boundStr << "ext" << *fir::getIntIfConstant(boundsOp.getExtent());
} else {
boundStr << "?";
}
},
[&] { boundStr << "x"; });
return boundStr.str();
}

/// Rebuild the array type from the acc.bounds operation with constant
/// lowerbound/upperbound or extent.
mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds,
Expand Down Expand Up @@ -1458,9 +1420,8 @@ static void genPrivatizationRecipes(
RecipeOp recipe;
mlir::Type retTy = getTypeFromBounds(bounds, info.addr.getType());
if constexpr (std::is_same_v<RecipeOp, mlir::acc::PrivateRecipeOp>) {
std::string recipeName =
fir::getTypeAsString(retTy, converter.getKindMap(),
Fortran::lower::privatizationRecipePrefix);
std::string recipeName = fir::acc::getRecipeName(
mlir::acc::RecipeKind::private_recipe, retTy, info.addr, bounds);
recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName,
operandLocation, retTy);
auto op = createDataEntryOp<mlir::acc::PrivateOp>(
Expand All @@ -1474,10 +1435,8 @@ static void genPrivatizationRecipes(
symbolPairs->emplace_back(op.getAccVar(),
Fortran::semantics::SymbolRef(symbol));
} else {
std::string suffix =
areAllBoundConstant(bounds) ? getBoundsString(bounds) : "";
std::string recipeName = fir::getTypeAsString(
retTy, converter.getKindMap(), "firstprivatization" + suffix);
std::string recipeName = fir::acc::getRecipeName(
mlir::acc::RecipeKind::firstprivate_recipe, retTy, info.addr, bounds);
recipe = Fortran::lower::createOrGetFirstprivateRecipe(
builder, recipeName, operandLocation, retTy, bounds);
auto op = createDataEntryOp<mlir::acc::FirstprivateOp>(
Expand Down Expand Up @@ -1623,7 +1582,7 @@ mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe(
mlir::OpBuilder::InsertionGuard guard(builder);
auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
builder, mod, recipeName, loc, ty, op);
bool allConstantBound = areAllBoundConstant(bounds);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);

auto [dest, src] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCombinerRegion(), bounds, allConstantBound);
Expand Down Expand Up @@ -1708,15 +1667,12 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
mlir::acc::DataClause::acc_reduction, info.addr.getType(), async,
asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
mlir::Type ty = op.getAccVar().getType();
if (!areAllBoundConstant(bounds) ||
if (!fir::acc::areAllBoundsConstant(bounds) ||
fir::isAssumedShape(info.addr.getType()) ||
fir::isAllocatableOrPointerArray(info.addr.getType()))
ty = info.addr.getType();
std::string suffix =
areAllBoundConstant(bounds) ? getBoundsString(bounds) : "";
std::string recipeName = fir::getTypeAsString(
ty, converter.getKindMap(),
("reduction_" + stringifyReductionOperator(mlirOp)).str() + suffix);
std::string recipeName = fir::acc::getRecipeName(
mlir::acc::RecipeKind::reduction_recipe, ty, info.addr, bounds, mlirOp);

mlir::acc::ReductionRecipeOp recipe =
Fortran::lower::createOrGetReductionRecipe(
Expand Down Expand Up @@ -1961,9 +1917,8 @@ static void privatizeIv(
}

if (privateOp == nullptr) {
std::string recipeName =
fir::getTypeAsString(ivValue.getType(), converter.getKindMap(),
Fortran::lower::privatizationRecipePrefix);
std::string recipeName = fir::acc::getRecipeName(
mlir::acc::RecipeKind::private_recipe, ivValue.getType(), ivValue, {});
auto recipe = Fortran::lower::createOrGetPrivateRecipe(
builder, recipeName, loc, ivValue.getType());

Expand Down
22 changes: 22 additions & 0 deletions flang/lib/Optimizer/OpenACC/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
add_flang_library(FIROpenACCAnalysis
FIROpenACCSupportAnalysis.cpp

DEPENDS
FIRAnalysis
FIRDialect
FIROpenACCSupport
HLFIRDialect

LINK_LIBS
FIRAnalysis
FIRDialect
FIROpenACCSupport
HLFIRDialect

MLIR_DEPS
MLIROpenACCDialect

MLIR_LIBS
MLIROpenACCDialect
)

40 changes: 40 additions & 0 deletions flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===- FIROpenACCSupportAnalysis.cpp - FIR OpenACCSupport Analysis -------===//
//
// 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 implements the FIR-specific OpenACCSupport analysis.
//
//===----------------------------------------------------------------------===//

#include "flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"

using namespace mlir;

namespace fir {
namespace acc {

std::string FIROpenACCSupportAnalysis::getVariableName(Value v) {
return fir::acc::getVariableName(v, /*preferDemangledName=*/true);
}

std::string FIROpenACCSupportAnalysis::getRecipeName(mlir::acc::RecipeKind kind,
Type type, Value var) {
return fir::acc::getRecipeName(kind, type, var);
}

mlir::InFlightDiagnostic
FIROpenACCSupportAnalysis::emitNYI(Location loc, const Twine &message) {
TODO(loc, message);
// Should be unreachable, but we return an actual diagnostic
// to satisfy the interface.
return mlir::emitError(loc, "not yet implemented: " + message.str());
}

} // namespace acc
} // namespace fir
1 change: 1 addition & 0 deletions flang/lib/Optimizer/OpenACC/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(Analysis)
add_subdirectory(Support)
add_subdirectory(Transforms)
1 change: 1 addition & 0 deletions flang/lib/Optimizer/OpenACC/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_flang_library(FIROpenACCSupport
FIROpenACCAttributes.cpp
FIROpenACCOpsInterfaces.cpp
FIROpenACCTypeInterfaces.cpp
FIROpenACCUtils.cpp
RegisterOpenACCExtensions.cpp

DEPENDS
Expand Down
Loading