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
135 changes: 135 additions & 0 deletions mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//===- OpenACCSupport.h - OpenACC Support Interface -------------*- 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 OpenACCSupport analysis interface, which provides
// extensible support for OpenACC passes. Custom implementations
// can be registered to provide pipeline and dialect-specific information
// that cannot be adequately expressed through type or operation interfaces
// alone.
//
// Usage Pattern:
// ==============
//
// A pass that needs this functionality should call
// getAnalysis<OpenACCSupport>(), which will provide either:
// - A cached version if previously initialized, OR
// - A default implementation if not previously initialized
//
// This analysis is never invalidated (isInvalidated returns false), so it only
// needs to be initialized once and will persist throughout the pass pipeline.
//
// Registering a Custom Implementation:
// =====================================
//
// If a custom implementation is needed, create a pass that runs BEFORE the pass
// that needs the analysis. In this setup pass, use
// getAnalysis<OpenACCSupport>() followed by setImplementation() to register
// your custom implementation. The custom implementation will need to provide
// implementation for all methods defined in the `OpenACCSupportTraits::Concept`
// class.
//
// Example:
// void MySetupPass::runOnOperation() {
// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
// support.setImplementation(MyCustomImpl());
// }
//
// void MyAnalysisConsumerPass::runOnOperation() {
// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
// std::string name = support.getVariableName(someValue);
// // ... use the analysis results
// }
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
#define MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H

#include "mlir/IR/Value.h"
#include "mlir/Pass/AnalysisManager.h"
#include <memory>
#include <string>

namespace mlir {
namespace acc {

namespace detail {
/// This class contains internal trait classes used by OpenACCSupport.
/// It follows the Concept-Model pattern used throughout MLIR (e.g., in
/// AliasAnalysis and interface definitions).
struct OpenACCSupportTraits {
class Concept {
public:
virtual ~Concept() = default;

/// Get the variable name for a given MLIR value.
virtual std::string getVariableName(Value v) = 0;
};

/// This class wraps a concrete OpenACCSupport implementation and forwards
/// interface calls to it. This provides type erasure, allowing different
/// implementation types to be used interchangeably without inheritance.
template <typename ImplT>
class Model final : public Concept {
public:
explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
~Model() override = default;

std::string getVariableName(Value v) final {
return impl.getVariableName(v);
}

private:
ImplT impl;
};
};
} // namespace detail

//===----------------------------------------------------------------------===//
// OpenACCSupport
//===----------------------------------------------------------------------===//

class OpenACCSupport {
using Concept = detail::OpenACCSupportTraits::Concept;
template <typename ImplT>
using Model = detail::OpenACCSupportTraits::Model<ImplT>;

public:
OpenACCSupport() = default;
OpenACCSupport(Operation *op) {}

/// Register a custom OpenACCSupport implementation. Only one implementation
/// can be registered at a time; calling this replaces any existing
/// implementation.
template <typename AnalysisT>
void setImplementation(AnalysisT &&analysis) {
impl =
std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis));
}

/// Get the variable name for a given value.
///
/// \param v The MLIR value to get the variable name for.
/// \return The variable name, or an empty string if unavailable.
std::string getVariableName(Value v);

/// Signal that this analysis should always be preserved so that
/// underlying implementation registration is not lost.
bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
return false;
}

private:
/// The registered custom implementation (if any).
std::unique_ptr<Concept> impl;
};

} // namespace acc
} // namespace mlir

#endif // MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
5 changes: 5 additions & 0 deletions mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ std::optional<ClauseDefaultValue> getDefaultAttr(mlir::Operation *op);
/// Get the type category of an OpenACC variable.
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Value var);

/// Attempts to extract the variable name from a value by walking through
/// view-like operations until an `acc.var_name` attribute is found. Returns
/// empty string if no name is found.
std::string getVariableName(mlir::Value v);

} // namespace acc
} // namespace mlir

Expand Down
13 changes: 13 additions & 0 deletions mlir/lib/Dialect/OpenACC/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_mlir_dialect_library(MLIROpenACCAnalysis
OpenACCSupport.cpp

ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/OpenACC

LINK_LIBS PUBLIC
MLIRIR
MLIROpenACCDialect
MLIROpenACCUtils
MLIRSupport
)

26 changes: 26 additions & 0 deletions mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===- OpenACCSupport.cpp - OpenACCSupport Implementation -----------------===//
//
// 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 OpenACCSupport analysis interface.
//
//===----------------------------------------------------------------------===//

#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"

namespace mlir {
namespace acc {

std::string OpenACCSupport::getVariableName(Value v) {
if (impl)
return impl->getVariableName(v);
return acc::getVariableName(v);
}

} // namespace acc
} // namespace mlir
1 change: 1 addition & 0 deletions mlir/lib/Dialect/OpenACC/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(Analysis)
add_subdirectory(IR)
add_subdirectory(Utils)
add_subdirectory(Transforms)
28 changes: 28 additions & 0 deletions mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"

#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Interfaces/ViewLikeInterface.h"
#include "llvm/ADT/TypeSwitch.h"

mlir::Operation *mlir::acc::getEnclosingComputeOp(mlir::Region &region) {
Expand Down Expand Up @@ -78,3 +79,30 @@ mlir::acc::VariableTypeCategory mlir::acc::getTypeCategory(mlir::Value var) {
pointerLikeTy.getElementType());
return typeCategory;
}

std::string mlir::acc::getVariableName(mlir::Value v) {
Value current = v;

// Walk through view operations until a name is found or can't go further
while (Operation *definingOp = current.getDefiningOp()) {
// Check for `acc.var_name` attribute
if (auto varNameAttr =
definingOp->getAttrOfType<VarNameAttr>(getVarNameAttrName()))
return varNameAttr.getName().str();

// If it is a data entry operation, get name via getVarName
if (isa<ACC_DATA_ENTRY_OPS>(definingOp))
if (auto name = acc::getVarName(definingOp))
return name->str();

// If it's a view operation, continue to the source
if (auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
current = viewOp.getViewSource();
continue;
}

break;
}

return "";
}
88 changes: 88 additions & 0 deletions mlir/test/Dialect/OpenACC/support-analysis-varname.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// RUN: mlir-opt %s -split-input-file -test-acc-support | FileCheck %s

// Test with direct variable names
func.func @test_direct_var_name() {
// Create a memref with acc.var_name attribute
%0 = memref.alloca() {acc.var_name = #acc.var_name<"my_variable">} : memref<10xi32>

%1 = memref.cast %0 {test.var_name} : memref<10xi32> to memref<10xi32>

// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
// CHECK-NEXT: getVariableName="my_variable"

return
}

// -----

// Test through memref.cast
func.func @test_through_cast() {
// Create a 5x2 memref with acc.var_name attribute
%0 = memref.alloca() {acc.var_name = #acc.var_name<"casted_variable">} : memref<5x2xi32>

// Cast to dynamic dimensions
%1 = memref.cast %0 : memref<5x2xi32> to memref<?x?xi32>

// Mark with test attribute - should find name through cast
%2 = memref.cast %1 {test.var_name} : memref<?x?xi32> to memref<5x2xi32>

// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<?x?xi32> to memref<5x2xi32>
// CHECK-NEXT: getVariableName="casted_variable"

return
}

// -----

// Test with no variable name
func.func @test_no_var_name() {
// Create a memref without acc.var_name attribute
%0 = memref.alloca() : memref<10xi32>

// Mark with test attribute - should find empty string
%1 = memref.cast %0 {test.var_name} : memref<10xi32> to memref<10xi32>

// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
// CHECK-NEXT: getVariableName=""

return
}

// -----

// Test through multiple casts
func.func @test_multiple_casts() {
// Create a memref with acc.var_name attribute
%0 = memref.alloca() {acc.var_name = #acc.var_name<"multi_cast">} : memref<10xi32>

// Multiple casts
%1 = memref.cast %0 : memref<10xi32> to memref<?xi32>
%2 = memref.cast %1 : memref<?xi32> to memref<10xi32>

// Mark with test attribute - should find name through multiple casts
%3 = memref.cast %2 {test.var_name} : memref<10xi32> to memref<10xi32>

// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xi32> to memref<10xi32>
// CHECK-NEXT: getVariableName="multi_cast"

return
}

// -----

// Test with acc.copyin operation
func.func @test_copyin_name() {
// Create a memref
%0 = memref.alloca() : memref<10xf32>

// Create an acc.copyin operation with a name
%1 = acc.copyin varPtr(%0 : memref<10xf32>) -> memref<10xf32> {name = "input_data"}

// Mark with test attribute - should find name from copyin operation
%2 = memref.cast %1 {test.var_name} : memref<10xf32> to memref<?xf32>

// CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.var_name} : memref<10xf32> to memref<?xf32>
// CHECK-NEXT: getVariableName="input_data"

return
}
2 changes: 2 additions & 0 deletions mlir/test/lib/Dialect/OpenACC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_mlir_library(MLIROpenACCTestPasses
TestOpenACC.cpp
TestPointerLikeTypeInterface.cpp
TestRecipePopulate.cpp
TestOpenACCSupport.cpp

EXCLUDE_FROM_LIBMLIR
)
Expand All @@ -11,6 +12,7 @@ mlir_target_link_libraries(MLIROpenACCTestPasses PUBLIC
MLIRFuncDialect
MLIRMemRefDialect
MLIROpenACCDialect
MLIROpenACCAnalysis
MLIRPass
MLIRSupport
)
Expand Down
2 changes: 2 additions & 0 deletions mlir/test/lib/Dialect/OpenACC/TestOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ namespace test {
// Forward declarations of individual test pass registration functions
void registerTestPointerLikeTypeInterfacePass();
void registerTestRecipePopulatePass();
void registerTestOpenACCSupportPass();

// Unified registration function for all OpenACC tests
void registerTestOpenACC() {
registerTestPointerLikeTypeInterfacePass();
registerTestRecipePopulatePass();
registerTestOpenACCSupportPass();
}

} // namespace test
Expand Down
Loading