diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 01f3a0326db2..5827d1c3c529 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -51,7 +51,7 @@ static bool hasGlobalOpTargetAttr(mlir::Value v, fir::AddrOfOp op) { v, fir::GlobalOp::getTargetAttrName(globalOpName)); } -mlir::Value getOriginalDef(mlir::Value v) { +static mlir::Value getOriginalDef(mlir::Value v) { mlir::Operation *defOp; bool breakFromLoop = false; while (!breakFromLoop && (defOp = v.getDefiningOp())) { @@ -578,16 +578,6 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, breakFromLoop = true; }) .Case([&](auto op) { - // If the load is from a leaf source, return the leaf. Do not track - // through indirections otherwise. - // TODO: Add support to fir.alloca and fir.allocmem - auto def = getOriginalDef(op.getMemref()); - if (isDummyArgument(def) || - def.template getDefiningOp()) { - v = def; - defOp = v.getDefiningOp(); - return; - } // If load is inside target and it points to mapped item, // continue tracking. Operation *loadMemrefOp = op.getMemref().getDefiningOp(); @@ -600,6 +590,40 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, defOp = v.getDefiningOp(); return; } + + // If we are loading a box reference, but following the data, + // we gather the attributes of the box to populate the source + // and stop tracking. + if (auto boxTy = mlir::dyn_cast(ty); + boxTy && followingData) { + + if (mlir::isa(boxTy.getEleTy())) + attributes.set(Attribute::Pointer); + + auto def = getOriginalDef(op.getMemref()); + if (auto addrOfOp = def.template getDefiningOp()) { + global = addrOfOp.getSymbol(); + + if (hasGlobalOpTargetAttr(def, addrOfOp)) + attributes.set(Attribute::Target); + + type = SourceKind::Global; + } + + // TODO: Add support to fir.alloca and fir.allocmem + // if (auto allocOp = def.template getDefiningOp()) { + // ... + // } + + if (isDummyArgument(def)) { + defOp = nullptr; + v = def; + } + + breakFromLoop = true; + return; + } + // No further tracking for addresses loaded from memory for now. type = SourceKind::Indirect; breakFromLoop = true; diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir index ca97c5900281..24cfaf6ed7ec 100644 --- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir @@ -47,13 +47,15 @@ // CHECK-DAG: arg2.load#0 <-> arg2.addr#0: MustAlias // CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias -// TODO: Can the address in a pointer alias the address of a pointer, even when the +// TODO: Can the address in a pointer alias the address of a pointer, when the // pointer has no box. Should this be NoAlias? -// T3: CHECK-DAG: p1.addr#0 <-> p1.tgt#0: MayAlias +// T3 from . +// CHECK-DAG: p1.addr#0 <-> p1.tgt#0: MayAlias // The addresses stored in two different pointers can alias, even if one has no // box. In this program, they happen to be the same address. -// T4: CHECK-DAG: p1.tgt#0 <-> boxp1.addr#0: MayAlias +// T4: +// CHECK-DAG: p1.tgt#0 <-> boxp1.addr#0: MayAlias func.func @_QFPtest(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref>> ) attributes {test.ptr = "func"} { diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-target.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-target.fir new file mode 100644 index 000000000000..8e88b508d56e --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-target.fir @@ -0,0 +1,82 @@ +// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' 2>&1 | FileCheck %s + +// The test was obtained from +// bbc test.f90 -emit-fir +// module mod +// real, pointer :: p0 +// real, allocatable :: alloc +// real, allocatable, target :: t_alloc +// real, target :: t +// real :: v +// end module +// +// subroutine test(n) +// use mod +// integer :: n +// real r1 +// p0 => t_alloc +// v = alloc +// r1 = p0 +// end subroutine test + +// Checking that aliasing can only happen with an entity with the target attribute +// +// CHECK-DAG: r1#0 <-> t_alloc#0: NoAlias +// CHECK-DAG: r1#0 <-> alloc#0: NoAlias +// CHECK-DAG: t_alloc#0 <-> alloc#0: NoAlias +// CHECK-DAG: r1#0 <-> p0.ptr#0: NoAlias +// CHECK-DAG: t_alloc#0 <-> p0.ptr#0: MayAlias +// CHECK-DAG: alloc#0 <-> p0.ptr#0: NoAlias + +fir.global @_QMmodEalloc : !fir.box> { + %0 = fir.zero_bits !fir.heap + %1 = fir.embox %0 : (!fir.heap) -> !fir.box> + fir.has_value %1 : !fir.box> +} +fir.global @_QMmodEp0 : !fir.box> { + %0 = fir.zero_bits !fir.ptr + %1 = fir.embox %0 : (!fir.ptr) -> !fir.box> + fir.has_value %1 : !fir.box> +} +fir.global @_QMmodEt target : f32 { + %0 = fir.zero_bits f32 + fir.has_value %0 : f32 +} +fir.global @_QMmodEt_alloc target : !fir.box> { + %0 = fir.zero_bits !fir.heap + %1 = fir.embox %0 : (!fir.heap) -> !fir.box> + fir.has_value %1 : !fir.box> +} +fir.global @_QMmodEv : f32 { + %0 = fir.zero_bits f32 + fir.has_value %0 : f32 +} +func.func @_QPtest(%arg0: !fir.ref {fir.bindc_name = "n"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.address_of(@_QMmodEalloc) : !fir.ref>> + %2 = fir.declare %1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodEalloc"} : (!fir.ref>>) -> !fir.ref>> + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtestEn"} : (!fir.ref, !fir.dscope) -> !fir.ref + %4 = fir.address_of(@_QMmodEp0) : !fir.ref>> + %5 = fir.declare %4 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodEp0"} : (!fir.ref>>) -> !fir.ref>> + %6 = fir.alloca f32 {bindc_name = "r1", uniq_name = "_QFtestEr1"} + %7 = fir.declare %6 {test.ptr="r1", uniq_name = "_QFtestEr1"} : (!fir.ref) -> !fir.ref + %8 = fir.address_of(@_QMmodEt) : !fir.ref + %9 = fir.declare %8 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodEt"} : (!fir.ref) -> !fir.ref + %10 = fir.address_of(@_QMmodEt_alloc) : !fir.ref>> + %11 = fir.declare %10 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodEt_alloc"} : (!fir.ref>>) -> !fir.ref>> + %12 = fir.address_of(@_QMmodEv) : !fir.ref + %13 = fir.declare %12 {uniq_name = "_QMmodEv"} : (!fir.ref) -> !fir.ref + %14 = fir.load %11 : !fir.ref>> + %15 = fir.box_addr %14 {test.ptr="t_alloc"}: (!fir.box>) -> !fir.heap + %16 = fir.embox %15 : (!fir.heap) -> !fir.box> + fir.store %16 to %5 : !fir.ref>> + %17 = fir.load %2 : !fir.ref>> + %18 = fir.box_addr %17 {test.ptr="alloc"} : (!fir.box>) -> !fir.heap + %19 = fir.load %18 : !fir.heap + fir.store %19 to %13 : !fir.ref + %20 = fir.load %5 : !fir.ref>> + %21 = fir.box_addr %20 {test.ptr="p0.ptr"} : (!fir.box>) -> !fir.ptr + %22 = fir.load %21 : !fir.ptr + fir.store %22 to %7 : !fir.ref + return +}