Skip to content

Commit 5bc5161

Browse files
authored
[flang] Add support to fir::cg in alias analysis (llvm#127827)
Currently the alias analysis doesn't trace the source whenever there are operations from fir::cg dialect. This PR added support for fir::cg::XEmboxOp, fir::cg::XReboxOp, fir::cg::XDeclareOp for a specific application i'm working on.
1 parent b10ddfa commit 5bc5161

File tree

2 files changed

+158
-39
lines changed

2 files changed

+158
-39
lines changed

flang/lib/Optimizer/Analysis/AliasAnalysis.cpp

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Optimizer/Analysis/AliasAnalysis.h"
10+
#include "flang/Optimizer/CodeGen/CGOps.h"
1011
#include "flang/Optimizer/Dialect/FIROps.h"
1112
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
1213
#include "flang/Optimizer/Dialect/FIRType.h"
@@ -61,13 +62,17 @@ getOriginalDef(mlir::Value v,
6162
mlir::Type ty = defOp->getResultTypes()[0];
6263
llvm::TypeSwitch<Operation *>(defOp)
6364
.Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
64-
.Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
65-
v = op.getMemref();
66-
auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
67-
attributes |= getAttrsFromVariable(varIf);
68-
isCapturedInInternalProcedure |=
69-
varIf.isCapturedInInternalProcedure();
70-
})
65+
.Case<fir::DeclareOp, hlfir::DeclareOp, fir::cg::XDeclareOp>(
66+
[&](auto op) {
67+
v = op.getMemref();
68+
auto varIf =
69+
llvm::dyn_cast<fir::FortranVariableOpInterface>(defOp);
70+
if (varIf) {
71+
attributes |= getAttrsFromVariable(varIf);
72+
isCapturedInInternalProcedure |=
73+
varIf.isCapturedInInternalProcedure();
74+
}
75+
})
7176
.Case<fir::CoordinateOp>([&](auto op) {
7277
if (fir::AliasAnalysis::isPointerReference(ty))
7378
attributes.set(fir::AliasAnalysis::Attribute::Pointer);
@@ -591,19 +596,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
591596
followBoxData = true;
592597
approximateSource = true;
593598
})
594-
.Case<fir::EmboxOp, fir::ReboxOp>([&](auto op) {
595-
if (followBoxData) {
596-
v = op->getOperand(0);
597-
defOp = v.getDefiningOp();
598-
} else
599-
breakFromLoop = true;
600-
})
599+
.Case<fir::EmboxOp, fir::ReboxOp, fir::cg::XEmboxOp, fir::cg::XReboxOp>(
600+
[&](auto op) {
601+
if (followBoxData) {
602+
v = op->getOperand(0);
603+
defOp = v.getDefiningOp();
604+
} else
605+
breakFromLoop = true;
606+
})
601607
.Case<fir::LoadOp>([&](auto op) {
602608
// If load is inside target and it points to mapped item,
603609
// continue tracking.
604610
Operation *loadMemrefOp = op.getMemref().getDefiningOp();
605611
bool isDeclareOp =
606612
llvm::isa_and_present<fir::DeclareOp>(loadMemrefOp) ||
613+
llvm::isa_and_present<fir::cg::XDeclareOp>(loadMemrefOp) ||
607614
llvm::isa_and_present<hlfir::DeclareOp>(loadMemrefOp);
608615
if (isDeclareOp &&
609616
llvm::isa<omp::TargetOp>(loadMemrefOp->getParentOp())) {
@@ -666,7 +673,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
666673
global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
667674
breakFromLoop = true;
668675
})
669-
.Case<hlfir::DeclareOp, fir::DeclareOp>([&](auto op) {
676+
.Case<hlfir::DeclareOp, fir::DeclareOp,
677+
fir::cg::XDeclareOp>([&](auto op) {
670678
bool isPrivateItem = false;
671679
if (omp::BlockArgOpenMPOpInterface argIface =
672680
dyn_cast<omp::BlockArgOpenMPOpInterface>(op->getParentOp())) {
@@ -700,30 +708,33 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
700708
return;
701709
}
702710
}
703-
auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
704-
// While going through a declare operation collect
705-
// the variable attributes from it. Right now, some
706-
// of the attributes are duplicated, e.g. a TARGET dummy
707-
// argument has the target attribute both on its declare
708-
// operation and on the entry block argument.
709-
// In case of host associated use, the declare operation
710-
// is the only carrier of the variable attributes,
711-
// so we have to collect them here.
712-
attributes |= getAttrsFromVariable(varIf);
713-
isCapturedInInternalProcedure |=
714-
varIf.isCapturedInInternalProcedure();
715-
if (varIf.isHostAssoc()) {
716-
// Do not track past such DeclareOp, because it does not
717-
// currently provide any useful information. The host associated
718-
// access will end up dereferencing the host association tuple,
719-
// so we may as well stop right now.
720-
v = defOp->getResult(0);
721-
// TODO: if the host associated variable is a dummy argument
722-
// of the host, I think, we can treat it as SourceKind::Argument
723-
// for the purpose of alias analysis inside the internal procedure.
724-
type = SourceKind::HostAssoc;
725-
breakFromLoop = true;
726-
return;
711+
auto varIf = llvm::dyn_cast<fir::FortranVariableOpInterface>(defOp);
712+
if (varIf) {
713+
// While going through a declare operation collect
714+
// the variable attributes from it. Right now, some
715+
// of the attributes are duplicated, e.g. a TARGET dummy
716+
// argument has the target attribute both on its declare
717+
// operation and on the entry block argument.
718+
// In case of host associated use, the declare operation
719+
// is the only carrier of the variable attributes,
720+
// so we have to collect them here.
721+
attributes |= getAttrsFromVariable(varIf);
722+
isCapturedInInternalProcedure |=
723+
varIf.isCapturedInInternalProcedure();
724+
if (varIf.isHostAssoc()) {
725+
// Do not track past such DeclareOp, because it does not
726+
// currently provide any useful information. The host associated
727+
// access will end up dereferencing the host association tuple,
728+
// so we may as well stop right now.
729+
v = defOp->getResult(0);
730+
// TODO: if the host associated variable is a dummy argument
731+
// of the host, I think, we can treat it as SourceKind::Argument
732+
// for the purpose of alias analysis inside the internal
733+
// procedure.
734+
type = SourceKind::HostAssoc;
735+
breakFromLoop = true;
736+
return;
737+
}
727738
}
728739
if (getLastInstantiationPoint) {
729740
// Fetch only the innermost instantiation point.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Check aliasing with the address *in* (not *of*) a local (fir.alloca) pointer
2+
// variable.
3+
//
4+
// Throughout this test, the ".fir" suffix on symbols indicates a version of the
5+
// MLIR after convert-hlfir-to-fir. We would like alias analysis results to be
6+
// the same in both versions.
7+
8+
// RUN: fir-opt %s -split-input-file -o /dev/null --mlir-disable-threading \
9+
// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
10+
// RUN: 2>&1 | FileCheck -match-full-lines %s
11+
12+
// subroutine test(p1, arr, t_arr, alloc, t_alloc, t, v)
13+
// real, pointer :: p1
14+
// real :: arr(:)
15+
// real, target :: t_arr(:)
16+
// real, allocatable :: alloc
17+
// real, allocatable, target :: t_alloc
18+
// real, target :: t
19+
// real :: v
20+
// real, pointer :: p0
21+
// end subroutine test
22+
23+
// check when fircg.ext_rebox and fircg.ext_declare are in the path of tracing the source
24+
// CHECK-LABEL: Testing : "_QPtest.fir"
25+
// CHECK-DAG: p0.tgt.fir#0 <-> arr(1).fir#0: NoAlias
26+
// CHECK-DAG: p0.tgt.fir#0 <-> t_arr(1).fir#0: MayAlias
27+
// CHECK-DAG: p0.tgt.fir#0 <-> alloc.tgt.fir#0: NoAlias
28+
// CHECK-DAG: p0.tgt.fir#0 <-> t_alloc.tgt.fir#0: MayAlias
29+
// CHECK-DAG: alloc.fir#0 <-> alloc.tgt.fir#0: NoAlias
30+
31+
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"}) {
32+
%0 = fir.dummy_scope : !fir.dscope
33+
%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>>>
34+
%2 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
35+
%3 = fircg.ext_rebox %2 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
36+
%4 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
37+
%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>>>
38+
%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>>>
39+
%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>
40+
%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>>>
41+
%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>>
42+
%10 = fircg.ext_rebox %9 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
43+
%11 = fir.declare %arg6 dummy_scope %0 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
44+
%12 = fir.load %5 : !fir.ref<!fir.box<!fir.ptr<f32>>>
45+
%13 = fir.box_addr %12 {test.ptr = "p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
46+
%14 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
47+
%15 = fir.box_addr %14 {test.ptr = "p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
48+
%c1 = arith.constant 1 : index
49+
%16 = fir.array_coor %3 %c1 {test.ptr="arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
50+
%c1_0 = arith.constant 1 : index
51+
%17 = fir.array_coor %10 %c1_0 {test.ptr="t_arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
52+
%18 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<f32>>>
53+
%19 = fir.box_addr %18 {test.ptr = "alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
54+
%20 = fir.load %8 : !fir.ref<!fir.box<!fir.heap<f32>>>
55+
%21 = fir.box_addr %20 {test.ptr = "t_alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
56+
return
57+
}
58+
59+
// -----
60+
// CHECK-LABEL: Testing : "_QFPtest3"
61+
62+
// module pointers
63+
// real, pointer :: p
64+
// end module
65+
//
66+
// program main
67+
// use pointers
68+
// real, target :: var1 = 1, var2 =2
69+
// p => var1
70+
//
71+
// call test3(p)
72+
//
73+
// contains
74+
// subroutine test3(p1)
75+
// real, pointer :: p1
76+
// p1 => var2
77+
// print *, p
78+
// end subroutine
79+
// end
80+
81+
// check when there are fircg.ext_embox in the paths
82+
// CHECK-DAG: p#0 <-> box.addr#0: NoAlias
83+
// CHECK-DAG: box.addr#0 <-> func.region0#0: NoAlias
84+
// CHECK-DAG: var2#0 <-> p#0: NoAlias
85+
// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
86+
// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias
87+
// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias
88+
89+
fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {
90+
%0 = fir.zero_bits !fir.ptr<f32>
91+
%1 = fircg.ext_embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
92+
fir.has_value %1 : !fir.box<!fir.ptr<f32>>
93+
}
94+
95+
fir.global internal @_QFEvar2 target : f32 {
96+
%cst = arith.constant 2.000000e+00 : f32
97+
fir.has_value %cst : f32
98+
}
99+
100+
func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
101+
%3 = fir.load %arg0 {test.ptr = "arg0.load"}: !fir.ref<!fir.box<!fir.ptr<f32>>>
102+
%4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
103+
%5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
104+
%6 = fircg.ext_embox %4 : (!fir.ref<f32>) -> !fir.box<!fir.ptr<f32>>
105+
%13 = fir.box_addr %6 {test.ptr = "box.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
106+
return
107+
}
108+

0 commit comments

Comments
 (0)