[flang-commits] [flang] [flang] Add support to fir::cg in alias analysis (PR #127827)
Susan Tan ス-ザン タン via flang-commits
flang-commits at lists.llvm.org
Wed Feb 19 15:07:15 PST 2025
https://github.com/SusanTan updated https://github.com/llvm/llvm-project/pull/127827
>From 1b86576d1ecfd94386e50fa441912ff006ad7a36 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Fri, 14 Feb 2025 13:10:24 -0800
Subject: [PATCH 1/4] add support to fir::cg
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 56 ++++++++++---------
1 file changed, 30 insertions(+), 26 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 873758487ddd0..f95a66ed066da 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -19,6 +19,7 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Value.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "flang/Optimizer/CodeGen/CGOps.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
@@ -578,7 +579,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
followBoxData = true;
approximateSource = true;
})
- .Case<fir::EmboxOp, fir::ReboxOp>([&](auto op) {
+ .Case<fir::EmboxOp, fir::ReboxOp, fir::cg::XEmboxOp, fir::cg::XReboxOp>([&](auto op) {
if (followBoxData) {
v = op->getOperand(0);
defOp = v.getDefiningOp();
@@ -591,6 +592,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
Operation *loadMemrefOp = op.getMemref().getDefiningOp();
bool isDeclareOp =
llvm::isa_and_present<fir::DeclareOp>(loadMemrefOp) ||
+ llvm::isa_and_present<fir::cg::XDeclareOp>(loadMemrefOp) ||
llvm::isa_and_present<hlfir::DeclareOp>(loadMemrefOp);
if (isDeclareOp &&
llvm::isa<omp::TargetOp>(loadMemrefOp->getParentOp())) {
@@ -652,7 +654,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
breakFromLoop = true;
})
- .Case<hlfir::DeclareOp, fir::DeclareOp>([&](auto op) {
+ .Case<hlfir::DeclareOp, fir::DeclareOp, fir::cg::XDeclareOp>([&](auto op) {
bool isPrivateItem = false;
if (omp::BlockArgOpenMPOpInterface argIface =
dyn_cast<omp::BlockArgOpenMPOpInterface>(op->getParentOp())) {
@@ -686,30 +688,32 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
return;
}
}
- auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
- // While going through a declare operation collect
- // the variable attributes from it. Right now, some
- // of the attributes are duplicated, e.g. a TARGET dummy
- // argument has the target attribute both on its declare
- // operation and on the entry block argument.
- // In case of host associated use, the declare operation
- // is the only carrier of the variable attributes,
- // so we have to collect them here.
- attributes |= getAttrsFromVariable(varIf);
- isCapturedInInternalProcedure |=
- varIf.isCapturedInInternalProcedure();
- if (varIf.isHostAssoc()) {
- // Do not track past such DeclareOp, because it does not
- // currently provide any useful information. The host associated
- // access will end up dereferencing the host association tuple,
- // so we may as well stop right now.
- v = defOp->getResult(0);
- // TODO: if the host associated variable is a dummy argument
- // of the host, I think, we can treat it as SourceKind::Argument
- // for the purpose of alias analysis inside the internal procedure.
- type = SourceKind::HostAssoc;
- breakFromLoop = true;
- return;
+ auto varIf = llvm::dyn_cast<fir::FortranVariableOpInterface>(defOp);
+ if(varIf){
+ // While going through a declare operation collect
+ // the variable attributes from it. Right now, some
+ // of the attributes are duplicated, e.g. a TARGET dummy
+ // argument has the target attribute both on its declare
+ // operation and on the entry block argument.
+ // In case of host associated use, the declare operation
+ // is the only carrier of the variable attributes,
+ // so we have to collect them here.
+ attributes |= getAttrsFromVariable(varIf);
+ isCapturedInInternalProcedure |=
+ varIf.isCapturedInInternalProcedure();
+ if (varIf.isHostAssoc()) {
+ // Do not track past such DeclareOp, because it does not
+ // currently provide any useful information. The host associated
+ // access will end up dereferencing the host association tuple,
+ // so we may as well stop right now.
+ v = defOp->getResult(0);
+ // TODO: if the host associated variable is a dummy argument
+ // of the host, I think, we can treat it as SourceKind::Argument
+ // for the purpose of alias analysis inside the internal procedure.
+ type = SourceKind::HostAssoc;
+ breakFromLoop = true;
+ return;
+ }
}
if (getLastInstantiationPoint) {
// Fetch only the innermost instantiation point.
>From 1621aae1a7c6015099bdfdb199578c504832d67c Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 19 Feb 2025 12:21:06 -0800
Subject: [PATCH 2/4] format
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index f95a66ed066da..c6b61e6285dda 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/Analysis/AliasAnalysis.h"
+#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@@ -19,7 +20,6 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Value.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
-#include "flang/Optimizer/CodeGen/CGOps.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
@@ -579,13 +579,14 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
followBoxData = true;
approximateSource = true;
})
- .Case<fir::EmboxOp, fir::ReboxOp, fir::cg::XEmboxOp, fir::cg::XReboxOp>([&](auto op) {
- if (followBoxData) {
- v = op->getOperand(0);
- defOp = v.getDefiningOp();
- } else
- breakFromLoop = true;
- })
+ .Case<fir::EmboxOp, fir::ReboxOp, fir::cg::XEmboxOp, fir::cg::XReboxOp>(
+ [&](auto op) {
+ if (followBoxData) {
+ v = op->getOperand(0);
+ defOp = v.getDefiningOp();
+ } else
+ breakFromLoop = true;
+ })
.Case<fir::LoadOp>([&](auto op) {
// If load is inside target and it points to mapped item,
// continue tracking.
@@ -654,7 +655,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
breakFromLoop = true;
})
- .Case<hlfir::DeclareOp, fir::DeclareOp, fir::cg::XDeclareOp>([&](auto op) {
+ .Case<hlfir::DeclareOp, fir::DeclareOp,
+ fir::cg::XDeclareOp>([&](auto op) {
bool isPrivateItem = false;
if (omp::BlockArgOpenMPOpInterface argIface =
dyn_cast<omp::BlockArgOpenMPOpInterface>(op->getParentOp())) {
@@ -689,7 +691,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
}
}
auto varIf = llvm::dyn_cast<fir::FortranVariableOpInterface>(defOp);
- if(varIf){
+ if (varIf) {
// While going through a declare operation collect
// the variable attributes from it. Right now, some
// of the attributes are duplicated, e.g. a TARGET dummy
@@ -709,7 +711,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
v = defOp->getResult(0);
// TODO: if the host associated variable is a dummy argument
// of the host, I think, we can treat it as SourceKind::Argument
- // for the purpose of alias analysis inside the internal procedure.
+ // for the purpose of alias analysis inside the internal
+ // procedure.
type = SourceKind::HostAssoc;
breakFromLoop = true;
return;
>From cb7f432f97f2b63aefd415fb9f268e595c57c213 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 19 Feb 2025 14:42:27 -0800
Subject: [PATCH 3/4] add declare in tracing original def
---
flang/lib/Optimizer/Analysis/AliasAnalysis.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index ee43b9e155f11..436f7a1154c7c 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -62,13 +62,17 @@ getOriginalDef(mlir::Value v,
mlir::Type ty = defOp->getResultTypes()[0];
llvm::TypeSwitch<Operation *>(defOp)
.Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
- .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
- v = op.getMemref();
- auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
- attributes |= getAttrsFromVariable(varIf);
- isCapturedInInternalProcedure |=
- varIf.isCapturedInInternalProcedure();
- })
+ .Case<fir::DeclareOp, hlfir::DeclareOp, fir::cg::XDeclareOp>(
+ [&](auto op) {
+ v = op.getMemref();
+ auto varIf =
+ llvm::dyn_cast<fir::FortranVariableOpInterface>(defOp);
+ if (varIf) {
+ attributes |= getAttrsFromVariable(varIf);
+ isCapturedInInternalProcedure |=
+ varIf.isCapturedInInternalProcedure();
+ }
+ })
.Case<fir::CoordinateOp>([&](auto op) {
if (fir::AliasAnalysis::isPointerReference(ty))
attributes.set(fir::AliasAnalysis::Attribute::Pointer);
>From 64bf95f0ced24c9e9fd0449505da6104e609dd9d Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 19 Feb 2025 15:07:03 -0800
Subject: [PATCH 4/4] add a test
---
.../AliasAnalysis/fircg-as-sources.fir | 108 ++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 flang/test/Analysis/AliasAnalysis/fircg-as-sources.fir
diff --git a/flang/test/Analysis/AliasAnalysis/fircg-as-sources.fir b/flang/test/Analysis/AliasAnalysis/fircg-as-sources.fir
new file mode 100644
index 0000000000000..edb3b1dadb8cd
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/fircg-as-sources.fir
@@ -0,0 +1,108 @@
+// Check aliasing with the address *in* (not *of*) a local (fir.alloca) pointer
+// variable.
+//
+// Throughout this test, the ".fir" suffix on symbols indicates a version of the
+// MLIR after convert-hlfir-to-fir. We would like alias analysis results to be
+// the same in both versions.
+
+// RUN: fir-opt %s -split-input-file -o /dev/null --mlir-disable-threading \
+// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
+// RUN: 2>&1 | FileCheck -match-full-lines %s
+
+// subroutine test(p1, arr, t_arr, alloc, t_alloc, t, v)
+// real, pointer :: p1
+// real :: arr(:)
+// real, target :: t_arr(:)
+// real, allocatable :: alloc
+// real, allocatable, target :: t_alloc
+// real, target :: t
+// real :: v
+// real, pointer :: p0
+// end subroutine test
+
+// check when fircg.ext_rebox and fircg.ext_declare are in the path of tracing the source
+// CHECK-LABEL: Testing : "_QPtest.fir"
+// CHECK-DAG: p0.tgt.fir#0 <-> arr(1).fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_arr(1).fir#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_alloc.tgt.fir#0: MayAlias
+// CHECK-DAG: alloc.fir#0 <-> alloc.tgt.fir#0: NoAlias
+
+func.func @_QPtest.fir(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "arr"}, %arg2: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "t_arr", fir.target}, %arg3: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "alloc"}, %arg4: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "t_alloc", fir.target}, %arg5: !fir.ref<f32> {fir.bindc_name = "t", fir.target}, %arg6: !fir.ref<f32> {fir.bindc_name = "v"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fircg.ext_declare %arg3 dummy_scope %0 {test.ptr = "alloc.fir", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %2 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+ %3 = fircg.ext_rebox %2 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+ %4 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
+ %5 = fircg.ext_declare %4 {test.ptr = "p0.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %6 = fir.declare %arg0 dummy_scope %0 {test.ptr = "p1.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %7 = fir.declare %arg5 dummy_scope %0 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %8 = fir.declare %arg4 dummy_scope %0 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %9 = fir.declare %arg2 dummy_scope %0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+ %10 = fircg.ext_rebox %9 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+ %11 = fir.declare %arg6 dummy_scope %0 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %12 = fir.load %5 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %13 = fir.box_addr %12 {test.ptr = "p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %14 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %15 = fir.box_addr %14 {test.ptr = "p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %c1 = arith.constant 1 : index
+ %16 = fir.array_coor %3 %c1 {test.ptr="arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+ %c1_0 = arith.constant 1 : index
+ %17 = fir.array_coor %10 %c1_0 {test.ptr="t_arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+ %18 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %19 = fir.box_addr %18 {test.ptr = "alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ %20 = fir.load %8 : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %21 = fir.box_addr %20 {test.ptr = "t_alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ return
+}
+
+// -----
+// CHECK-LABEL: Testing : "_QFPtest3"
+
+// module pointers
+// real, pointer :: p
+// end module
+//
+// program main
+// use pointers
+// real, target :: var1 = 1, var2 =2
+// p => var1
+//
+// call test3(p)
+//
+// contains
+// subroutine test3(p1)
+// real, pointer :: p1
+// p1 => var2
+// print *, p
+// end subroutine
+// end
+
+// check when there are fircg.ext_embox in the paths
+// CHECK-DAG: p#0 <-> box.addr#0: NoAlias
+// CHECK-DAG: box.addr#0 <-> func.region0#0: NoAlias
+// CHECK-DAG: var2#0 <-> p#0: NoAlias
+// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
+// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias
+// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias
+
+fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {
+ %0 = fir.zero_bits !fir.ptr<f32>
+ %1 = fircg.ext_embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
+ fir.has_value %1 : !fir.box<!fir.ptr<f32>>
+}
+
+fir.global internal @_QFEvar2 target : f32 {
+ %cst = arith.constant 2.000000e+00 : f32
+ fir.has_value %cst : f32
+}
+
+func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
+ %3 = fir.load %arg0 {test.ptr = "arg0.load"}: !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
+ %5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %6 = fircg.ext_embox %4 : (!fir.ref<f32>) -> !fir.box<!fir.ptr<f32>>
+ %13 = fir.box_addr %6 {test.ptr = "box.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ return
+}
+
More information about the flang-commits
mailing list