[flang][test] Experimental support of MemoryEffectOpInterface for fir.call. (#191580)

I would like to experiment with `fir.call` implementing
`MemoryEffectOpInterface`. So the main change is the fall-through
path in FIR AA. It should be NFC for Flang.
This commit is contained in:
Slava Zakharin authored and GitHub committed 2026-04-15 12:40:36 -07:00
1 parent cdfd0b60d2
commit 89e736d1df
3 files changed
+84 -2

No files matched your search

@@ -724,8 +724,13 @@ ModRefResult AliasAnalysis::getCallModRef(Operation *op, Value var) {
/// This is mostly inspired by MLIR::LocalAliasAnalysis, except that
/// fir.call's are handled in a special way.
ModRefResult AliasAnalysis::getModRef(Operation *op, Value location) {
if (auto call = llvm::dyn_cast<fir::CallOp>(op))
return getCallModRef(call, location);
if (auto call = llvm::dyn_cast<fir::CallOp>(op)) {
ModRefResult result = getCallModRef(call, location);
if (result != ModRefResult::getModAndRef())
return result;
// Proceed to MemoryEffectOpInterface analysis in case one
// is attached for fir.call.
}
// Build a ModRefResult by merging the behavior of the effects of this
// operation.
@@ -0,0 +1,28 @@
// RUN: fir-opt -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis-modref-call-effects))' \
// RUN: --mlir-disable-threading %s -o /dev/null 2>&1 | FileCheck %s
// Test that when MemoryEffectOpInterface is externally attached to fir.call,
// fir::AliasAnalysis::getModRef uses it to refine the result after
// getCallModRef returns ModAndRef.
// The test infrastructure attaches MemoryEffectOpInterface to fir::CallOp
// such that calls to functions starting with "test_pure" have no memory
// effects, while all other calls read and write DefaultResource.
// "test_pure_call" has no memory effects via the attached interface,
// so it cannot modify or reference the variable.
// "test_impure_call" reads and writes DefaultResource without specifying
// a value, so alias analysis conservatively reports ModRef.
func.func @test_call_effects(%arg0: !fir.ref<f32>) {
%0 = fir.dummy_scope : !fir.dscope
%1 = fir.declare %arg0 dummy_scope %0 arg 1 {test.ptr = "x", uniq_name = "_QFtestEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
fir.call @test_pure_call() {test.ptr = "pure_call"} : () -> ()
fir.call @test_impure_call() {test.ptr = "impure_call"} : () -> ()
return
}
func.func private @test_pure_call()
func.func private @test_impure_call()
// CHECK-LABEL: Testing : "test_call_effects"
// CHECK-DAG: pure_call -> x#0: NoModRef
// CHECK-DAG: impure_call -> x#0: ModRef
@@ -8,8 +8,10 @@
#include "mlir/test/lib/Analysis/TestAliasAnalysis.h"
#include "mlir/Analysis/AliasAnalysis.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Pass/Pass.h"
#include "flang/Optimizer/Analysis/AliasAnalysis.h"
#include "flang/Optimizer/Dialect/FIROps.h"
using namespace mlir;
@@ -56,6 +58,52 @@ struct TestFIRAliasAnalysisModRefPass
runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
}
};
//===----------------------------------------------------------------------===//
// Testing ModRefResult with MemoryEffectOpInterface attached to fir.call
//===----------------------------------------------------------------------===//
/// External model that attaches MemoryEffectOpInterface to fir::CallOp.
/// Calls to functions whose name starts with "test_pure" have no memory
/// effects; all other calls read and write DefaultResource.
struct TestCallMemoryEffectsModel
: public MemoryEffectOpInterface::ExternalModel<TestCallMemoryEffectsModel,
fir::CallOp> {
void getEffects(Operation *op,
llvm::SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
&effects) const {
auto call = cast<fir::CallOp>(op);
if (auto callee = call.getCallee())
if (callee->getLeafReference().getValue().starts_with("test_pure"))
return;
effects.emplace_back(
MemoryEffects::Read::get(), SideEffects::DefaultResource::get());
effects.emplace_back(
MemoryEffects::Write::get(), SideEffects::DefaultResource::get());
}
};
struct TestFIRAliasAnalysisModRefCallEffectsPass
: public test::TestAliasAnalysisModRefBase,
PassWrapper<TestFIRAliasAnalysisModRefCallEffectsPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(
TestFIRAliasAnalysisModRefCallEffectsPass)
StringRef getArgument() const final {
return "test-fir-alias-analysis-modref-call-effects";
}
StringRef getDescription() const final {
return "Test alias analysis ModRef results with MemoryEffectOpInterface "
"attached to fir.call.";
}
void runOnOperation() override {
MLIRContext *ctx = &getContext();
fir::CallOp::attachInterface<TestCallMemoryEffectsModel>(*ctx);
AliasAnalysis aliasAnalysis(getOperation());
aliasAnalysis.addAnalysisImplementation(fir::AliasAnalysis());
runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
}
};
} // namespace
//===----------------------------------------------------------------------===//
@@ -67,6 +115,7 @@ namespace test {
void registerTestFIRAliasAnalysisPass() {
PassRegistration<TestFIRAliasAnalysisPass>();
PassRegistration<TestFIRAliasAnalysisModRefPass>();
PassRegistration<TestFIRAliasAnalysisModRefCallEffectsPass>();
}
} // namespace test
} // namespace fir