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

via flang-commits flang-commits at lists.llvm.org
Fri Apr 10 17:27:04 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Slava Zakharin (vzakhari)

<details>
<summary>Changes</summary>

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.


---
Full diff: https://github.com/llvm/llvm-project/pull/191580.diff


3 Files Affected:

- (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+7-2) 
- (added) flang/test/Analysis/AliasAnalysis/modref-call-memory-effects.fir (+28) 
- (modified) flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp (+49) 


``````````diff
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 8b8cb9c658e4a..c49928e3bad06 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -732,8 +732,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.
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 0000000000000..71f4929255497
--- /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<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
diff --git a/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp b/flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp
index 39aaf8fba180a..19f9ffaa50030 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<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
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/191580


More information about the flang-commits mailing list