[flang-commits] [flang] [flang] AliasAnalysis: distinguish addr of arg vs. addr in arg (PR #87723)
via flang-commits
flang-commits at lists.llvm.org
Thu Apr 4 15:32:01 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Joel E. Denny (jdenny-ornl)
<details>
<summary>Changes</summary>
For example, in the following program, the relationship between the address *in* arg (dynamically the address of x's alloca) and the address *of* arg (dynamically the address of p's alloca) is not MustAlias, as determined without this patch:
```
subroutine f()
real, pointer :: p
real, target :: x
p => x
call g(p)
end subroutine f
subroutine g(arg)
real, pointer :: arg
end subroutine g
```
Generally extend test coverage for HLFIR-based alias analysis for addresses extracted from pointers.
---
Full diff: https://github.com/llvm/llvm-project/pull/87723.diff
4 Files Affected:
- (modified) flang/include/flang/Optimizer/Analysis/AliasAnalysis.h (+2-2)
- (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+15-5)
- (modified) flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir (+1-1)
- (added) flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir (+90)
``````````diff
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index dfcafe88fee1b5..dd4eb363cc7277 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -36,8 +36,8 @@ struct AliasAnalysis {
/// Represents memory allocated outside of a function
/// and passed to the function via host association tuple.
HostAssoc,
- /// Represents direct memory access whose source cannot be further
- /// determined
+ /// Memory address retrieved from a box, perhaps from a global or
+ /// an argument.
Direct,
/// Represents memory allocated by unknown means and
/// with the memory address defined by a memory reading
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index e144640081cbf3..f0af0dd547f980 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -91,8 +91,14 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
LLVM_DEBUG(llvm::dbgs() << "AliasAnalysis::alias\n";
llvm::dbgs() << " lhs: " << lhs << "\n";
llvm::dbgs() << " lhsSrc: " << lhsSrc << "\n";
+ llvm::dbgs() << " lhsSrc kind: " << EnumToString(lhsSrc.kind) << "\n";
+ llvm::dbgs() << " lhsSrc pointer: " << lhsSrc.attributes.test(Attribute::Pointer) << "\n";
+ llvm::dbgs() << " lhsSrc target: " << lhsSrc.attributes.test(Attribute::Target) << "\n";
llvm::dbgs() << " rhs: " << rhs << "\n";
llvm::dbgs() << " rhsSrc: " << rhsSrc << "\n";
+ llvm::dbgs() << " rhsSrc kind: " << EnumToString(rhsSrc.kind) << "\n";
+ llvm::dbgs() << " rhsSrc pointer: " << rhsSrc.attributes.test(Attribute::Pointer) << "\n";
+ llvm::dbgs() << " rhsSrc target: " << rhsSrc.attributes.test(Attribute::Target) << "\n";
llvm::dbgs() << "\n";);
// Indirect case currently not handled. Conservatively assume
@@ -101,8 +107,10 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::MayAlias;
}
- // SourceKind::Direct is set for the addresses wrapped in a global boxes.
- // ie: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+ // SourceKind::Direct is set for the addresses wrapped in a box, perhaps from
+ // a global or an argument.
+ // e.g.: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+ // e.g.: %arg0: !fir.ref<!fir.box<!fir.ptr<f32>>>
// Though nothing is known about them, they would only alias with targets or
// pointers
bool directSourceToNonTargetOrPointer = false;
@@ -399,16 +407,18 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
if (!defOp && type == SourceKind::Unknown)
// Check if the memory source is coming through a dummy argument.
if (isDummyArgument(v)) {
- type = SourceKind::Argument;
ty = v.getType();
if (fir::valueHasFirAttribute(v, fir::getTargetAttrName()))
attributes.set(Attribute::Target);
-
if (Source::isPointerReference(ty))
attributes.set(Attribute::Pointer);
+ if (followBoxAddr && attributes.test(Attribute::Pointer))
+ type = SourceKind::Direct;
+ else
+ type = SourceKind::Argument;
}
- if (type == SourceKind::Global || type == SourceKind::Direct)
+ if (global)
return {global, type, ty, attributes, approximateSource};
return {v, type, ty, attributes, approximateSource};
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
index 31459ef21d947c..d915ba9d27905a 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
@@ -44,7 +44,7 @@
// pointer arguments
// CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias
-// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MustAlias
+// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MayAlias
// CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias
func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir
new file mode 100644
index 00000000000000..de1b478fa9599e
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir
@@ -0,0 +1,90 @@
+// Check aliasing with the address passed via a pointer dummy argument.
+
+// Use --mlir-disable-threading so that the AA queries are serialized
+// as well as its diagnostic output.
+// RUN: fir-opt %s \
+// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
+// RUN: --mlir-disable-threading 2>&1 | FileCheck %s
+
+// subroutine test(p0, p1, arr, t_arr, alloc, t_alloc)
+// real, pointer :: p0, p1
+// real :: arr(:)
+// real, target :: t_arr(:)
+// real, allocatable :: alloc
+// real, allocatable, target :: t_alloc
+// real, target :: t
+// real :: v
+// v = p0
+// v = p1
+// v = arr(1)
+// v = t_arr(1)
+// v = alloc
+// v = t_alloc
+// end subroutine test
+
+// CHECK-LABEL: Testing : "_QPtest"
+
+// The address in a pointer can alias the address in another pointer or the
+// address of a target but not the address of other variables.
+// CHECK-DAG: t.addr#0 <-> p0.tgt_addr#0: MayAlias
+// CHECK-DAG: t.addr#0 <-> p1.tgt_addr#0: MayAlias
+// CHECK-DAG: v.addr#0 <-> p0.tgt_addr#0: NoAlias
+// CHECK-DAG: v.addr#0 <-> p1.tgt_addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> p1.tgt_addr#0: MayAlias
+
+// Determining whether the address *in* a pointer can alias the address *of* a
+// pointer is not yet handled. In the past, when it was the same pointer, that
+// relationship was mistakenly determined to be MustAlias.
+// CHECK-DAG: p0.tgt_addr#0 <-> func.region0#0: MayAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> func.region0#1: MayAlias
+// CHECK-DAG: p1.tgt_addr#0 <-> func.region0#0: MayAlias
+// CHECK-DAG: p1.tgt_addr#0 <-> func.region0#1: MayAlias
+
+// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so
+// make sure it doesn't mistakenly see arr(1).addr as an address that was loaded
+// from a pointer and that could alias something. However, t_arr is a target.
+// CHECK-DAG: p0.tgt_addr#0 <-> arr(1).addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> t_arr(1).addr#0: MayAlias
+
+// Like a pointer, an allocatable contains an address, but an allocatable is not
+// a pointer and so cannot alias pointers. However, t_alloc is a target.
+// CHECK-DAG: p0.tgt_addr#0 <-> alloc.tgt_addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> t_alloc.tgt_addr#0: MayAlias
+
+func.func @_QPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p0"}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg2: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "arr"}, %arg3: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "t_arr", fir.target}, %arg4: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "alloc"}, %arg5: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "t_alloc", fir.target}) attributes {test.ptr="func"} {
+ %0:2 = hlfir.declare %arg4 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+ %1:2 = hlfir.declare %arg2 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+ %2:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+ %3:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+ %4 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+ %5:2 = hlfir.declare %4 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt", test.ptr="t.addr"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %6:2 = hlfir.declare %arg5 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+ %7:2 = hlfir.declare %arg3 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+ %8 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+ %9:2 = hlfir.declare %8 {uniq_name = "_QFtestEv", test.ptr="v.addr"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %10 = fir.load %2#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %11 = fir.box_addr %10 {test.ptr="p0.tgt_addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %12 = fir.load %11 : !fir.ptr<f32>
+ hlfir.assign %12 to %9#0 : f32, !fir.ref<f32>
+ %13 = fir.load %3#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %14 = fir.box_addr %13 {test.ptr="p1.tgt_addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %15 = fir.load %14 : !fir.ptr<f32>
+ hlfir.assign %15 to %9#0 : f32, !fir.ref<f32>
+ %c1 = arith.constant 1 : index
+ %16 = hlfir.designate %1#0 (%c1) {test.ptr="arr(1).addr"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+ %17 = fir.load %16 : !fir.ref<f32>
+ hlfir.assign %17 to %9#0 : f32, !fir.ref<f32>
+ %c1_0 = arith.constant 1 : index
+ %18 = hlfir.designate %7#0 (%c1_0) {test.ptr="t_arr(1).addr"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+ %19 = fir.load %18 : !fir.ref<f32>
+ hlfir.assign %19 to %9#0 : f32, !fir.ref<f32>
+ %20 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %21 = fir.box_addr %20 {test.ptr="alloc.tgt_addr"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ %22 = fir.load %21 : !fir.heap<f32>
+ hlfir.assign %22 to %9#0 : f32, !fir.ref<f32>
+ %23 = fir.load %6#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %24 = fir.box_addr %23 {test.ptr="t_alloc.tgt_addr"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ %25 = fir.load %24 : !fir.heap<f32>
+ hlfir.assign %25 to %9#0 : f32, !fir.ref<f32>
+ return
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/87723
More information about the flang-commits
mailing list