[flang-commits] [flang] [flang][AliasAnalysis] Relax AliasAnalysis for host associated alloca… (PR #220826)
Moazin K. via flang-commits
flang-commits at lists.llvm.org
Wed Sep 2 23:48:59 PDT 2026
https://github.com/moazin created https://github.com/llvm/llvm-project/pull/220826
…tables.
FIR alias analysis conservatively returns MayAlias for values with distinct host-associated origins because their storage may overlap through EQUIVALENCE.
This change utilizes the fact that an equivalence object cannot be an allocatable and relaxes the analysis for them. Specifically, if two values have distinct host associated origin, neither is a pointer or a target and at least one of them is an allocatable, we can safely declare them NoAlias. Otherwise, we continue to conservatiely declare them MayAlias.
Assisted-by: Codex
>From 5259e041f1305205d45eb2637458315fa36d4492 Mon Sep 17 00:00:00 2001
From: Moazin Khatti <mkhatti at nvidia.com>
Date: Wed, 5 Aug 2026 13:47:26 -0700
Subject: [PATCH] [flang][AliasAnalysis] Relax AliasAnalysis for host
associated allocatables.
FIR alias analysis conservatively returns MayAlias for values with
distinct host-associated origins because their storage may overlap
through EQUIVALENCE.
This change utilizes the fact that an equivalence object cannot be an
allocatable and relaxes the analysis for them. Specifically, if two
values have distinct host associated origin, neither is a pointer or a
target and at least one of them is an allocatable, we can safely declare
them NoAlias. Otherwise, we continue to conservatiely declare them
MayAlias.
Assisted-by: Codex
---
.../flang/Optimizer/Analysis/AliasAnalysis.h | 4 ++
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 26 +++++++-
.../alias-analysis-host-assoc.fir | 65 +++++++++++++++++++
3 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 32d95d3e09677..98d92e683a2a7 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -287,6 +287,10 @@ struct AliasAnalysis {
/// Return true, if Pointer attribute is set.
bool isPointer() const;
+ /// Return true if the source originates at a Fortran variable declaration
+ /// with the ALLOCATABLE attribute.
+ bool isDeclaredAllocatable() const;
+
/// Return true, if CrayPointer attribute is set.
bool isCrayPointer() const;
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 4322e9ebcd0d1..ad8dd3f13a8c3 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -427,6 +427,18 @@ bool AliasAnalysis::Source::isPointer() const {
return attributes.test(Attribute::Pointer);
}
+bool AliasAnalysis::Source::isDeclaredAllocatable() const {
+ auto isAllocatable = [](mlir::Operation *op) {
+ auto var =
+ mlir::dyn_cast_or_null<fir::FortranVariableOpInterface>(op);
+ return var && var.isAllocatable();
+ };
+
+ auto value = origin.u.dyn_cast<mlir::Value>();
+ return (value && isAllocatable(value.getDefiningOp())) ||
+ isAllocatable(origin.instantiationPoint);
+}
+
bool AliasAnalysis::Source::isCrayPointee() const {
return attributes.test(Attribute::CrayPointee);
}
@@ -831,8 +843,20 @@ AliasResult AliasAnalysis::alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs,
return AliasResult::MayAlias;
}
- // Two host associated accesses may overlap due to an equivalence.
+ // Two host-associated accesses may overlap through EQUIVALENCE, so return
+ // MayAlias conservatively. The exception is distinct data accesses where
+ // at least one is allocatable, since allocatables cannot be EQUIVALENCE
+ // objects, provided neither can participate in pointer association.
if (lhsSrc.kind == SourceKind::HostAssoc) {
+ if (lhsSrc.isData() && rhsSrc.isData() &&
+ !lhsSrc.isTargetOrPointer() && !rhsSrc.isTargetOrPointer() &&
+ (lhsSrc.isDeclaredAllocatable() ||
+ rhsSrc.isDeclaredAllocatable())) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " no alias: distinct host-associated data involving "
+ "an allocatable\n");
+ return AliasResult::NoAlias;
+ }
LLVM_DEBUG(llvm::dbgs() << " aliasing because of host association\n");
return AliasResult::MayAlias;
}
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir
index d570d039432bd..1d26c12de0f0f 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir
@@ -409,3 +409,68 @@ fir.global @_QMglobalsEg target : !fir.array<10xi32> {
%0 = fir.undefined !fir.array<10xi32>
fir.has_value %0 : !fir.array<10xi32>
}
+
+// -----
+
+// subroutine test12
+// integer, allocatable :: a(:), b(:)
+// allocate(a(1), b(1))
+// contains
+// subroutine inner()
+// a(1) = b(1)
+// end subroutine inner
+// end subroutine test12
+
+// Distinct host-associated allocatables cannot overlap through EQUIVALENCE.
+// CHECK: test12_a(1)#0 <-> test12_b(1)#0: NoAlias
+func.func @_QFtest12Pinner(%arg0: !fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+ %c0_i32 = arith.constant 0 : i32
+ %0 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %1 = fir.load %0 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<allocatable, host_assoc>, uniq_name = "_QFtest12Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+ %3 = fir.load %2#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c1 = arith.constant 1 : index
+ %4 = hlfir.designate %3 (%c1) {test.ptr = "test12_a(1)"} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+
+ %c1_i32 = arith.constant 1 : i32
+ %5 = fir.coordinate_of %arg0, %c1_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %6 = fir.load %5 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %7:2 = hlfir.declare %6 {fortran_attrs = #fir.var_attrs<allocatable, host_assoc>, uniq_name = "_QFtest12Eb"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+ %8 = fir.load %7#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c1_0 = arith.constant 1 : index
+ %9 = hlfir.designate %8 (%c1_0) {test.ptr = "test12_b(1)"} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+ return
+}
+
+// -----
+
+// subroutine test13
+// integer, allocatable, target :: a(:)
+// integer, pointer :: p(:)
+// allocate(a(10))
+// p => a
+// contains
+// subroutine inner()
+// a(1) = p(1)
+// end subroutine inner
+// end subroutine test13
+
+// CHECK: test13_a(1)#0 <-> test13_p(1)#0: MayAlias
+func.func @_QFtest13Pinner(%arg0: !fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+ %c0_i32 = arith.constant 0 : i32
+ %0 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %1 = fir.load %0 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<allocatable, target, host_assoc>, uniq_name = "_QFtest13Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+ %3 = fir.load %2#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c1 = arith.constant 1 : index
+ %4 = hlfir.designate %3 (%c1) {test.ptr = "test13_a(1)"} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+
+ %c1_i32 = arith.constant 1 : i32
+ %5 = fir.coordinate_of %arg0, %c1_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+ %6 = fir.load %5 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+ %7:2 = hlfir.declare %6 {fortran_attrs = #fir.var_attrs<pointer, host_assoc>, uniq_name = "_QFtest13Ep"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+ %8 = fir.load %7#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %c1_0 = arith.constant 1 : index
+ %9 = hlfir.designate %8 (%c1_0) {test.ptr = "test13_p(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+ return
+}
More information about the flang-commits
mailing list