Skip to content

Commit f3599e5

Browse files
[mlir][acc] Add OpenACCSupport for extensible dialect handling (llvm#164510)
The OpenACC dialect must coexist with source language dialects (FIR, CIR, etc.) to enable offloading. While type interfaces (`PointerLikeType` and `MappableType`) provide the primary contract for variable mapping, some scenarios require pipeline-specific customization or need to express information that cannot be adequately captured through operation and type interfaces alone. This commit introduces the `OpenACCSupport` analysis, which provides extensible support APIs that can be customized per-pipeline. The analysis follows the Concept-Model pattern used in MLIR's `AliasAnalysis` and is never invalidated, persisting throughout the pass pipeline. The initial API, `getVariableName(Value) -> string`, retrieves variable names from MLIR values by: - Checking for `acc.var_name` attributes - Extracting names from ACC data clause operations (e.g., `acc.copyin`) - Walking through `ViewLikeOpInterface` operations to find the source This will be used in the implicit data mapping pass to automatically generate device mappings with correct user-visible variable names. Usage: Passes call `getAnalysis<OpenACCSupport>()` to get a cached instance with either the default or a previously- registered custom implementation. Custom implementations can be registered in a setup pass by calling `setImplementation()` before the consumer pass runs.
1 parent 003101e commit f3599e5

File tree

11 files changed

+448
-0
lines changed

11 files changed

+448
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//===- OpenACCSupport.h - OpenACC Support Interface -------------*- 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 defines the OpenACCSupport analysis interface, which provides
10+
// extensible support for OpenACC passes. Custom implementations
11+
// can be registered to provide pipeline and dialect-specific information
12+
// that cannot be adequately expressed through type or operation interfaces
13+
// alone.
14+
//
15+
// Usage Pattern:
16+
// ==============
17+
//
18+
// A pass that needs this functionality should call
19+
// getAnalysis<OpenACCSupport>(), which will provide either:
20+
// - A cached version if previously initialized, OR
21+
// - A default implementation if not previously initialized
22+
//
23+
// This analysis is never invalidated (isInvalidated returns false), so it only
24+
// needs to be initialized once and will persist throughout the pass pipeline.
25+
//
26+
// Registering a Custom Implementation:
27+
// =====================================
28+
//
29+
// If a custom implementation is needed, create a pass that runs BEFORE the pass
30+
// that needs the analysis. In this setup pass, use
31+
// getAnalysis<OpenACCSupport>() followed by setImplementation() to register
32+
// your custom implementation. The custom implementation will need to provide
33+
// implementation for all methods defined in the `OpenACCSupportTraits::Concept`
34+
// class.
35+
//
36+
// Example:
37+
// void MySetupPass::runOnOperation() {
38+
// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
39+
// support.setImplementation(MyCustomImpl());
40+
// }
41+
//
42+
// void MyAnalysisConsumerPass::runOnOperation() {
43+
// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
44+
// std::string name = support.getVariableName(someValue);
45+
// // ... use the analysis results
46+
// }
47+
//
48+
//===----------------------------------------------------------------------===//
49+
50+
#ifndef MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
51+
#define MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
52+
53+
#include "mlir/IR/Value.h"
54+
#include "mlir/Pass/AnalysisManager.h"
55+
#include <memory>
56+
#include <string>
57+
58+
namespace mlir {
59+
namespace acc {
60+
61+
namespace detail {
62+
/// This class contains internal trait classes used by OpenACCSupport.
63+
/// It follows the Concept-Model pattern used throughout MLIR (e.g., in
64+
/// AliasAnalysis and interface definitions).
65+
struct OpenACCSupportTraits {
66+
class Concept {
67+
public:
68+
virtual ~Concept() = default;
69+
70+
/// Get the variable name for a given MLIR value.
71+
virtual std::string getVariableName(Value v) = 0;
72+
};
73+
74+
/// This class wraps a concrete OpenACCSupport implementation and forwards
75+
/// interface calls to it. This provides type erasure, allowing different
76+
/// implementation types to be used interchangeably without inheritance.
77+
template <typename ImplT>
78+
class Model final : public Concept {
79+
public:
80+
explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
81+
~Model() override = default;
82+
83+
std::string getVariableName(Value v) final {
84+
return impl.getVariableName(v);
85+
}
86+
87+
private:
88+
ImplT impl;
89+
};
90+
};
91+
} // namespace detail
92+
93+
//===----------------------------------------------------------------------===//
94+
// OpenACCSupport
95+
//===----------------------------------------------------------------------===//
96+
97+
class OpenACCSupport {
98+
using Concept = detail::OpenACCSupportTraits::Concept;
99+
template <typename ImplT>
100+
using Model = detail::OpenACCSupportTraits::Model<ImplT>;
101+
102+
public:
103+
OpenACCSupport() = default;
104+
OpenACCSupport(Operation *op) {}
105+
106+
/// Register a custom OpenACCSupport implementation. Only one implementation
107+
/// can be registered at a time; calling this replaces any existing
108+
/// implementation.
109+
template <typename AnalysisT>
110+
void setImplementation(AnalysisT &&analysis) {
111+
impl =
112+
std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis));
113+
}
114+
115+
/// Get the variable name for a given value.
116+
///
117+
/// \param v The MLIR value to get the variable name for.
118+
/// \return The variable name, or an empty string if unavailable.
119+
std::string getVariableName(Value v);
120+
121+
/// Signal that this analysis should always be preserved so that
122+
/// underlying implementation registration is not lost.
123+
bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
124+
return false;
125+
}
126+
127+
private:
128+
/// The registered custom implementation (if any).
129+
std::unique_ptr<Concept> impl;
130+
};
131+
132+
} // namespace acc
133+
} // namespace mlir
134+
135+
#endif // MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H

mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ std::optional<ClauseDefaultValue> getDefaultAttr(mlir::Operation *op);
3838
/// Get the type category of an OpenACC variable.
3939
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Value var);
4040

41+
/// Attempts to extract the variable name from a value by walking through
42+
/// view-like operations until an `acc.var_name` attribute is found. Returns
43+
/// empty string if no name is found.
44+
std::string getVariableName(mlir::Value v);
45+
4146
} // namespace acc
4247
} // namespace mlir
4348

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
add_mlir_dialect_library(MLIROpenACCAnalysis
2+
OpenACCSupport.cpp
3+
4+
ADDITIONAL_HEADER_DIRS
5+
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/OpenACC
6+
7+
LINK_LIBS PUBLIC
8+
MLIRIR
9+
MLIROpenACCDialect
10+
MLIROpenACCUtils
11+
MLIRSupport
12+
)
13+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===- OpenACCSupport.cpp - OpenACCSupport Implementation -----------------===//
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 OpenACCSupport analysis interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
14+
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
15+
16+
namespace mlir {
17+
namespace acc {
18+
19+
std::string OpenACCSupport::getVariableName(Value v) {
20+
if (impl)
21+
return impl->getVariableName(v);
22+
return acc::getVariableName(v);
23+
}
24+
25+
} // namespace acc
26+
} // namespace mlir
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
add_subdirectory(Analysis)
12
add_subdirectory(IR)
23
add_subdirectory(Utils)
34
add_subdirectory(Transforms)

mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
1010

1111
#include "mlir/Dialect/OpenACC/OpenACC.h"
12+
#include "mlir/Interfaces/ViewLikeInterface.h"
1213
#include "llvm/ADT/TypeSwitch.h"
1314

1415
mlir::Operation *mlir::acc::getEnclosingComputeOp(mlir::Region &region) {
@@ -78,3 +79,30 @@ mlir::acc::VariableTypeCategory mlir::acc::getTypeCategory(mlir::Value var) {
7879
pointerLikeTy.getElementType());
7980
return typeCategory;
8081
}
82+
83+
std::string mlir::acc::getVariableName(mlir::Value v) {
84+
Value current = v;
85+
86+
// Walk through view operations until a name is found or can't go further
87+
while (Operation *definingOp = current.getDefiningOp()) {
88+
// Check for `acc.var_name` attribute
89+
if (auto varNameAttr =
90+
definingOp->getAttrOfType<VarNameAttr>(getVarNameAttrName()))
91+
return varNameAttr.getName().str();
92+
93+
// If it is a data entry operation, get name via getVarName
94+
if (isa<ACC_DATA_ENTRY_OPS>(definingOp))
95+
if (auto name = acc::getVarName(definingOp))
96+
return name->str();
97+
98+
// If it's a view operation, continue to the source
99+
if (auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
100+
current = viewOp.getViewSource();
101+
continue;
102+
}
103+
104+
break;
105+
}
106+
107+
return "";
108+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: mlir-opt %s -split-input-file -test-acc-support | FileCheck %s
2+
3+
// Test with direct variable names
4+
func.func @test_direct_var_name() {
5+
// Create a memref with acc.var_name attribute
6+
%0 = memref.alloca() {acc.var_name = #acc.var_name<"my_variable">} : memref<10xi32>
7+
8+
%1 = memref.cast %0 {test.var_name} : memref<10xi32> to memref<10xi32>
9+
10+
// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
11+
// CHECK-NEXT: getVariableName="my_variable"
12+
13+
return
14+
}
15+
16+
// -----
17+
18+
// Test through memref.cast
19+
func.func @test_through_cast() {
20+
// Create a 5x2 memref with acc.var_name attribute
21+
%0 = memref.alloca() {acc.var_name = #acc.var_name<"casted_variable">} : memref<5x2xi32>
22+
23+
// Cast to dynamic dimensions
24+
%1 = memref.cast %0 : memref<5x2xi32> to memref<?x?xi32>
25+
26+
// Mark with test attribute - should find name through cast
27+
%2 = memref.cast %1 {test.var_name} : memref<?x?xi32> to memref<5x2xi32>
28+
29+
// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<?x?xi32> to memref<5x2xi32>
30+
// CHECK-NEXT: getVariableName="casted_variable"
31+
32+
return
33+
}
34+
35+
// -----
36+
37+
// Test with no variable name
38+
func.func @test_no_var_name() {
39+
// Create a memref without acc.var_name attribute
40+
%0 = memref.alloca() : memref<10xi32>
41+
42+
// Mark with test attribute - should find empty string
43+
%1 = memref.cast %0 {test.var_name} : memref<10xi32> to memref<10xi32>
44+
45+
// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
46+
// CHECK-NEXT: getVariableName=""
47+
48+
return
49+
}
50+
51+
// -----
52+
53+
// Test through multiple casts
54+
func.func @test_multiple_casts() {
55+
// Create a memref with acc.var_name attribute
56+
%0 = memref.alloca() {acc.var_name = #acc.var_name<"multi_cast">} : memref<10xi32>
57+
58+
// Multiple casts
59+
%1 = memref.cast %0 : memref<10xi32> to memref<?xi32>
60+
%2 = memref.cast %1 : memref<?xi32> to memref<10xi32>
61+
62+
// Mark with test attribute - should find name through multiple casts
63+
%3 = memref.cast %2 {test.var_name} : memref<10xi32> to memref<10xi32>
64+
65+
// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
66+
// CHECK-NEXT: getVariableName="multi_cast"
67+
68+
return
69+
}
70+
71+
// -----
72+
73+
// Test with acc.copyin operation
74+
func.func @test_copyin_name() {
75+
// Create a memref
76+
%0 = memref.alloca() : memref<10xf32>
77+
78+
// Create an acc.copyin operation with a name
79+
%1 = acc.copyin varPtr(%0 : memref<10xf32>) -> memref<10xf32> {name = "input_data"}
80+
81+
// Mark with test attribute - should find name from copyin operation
82+
%2 = memref.cast %1 {test.var_name} : memref<10xf32> to memref<?xf32>
83+
84+
// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xf32> to memref<?xf32>
85+
// CHECK-NEXT: getVariableName="input_data"
86+
87+
return
88+
}

mlir/test/lib/Dialect/OpenACC/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_mlir_library(MLIROpenACCTestPasses
22
TestOpenACC.cpp
33
TestPointerLikeTypeInterface.cpp
44
TestRecipePopulate.cpp
5+
TestOpenACCSupport.cpp
56

67
EXCLUDE_FROM_LIBMLIR
78
)
@@ -11,6 +12,7 @@ mlir_target_link_libraries(MLIROpenACCTestPasses PUBLIC
1112
MLIRFuncDialect
1213
MLIRMemRefDialect
1314
MLIROpenACCDialect
15+
MLIROpenACCAnalysis
1416
MLIRPass
1517
MLIRSupport
1618
)

mlir/test/lib/Dialect/OpenACC/TestOpenACC.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ namespace test {
1616
// Forward declarations of individual test pass registration functions
1717
void registerTestPointerLikeTypeInterfacePass();
1818
void registerTestRecipePopulatePass();
19+
void registerTestOpenACCSupportPass();
1920

2021
// Unified registration function for all OpenACC tests
2122
void registerTestOpenACC() {
2223
registerTestPointerLikeTypeInterfacePass();
2324
registerTestRecipePopulatePass();
25+
registerTestOpenACCSupportPass();
2426
}
2527

2628
} // namespace test

0 commit comments

Comments
 (0)