diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h index 8d3fa36cbed5b..8dd0ef5a6e49f 100644 --- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h +++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h @@ -55,6 +55,9 @@ class AliasAnalysis { mlir::Type valueType; /// Attributes of the memory source object, e.g. Target. Attributes attributes; + /// Have we lost precision following the source such that + /// even an exact match cannot be MustAlias? + bool approximateSource; /// Print information about the memory source to `os`. void print(llvm::raw_ostream &os) const; diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 3d4b9e9b24263..147c0658952b3 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -71,6 +71,7 @@ bool AliasAnalysis::Source::isRecordWithPointerComponent() const { AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { auto lhsSrc = getSource(lhs); auto rhsSrc = getSource(rhs); + bool approximateSource = lhsSrc.approximateSource || rhsSrc.approximateSource; LLVM_DEBUG(llvm::dbgs() << "AliasAnalysis::alias\n"; llvm::dbgs() << " lhs: " << lhs << "\n"; llvm::dbgs() << " lhsSrc: " << lhsSrc << "\n"; @@ -86,8 +87,11 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { return AliasResult::MayAlias; if (lhsSrc.kind == rhsSrc.kind) { - if (lhsSrc.u == rhsSrc.u) + if (lhsSrc.u == rhsSrc.u) { + if (approximateSource) + return AliasResult::MayAlias; return AliasResult::MustAlias; + } // Allocate and global memory address cannot physically alias if (lhsSrc.kind == SourceKind::Allocate || @@ -195,6 +199,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { SourceKind type{SourceKind::Unknown}; mlir::Type ty; bool breakFromLoop{false}; + bool approximateSource{false}; mlir::SymbolRefAttr global; Source::Attributes attributes; while (defOp && !breakFromLoop) { @@ -234,6 +239,19 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { v = op.getMemref(); defOp = v.getDefiningOp(); }) + .Case([&](auto op) { + // Track further through the memory indexed into + // => if the source arrays/structures don't alias then nor do the + // results of hlfir.designate + v = op.getMemref(); + defOp = v.getDefiningOp(); + // TODO: there will be some cases which provably don't alias if one + // takes into account the component or indices, which are currently + // ignored here - leading to false positives + // because of this limitation, we need to make sure we never return + // MustAlias after going through a designate operation + approximateSource = true; + }) .Default([&](auto op) { defOp = nullptr; breakFromLoop = true; @@ -252,9 +270,9 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { } if (type == SourceKind::Global) - return {global, type, ty, attributes}; + return {global, type, ty, attributes, approximateSource}; - return {v, type, ty, attributes}; + return {v, type, ty, attributes, approximateSource}; } } // namespace fir diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-4.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-4.fir new file mode 100644 index 0000000000000..24baab80f83e9 --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-4.fir @@ -0,0 +1,73 @@ +// check that hlfir.designate can be followed by alias analysis + +// use --mlir-disable-threading so that the AA queries are serialised +// as well as its diagnostic output. +// RUN: fir-opt %s --test-fir-alias-analysis -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s + +// designate for a derived type component: +// module m +// type t +// real :: array(42) +// end type t +// type (t) :: glbl +// contains +// subroutine test(arg) +// real :: arg(42) +// glbl%array = arg +// end subroutine test +// end module m + +// A global can't alias with a dummy argument +// CHECK: arg#0 <-> glbl%array#0: NoAlias + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} { + fir.global @_QMmEglbl : !fir.type<_QMmTt{array:!fir.array<42xf32>}> { + %0 = fir.undefined !fir.type<_QMmTt{array:!fir.array<42xf32>}> + fir.has_value %0 : !fir.type<_QMmTt{array:!fir.array<42xf32>}> + } + func.func @_QMmPtest(%arg0: !fir.ref> {fir.bindc_name = "arg"}) { + %c42 = arith.constant 42 : index + %0 = fir.address_of(@_QMmEglbl) : !fir.ref}>> + %1:2 = hlfir.declare %0 {uniq_name = "_QMmEglbl"} : (!fir.ref}>>) -> (!fir.ref}>>, !fir.ref}>>) + %2 = fir.shape %c42 : (index) -> !fir.shape<1> + %3:2 = hlfir.declare %arg0(%2) {uniq_name = "_QMmFtestEarg", test.ptr = "arg"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + %4 = hlfir.designate %1#0{"array"} shape %2 {test.ptr = "glbl%array"} : (!fir.ref}>>, !fir.shape<1>) -> !fir.ref> + hlfir.assign %3#0 to %4 : !fir.ref>, !fir.ref> + return + } +} + +// ----- + +// designate for an array element + +// two dummy arguments don't alias +// CHECK: array0#0 <-> array1#0: NoAlias + +func.func @array_element(%arg0: !fir.ref>, %arg1: !fir.ref>) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c41 = arith.constant 41 : index + %c42 = arith.constant 42 : index + %shape = fir.shape %c42 : (index) -> !fir.shape<1> + %array0 = hlfir.designate %arg0 (%c0, %c0:%c41:%c1) shape %shape {test.ptr = "array0"} : (!fir.ref>, index, index, index, index, !fir.shape<1>) -> !fir.box> + %array1 = hlfir.designate %arg1 (%c1, %c0:%c41:%c1) shape %shape {test.ptr = "array1"} : (!fir.ref>, index, index, index, index, !fir.shape<1>) -> !fir.box> + return +} + +// ----- + +// FIXME: designate doesn't understand non-overlappning array indices +// make sure that we say MayAlias and not MustAlias until array indexes are understood +// CHECK: array2#0 <-> array3#0: MayAlias + +func.func @array_element_same_source(%arg0: !fir.ref>) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c41 = arith.constant 41 : index + %c42 = arith.constant 42 : index + %shape = fir.shape %c42 : (index) -> !fir.shape<1> + %array2 = hlfir.designate %arg0 (%c0, %c0:%c41:%c1) shape %shape {test.ptr = "array2"} : (!fir.ref>, index, index, index, index, !fir.shape<1>) -> !fir.box> + %array3 = hlfir.designate %arg0 (%c1, %c0:%c41:%c1) shape %shape {test.ptr = "array3"} : (!fir.ref>, index, index, index, index, !fir.shape<1>) -> !fir.box> + return +} \ No newline at end of file