diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index ea97f2228651..2509334b8ec4 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -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(op)) - return getCallModRef(call, location); + if (auto call = llvm::dyn_cast(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. diff --git a/flang/test/Analysis/AliasAnalysis/modref-call-memory-effects.fir b/flang/test/Analysis/AliasAnalysis/modref-call-memory-effects.fir new file mode 100644 index 000000000000..71f492925549 --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/modref-call-memory-effects.fir @@ -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) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.declare %arg0 dummy_scope %0 arg 1 {test.ptr = "x", uniq_name = "_QFtestEx"} : (!fir.ref, !fir.dscope) -> !fir.ref + 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 diff --git a/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp b/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp index 39aaf8fba180..19f9ffaa5003 100644 --- a/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp +++ b/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp @@ -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 { + void getEffects(Operation *op, + llvm::SmallVectorImpl> + &effects) const { + auto call = cast(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> { + 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(*ctx); + + AliasAnalysis aliasAnalysis(getOperation()); + aliasAnalysis.addAnalysisImplementation(fir::AliasAnalysis()); + runAliasAnalysisOnOperation(getOperation(), aliasAnalysis); + } +}; } // namespace //===----------------------------------------------------------------------===// @@ -67,6 +115,7 @@ namespace test { void registerTestFIRAliasAnalysisPass() { PassRegistration(); PassRegistration(); + PassRegistration(); } } // namespace test } // namespace fir \ No newline at end of file