Skip to content

Commit c12cb28

Browse files
[flang][acc] Add infrastructure and tests for ACCImplicitData (#166797)
This PR adds the necessary infrastructure to enable testing of the ACCImplicitData pass for FIR/HLFIR, along with comprehensive test coverage for implicit data clause generation in OpenACC constructs. New Infrastructure: - Add FIROpenACCSupport analysis providing FIR-specific implementations of OpenACCSupport interface methods for variable name extraction, recipe name generation, and NYI emission - Add FIROpenACCUtils with helper functions for: * Variable name extraction from FIR operations (getVariableName) * Recipe name generation with FIR type string representation * Bounds checking for constant array sections - Add ACCInitializeFIRAnalyses pass to pre-register FIR analyses (OpenACCSupport and AliasAnalysis) for use by subsequent OpenACC passes in the pipeline Refactoring in flang/lib/Lower/OpenACC.cpp: - Move bounds string generation and bounds checking to FIROpenACCUtils - Refactor recipe name generation to use fir::acc::getRecipeName Test Coverage: - acc-implicit-firstprivate.fir: Tests implicit firstprivate behavior for scalar types (i8, i16, i32, i64, f32, f64, logical, complex) in parallel/serial constructs with recipe generation verification - acc-implicit-data.fir: Tests implicit data clauses for scalars, arrays, derived types, and boxes in kernels/parallel/serial with default(none) and default(present) variations - acc-implicit-data-fortran.F90: Fortran tests verifying implicit data generation through bbc with both HLFIR and FIR - acc-implicit-data-derived-type-member.F90: Tests correct ordering of parent/child data clause operations for derived type members - acc-implicit-copy-reduction.fir: Tests enable-implicit-reduction-copy flag controlling whether reduction variables use copy or firstprivate This enables proper testing of implicit data clause generation through the flang optimizer pipeline for OpenACC directives.
1 parent 67eb691 commit c12cb28

File tree

17 files changed

+1425
-57
lines changed

17 files changed

+1425
-57
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===- FIROpenACCSupportAnalysis.h - FIR OpenACCSupport Analysis ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines the FIR-specific implementation of OpenACCSupport analysis.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
14+
#define FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
15+
16+
#include "mlir/Dialect/OpenACC/OpenACC.h"
17+
#include "mlir/IR/Value.h"
18+
#include <string>
19+
20+
namespace fir {
21+
namespace acc {
22+
23+
/// FIR-specific implementation for the OpenACCSupport analysis interface.
24+
///
25+
/// This class provides the custom implementations of the OpenACCSupport
26+
/// interface methods that are tailored to FIR's requirements and
27+
/// can handle FIR dialect operations and types.
28+
/// Its primary intent is to be registered with the OpenACCSupport analysis
29+
/// using setImplementation()
30+
///
31+
/// Usage:
32+
/// auto &support = getAnalysis<mlir::acc::OpenACCSupport>();
33+
/// support.setImplementation(fir::acc::FIROpenACCSupportAnalysis());
34+
///
35+
class FIROpenACCSupportAnalysis {
36+
public:
37+
FIROpenACCSupportAnalysis() = default;
38+
39+
std::string getVariableName(mlir::Value v);
40+
41+
std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type,
42+
mlir::Value var);
43+
44+
mlir::InFlightDiagnostic emitNYI(mlir::Location loc,
45+
const mlir::Twine &message);
46+
};
47+
48+
} // namespace acc
49+
} // namespace fir
50+
51+
#endif // FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H

flang/include/flang/Optimizer/OpenACC/Passes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#ifndef FORTRAN_OPTIMIZER_OPENACC_PASSES_H
1414
#define FORTRAN_OPTIMIZER_OPENACC_PASSES_H
1515

16+
#include "flang/Optimizer/Dialect/FIRDialect.h"
17+
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
18+
#include "mlir/Dialect/OpenACC/OpenACC.h"
1619
#include "mlir/IR/BuiltinOps.h"
1720
#include "mlir/Pass/Pass.h"
1821
#include "mlir/Pass/PassRegistry.h"
@@ -25,6 +28,7 @@ namespace acc {
2528
#define GEN_PASS_REGISTRATION
2629
#include "flang/Optimizer/OpenACC/Passes.h.inc"
2730

31+
std::unique_ptr<mlir::Pass> createACCInitializeFIRAnalysesPass();
2832
std::unique_ptr<mlir::Pass> createACCRecipeBufferizationPass();
2933

3034
} // namespace acc

flang/include/flang/Optimizer/OpenACC/Passes.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111

1212
include "mlir/Pass/PassBase.td"
1313

14+
def ACCInitializeFIRAnalyses
15+
: Pass<"acc-initialize-fir-analyses", "mlir::ModuleOp"> {
16+
let summary = "Initialize FIR analyses for OpenACC passes";
17+
let description = [{
18+
This pass initializes analyses that can be used by subsequent OpenACC passes
19+
in the pipeline. It creates and caches the OpenACCSupport analysis with a
20+
FIR-specific implementation that can handle FIR types and operations.
21+
It also initializes FIR's AliasAnalysis for use in OpenACC passes.
22+
This pass needs to rerun if any analyses were invalidated by MLIR's framework.
23+
}];
24+
// In addition to pre-registering the needed analyses, this pass also
25+
// pre-registers the dialects that various OpenACC passes may generate.
26+
let dependentDialects = ["fir::FIROpsDialect", "hlfir::hlfirDialect",
27+
"mlir::acc::OpenACCDialect"];
28+
}
29+
1430
def ACCRecipeBufferization
1531
: Pass<"fir-acc-recipe-bufferization", "mlir::ModuleOp"> {
1632
let summary = "Rewrite acc.*.recipe box values to ref<box> and update uses";
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===- FIROpenACCUtils.h - FIR OpenACC Utilities ----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares utility functions for FIR OpenACC support.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
14+
#define FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
15+
16+
#include "mlir/Dialect/OpenACC/OpenACC.h"
17+
#include "mlir/IR/Value.h"
18+
#include <string>
19+
20+
namespace fir {
21+
namespace acc {
22+
23+
/// Attempts to extract the variable name from a value by walking through
24+
/// FIR operations and looking for variable names.
25+
/// \param v The value to extract the variable name from
26+
/// \param preferDemangledName If true, prefers demangled/bindc names over
27+
/// mangled/unique names. If false, prefers mangled names.
28+
/// Returns empty string if no name is found.
29+
std::string getVariableName(mlir::Value v, bool preferDemangledName = true);
30+
31+
/// Get the recipe name for a given recipe kind, FIR type, and optional
32+
/// variable. Uses FIR's type string representation with appropriate prefix. For
33+
/// firstprivate and reduction recipes, handles bounds suffix when all bounds
34+
/// are constant. For reduction recipes, embeds the operator name in the recipe.
35+
/// \param kind The recipe kind (private, firstprivate, or reduction)
36+
/// \param type The FIR type (must be a FIR type)
37+
/// \param var Optional variable value
38+
/// \param bounds Optional bounds for array sections (used for suffix
39+
/// generation)
40+
/// \param reductionOp Optional reduction operator (required for reduction
41+
/// recipes)
42+
/// \return The complete recipe name with all necessary suffixes
43+
std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type,
44+
mlir::Value var = nullptr,
45+
llvm::ArrayRef<mlir::Value> bounds = {},
46+
mlir::acc::ReductionOperator reductionOp =
47+
mlir::acc::ReductionOperator::AccNone);
48+
49+
/// Check if all bounds are expressed with constant values.
50+
/// \param bounds Array of DataBoundsOp values to check
51+
/// \return true if all bounds have constant lowerbound/upperbound or extent
52+
bool areAllBoundsConstant(llvm::ArrayRef<mlir::Value> bounds);
53+
54+
} // namespace acc
55+
} // namespace fir
56+
57+
#endif // FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H

flang/lib/Lower/OpenACC.cpp

Lines changed: 12 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "flang/Optimizer/Builder/IntrinsicCall.h"
2929
#include "flang/Optimizer/Builder/Todo.h"
3030
#include "flang/Optimizer/Dialect/FIRType.h"
31+
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
3132
#include "flang/Parser/parse-tree-visitor.h"
3233
#include "flang/Parser/parse-tree.h"
3334
#include "flang/Parser/tools.h"
@@ -1159,18 +1160,6 @@ bool isConstantBound(mlir::acc::DataBoundsOp &op) {
11591160
return false;
11601161
}
11611162

1162-
/// Return true iff all the bounds are expressed with constant values.
1163-
bool areAllBoundConstant(const llvm::SmallVector<mlir::Value> &bounds) {
1164-
for (auto bound : bounds) {
1165-
auto dataBound =
1166-
mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
1167-
assert(dataBound && "Must be DataBoundOp operation");
1168-
if (!isConstantBound(dataBound))
1169-
return false;
1170-
}
1171-
return true;
1172-
}
1173-
11741163
static llvm::SmallVector<mlir::Value>
11751164
genConstantBounds(fir::FirOpBuilder &builder, mlir::Location loc,
11761165
mlir::acc::DataBoundsOp &dataBound) {
@@ -1324,7 +1313,7 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
13241313
mlir::OpBuilder::InsertionGuard guard(builder);
13251314
auto recipe = genRecipeOp<mlir::acc::FirstprivateRecipeOp>(
13261315
builder, mod, recipeName, loc, ty);
1327-
bool allConstantBound = areAllBoundConstant(bounds);
1316+
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
13281317
auto [source, destination] = genRecipeCombinerOrCopyRegion(
13291318
builder, loc, ty, recipe.getCopyRegion(), bounds, allConstantBound);
13301319

@@ -1358,33 +1347,6 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
13581347
return recipe;
13591348
}
13601349

1361-
/// Get a string representation of the bounds.
1362-
std::string getBoundsString(llvm::SmallVector<mlir::Value> &bounds) {
1363-
std::stringstream boundStr;
1364-
if (!bounds.empty())
1365-
boundStr << "_section_";
1366-
llvm::interleave(
1367-
bounds,
1368-
[&](mlir::Value bound) {
1369-
auto boundsOp =
1370-
mlir::cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
1371-
if (boundsOp.getLowerbound() &&
1372-
fir::getIntIfConstant(boundsOp.getLowerbound()) &&
1373-
boundsOp.getUpperbound() &&
1374-
fir::getIntIfConstant(boundsOp.getUpperbound())) {
1375-
boundStr << "lb" << *fir::getIntIfConstant(boundsOp.getLowerbound())
1376-
<< ".ub" << *fir::getIntIfConstant(boundsOp.getUpperbound());
1377-
} else if (boundsOp.getExtent() &&
1378-
fir::getIntIfConstant(boundsOp.getExtent())) {
1379-
boundStr << "ext" << *fir::getIntIfConstant(boundsOp.getExtent());
1380-
} else {
1381-
boundStr << "?";
1382-
}
1383-
},
1384-
[&] { boundStr << "x"; });
1385-
return boundStr.str();
1386-
}
1387-
13881350
/// Rebuild the array type from the acc.bounds operation with constant
13891351
/// lowerbound/upperbound or extent.
13901352
mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds,
@@ -1458,9 +1420,8 @@ static void genPrivatizationRecipes(
14581420
RecipeOp recipe;
14591421
mlir::Type retTy = getTypeFromBounds(bounds, info.addr.getType());
14601422
if constexpr (std::is_same_v<RecipeOp, mlir::acc::PrivateRecipeOp>) {
1461-
std::string recipeName =
1462-
fir::getTypeAsString(retTy, converter.getKindMap(),
1463-
Fortran::lower::privatizationRecipePrefix);
1423+
std::string recipeName = fir::acc::getRecipeName(
1424+
mlir::acc::RecipeKind::private_recipe, retTy, info.addr, bounds);
14641425
recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName,
14651426
operandLocation, retTy);
14661427
auto op = createDataEntryOp<mlir::acc::PrivateOp>(
@@ -1474,10 +1435,8 @@ static void genPrivatizationRecipes(
14741435
symbolPairs->emplace_back(op.getAccVar(),
14751436
Fortran::semantics::SymbolRef(symbol));
14761437
} else {
1477-
std::string suffix =
1478-
areAllBoundConstant(bounds) ? getBoundsString(bounds) : "";
1479-
std::string recipeName = fir::getTypeAsString(
1480-
retTy, converter.getKindMap(), "firstprivatization" + suffix);
1438+
std::string recipeName = fir::acc::getRecipeName(
1439+
mlir::acc::RecipeKind::firstprivate_recipe, retTy, info.addr, bounds);
14811440
recipe = Fortran::lower::createOrGetFirstprivateRecipe(
14821441
builder, recipeName, operandLocation, retTy, bounds);
14831442
auto op = createDataEntryOp<mlir::acc::FirstprivateOp>(
@@ -1623,7 +1582,7 @@ mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe(
16231582
mlir::OpBuilder::InsertionGuard guard(builder);
16241583
auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
16251584
builder, mod, recipeName, loc, ty, op);
1626-
bool allConstantBound = areAllBoundConstant(bounds);
1585+
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
16271586

16281587
auto [dest, src] = genRecipeCombinerOrCopyRegion(
16291588
builder, loc, ty, recipe.getCombinerRegion(), bounds, allConstantBound);
@@ -1708,15 +1667,12 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
17081667
mlir::acc::DataClause::acc_reduction, info.addr.getType(), async,
17091668
asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
17101669
mlir::Type ty = op.getAccVar().getType();
1711-
if (!areAllBoundConstant(bounds) ||
1670+
if (!fir::acc::areAllBoundsConstant(bounds) ||
17121671
fir::isAssumedShape(info.addr.getType()) ||
17131672
fir::isAllocatableOrPointerArray(info.addr.getType()))
17141673
ty = info.addr.getType();
1715-
std::string suffix =
1716-
areAllBoundConstant(bounds) ? getBoundsString(bounds) : "";
1717-
std::string recipeName = fir::getTypeAsString(
1718-
ty, converter.getKindMap(),
1719-
("reduction_" + stringifyReductionOperator(mlirOp)).str() + suffix);
1674+
std::string recipeName = fir::acc::getRecipeName(
1675+
mlir::acc::RecipeKind::reduction_recipe, ty, info.addr, bounds, mlirOp);
17201676

17211677
mlir::acc::ReductionRecipeOp recipe =
17221678
Fortran::lower::createOrGetReductionRecipe(
@@ -1961,9 +1917,8 @@ static void privatizeIv(
19611917
}
19621918

19631919
if (privateOp == nullptr) {
1964-
std::string recipeName =
1965-
fir::getTypeAsString(ivValue.getType(), converter.getKindMap(),
1966-
Fortran::lower::privatizationRecipePrefix);
1920+
std::string recipeName = fir::acc::getRecipeName(
1921+
mlir::acc::RecipeKind::private_recipe, ivValue.getType(), ivValue, {});
19671922
auto recipe = Fortran::lower::createOrGetPrivateRecipe(
19681923
builder, recipeName, loc, ivValue.getType());
19691924

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
add_flang_library(FIROpenACCAnalysis
2+
FIROpenACCSupportAnalysis.cpp
3+
4+
DEPENDS
5+
FIRAnalysis
6+
FIRDialect
7+
FIROpenACCSupport
8+
HLFIRDialect
9+
10+
LINK_LIBS
11+
FIRAnalysis
12+
FIRDialect
13+
FIROpenACCSupport
14+
HLFIRDialect
15+
16+
MLIR_DEPS
17+
MLIROpenACCDialect
18+
19+
MLIR_LIBS
20+
MLIROpenACCDialect
21+
)
22+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===- FIROpenACCSupportAnalysis.cpp - FIR OpenACCSupport Analysis -------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements the FIR-specific OpenACCSupport analysis.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h"
14+
#include "flang/Optimizer/Builder/Todo.h"
15+
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
16+
17+
using namespace mlir;
18+
19+
namespace fir {
20+
namespace acc {
21+
22+
std::string FIROpenACCSupportAnalysis::getVariableName(Value v) {
23+
return fir::acc::getVariableName(v, /*preferDemangledName=*/true);
24+
}
25+
26+
std::string FIROpenACCSupportAnalysis::getRecipeName(mlir::acc::RecipeKind kind,
27+
Type type, Value var) {
28+
return fir::acc::getRecipeName(kind, type, var);
29+
}
30+
31+
mlir::InFlightDiagnostic
32+
FIROpenACCSupportAnalysis::emitNYI(Location loc, const Twine &message) {
33+
TODO(loc, message);
34+
// Should be unreachable, but we return an actual diagnostic
35+
// to satisfy the interface.
36+
return mlir::emitError(loc, "not yet implemented: " + message.str());
37+
}
38+
39+
} // namespace acc
40+
} // namespace fir
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
add_subdirectory(Analysis)
12
add_subdirectory(Support)
23
add_subdirectory(Transforms)

flang/lib/Optimizer/OpenACC/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_flang_library(FIROpenACCSupport
44
FIROpenACCAttributes.cpp
55
FIROpenACCOpsInterfaces.cpp
66
FIROpenACCTypeInterfaces.cpp
7+
FIROpenACCUtils.cpp
78
RegisterOpenACCExtensions.cpp
89

910
DEPENDS

0 commit comments

Comments
 (0)