17
17
#include " flang/Optimizer/Dialect/FIRDialect.h"
18
18
#include " flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
19
19
#include " flang/Optimizer/Transforms/Passes.h"
20
+ #include " mlir/IR/Dominance.h"
20
21
#include " mlir/Pass/Pass.h"
21
22
#include " llvm/ADT/DenseMap.h"
22
23
#include " llvm/ADT/StringRef.h"
24
+ #include " llvm/ADT/Twine.h"
23
25
#include " llvm/Support/CommandLine.h"
24
26
#include " llvm/Support/Debug.h"
25
27
#include " llvm/Support/raw_ostream.h"
@@ -54,24 +56,85 @@ namespace {
54
56
// / Shared state per-module
55
57
class PassState {
56
58
public:
59
+ PassState (mlir::DominanceInfo &domInfo) : domInfo(domInfo) {}
57
60
// / memoised call to fir::AliasAnalysis::getSource
58
61
inline const fir::AliasAnalysis::Source &getSource (mlir::Value value) {
59
62
if (!analysisCache.contains (value))
60
- analysisCache.insert ({value, analysis.getSource (value)});
63
+ analysisCache.insert (
64
+ {value, analysis.getSource (value, /* getInstantiationPoint=*/ true )});
61
65
return analysisCache[value];
62
66
}
63
67
64
68
// / get the per-function TBAATree for this function
65
69
inline const fir::TBAATree &getFuncTree (mlir::func::FuncOp func) {
66
70
return forrest[func];
67
71
}
72
+ inline const fir::TBAATree &getFuncTreeWithScope (mlir::func::FuncOp func,
73
+ fir::DummyScopeOp scope) {
74
+ auto &scopeMap = scopeNames.at (func);
75
+ return forrest.getFuncTreeWithScope (func, scopeMap.lookup (scope));
76
+ }
77
+
78
+ void processFunctionScopes (mlir::func::FuncOp func);
79
+ fir::DummyScopeOp getDeclarationScope (fir::DeclareOp declareOp);
68
80
69
81
private:
82
+ mlir::DominanceInfo &domInfo;
70
83
fir::AliasAnalysis analysis;
71
84
llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
72
85
fir::TBAAForrest forrest;
86
+ // Unique names for fir.dummy_scope operations within
87
+ // the given function.
88
+ llvm::DenseMap<mlir::func::FuncOp,
89
+ llvm::DenseMap<fir::DummyScopeOp, std::string>>
90
+ scopeNames;
91
+ // A map providing a vector of fir.dummy_scope operations
92
+ // for the given function. The vectors are sorted according
93
+ // to the dominance information.
94
+ llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16 >>
95
+ sortedScopeOperations;
73
96
};
74
97
98
+ // Process fir.dummy_scope operations in the given func:
99
+ // sort them according to the dominance information, and
100
+ // associate a unique (within the current function) scope name
101
+ // with each of them.
102
+ void PassState::processFunctionScopes (mlir::func::FuncOp func) {
103
+ if (scopeNames.contains (func))
104
+ return ;
105
+
106
+ auto &scopeMap = scopeNames.getOrInsertDefault (func);
107
+ auto &scopeOps = sortedScopeOperations.getOrInsertDefault (func);
108
+ func.walk ([&](fir::DummyScopeOp op) { scopeOps.push_back (op); });
109
+ llvm::stable_sort (scopeOps, [&](const fir::DummyScopeOp &op1,
110
+ const fir::DummyScopeOp &op2) {
111
+ return domInfo.properlyDominates (&*op1, &*op2);
112
+ });
113
+ unsigned scopeId = 0 ;
114
+ for (auto scope : scopeOps) {
115
+ if (scopeId != 0 ) {
116
+ std::string name = (llvm::Twine (" Scope " ) + llvm::Twine (scopeId)).str ();
117
+ LLVM_DEBUG (llvm::dbgs () << " Creating scope '" << name << " ':\n "
118
+ << scope << " \n " );
119
+ scopeMap.insert ({scope, std::move (name)});
120
+ }
121
+ ++scopeId;
122
+ }
123
+ }
124
+
125
+ // For the given fir.declare returns the dominating fir.dummy_scope
126
+ // operation.
127
+ fir::DummyScopeOp PassState::getDeclarationScope (fir::DeclareOp declareOp) {
128
+ auto func = declareOp->getParentOfType <mlir::func::FuncOp>();
129
+ assert (func && " fir.declare does not have parent func.func" );
130
+ auto &scopeOps = sortedScopeOperations.at (func);
131
+ for (auto II = scopeOps.rbegin (), IE = scopeOps.rend (); II != IE; ++II) {
132
+ if (domInfo.dominates (&**II, &*declareOp))
133
+ return *II;
134
+ }
135
+ return nullptr ;
136
+ }
137
+
75
138
class AddAliasTagsPass : public fir ::impl::AddAliasTagsBase<AddAliasTagsPass> {
76
139
public:
77
140
void runOnOperation () override ;
@@ -85,6 +148,9 @@ class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
85
148
} // namespace
86
149
87
150
static fir::DeclareOp getDeclareOp (mlir::Value arg) {
151
+ if (auto declare =
152
+ mlir::dyn_cast_or_null<fir::DeclareOp>(arg.getDefiningOp ()))
153
+ return declare;
88
154
for (mlir::Operation *use : arg.getUsers ())
89
155
if (fir::DeclareOp declare = mlir::dyn_cast<fir::DeclareOp>(use))
90
156
return declare;
@@ -94,7 +160,7 @@ static fir::DeclareOp getDeclareOp(mlir::Value arg) {
94
160
// / Get the name of a function argument using the "fir.bindc_name" attribute,
95
161
// / or ""
96
162
static std::string getFuncArgName (mlir::Value arg) {
97
- // first try getting the name from the hlfir .declare
163
+ // first try getting the name from the fir .declare
98
164
if (fir::DeclareOp declare = getDeclareOp (arg))
99
165
return declare.getUniqName ().str ();
100
166
@@ -139,6 +205,23 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
139
205
return ;
140
206
}
141
207
208
+ // Process the scopes, if not processed yet.
209
+ state.processFunctionScopes (func);
210
+
211
+ fir::DummyScopeOp scopeOp;
212
+ if (auto declVal = source.origin .instantiationPoint ) {
213
+ // If the source is a dummy argument within some fir.dummy_scope,
214
+ // then find the corresponding innermost scope to be used for finding
215
+ // the right TBAA tree.
216
+ auto declareOp =
217
+ mlir::dyn_cast_or_null<fir::DeclareOp>(declVal.getDefiningOp ());
218
+ assert (declareOp && " Instantiation point must be fir.declare" );
219
+ if (auto dummyScope = declareOp.getDummyScope ())
220
+ scopeOp = mlir::cast<fir::DummyScopeOp>(dummyScope.getDefiningOp ());
221
+ if (!scopeOp)
222
+ scopeOp = state.getDeclarationScope (declareOp);
223
+ }
224
+
142
225
mlir::LLVM::TBAATagAttr tag;
143
226
// TBAA for dummy arguments
144
227
if (enableDummyArgs &&
@@ -147,7 +230,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
147
230
<< " Found reference to dummy argument at " << *op << " \n " );
148
231
std::string name = getFuncArgName (source.origin .u .get <mlir::Value>());
149
232
if (!name.empty ())
150
- tag = state.getFuncTree (func).dummyArgDataTree .getTag (name);
233
+ tag = state.getFuncTreeWithScope (func, scopeOp)
234
+ .dummyArgDataTree .getTag (name);
151
235
else
152
236
LLVM_DEBUG (llvm::dbgs ().indent (2 )
153
237
<< " WARN: couldn't find a name for dummy argument " << *op
@@ -161,7 +245,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
161
245
const char *name = glbl.getRootReference ().data ();
162
246
LLVM_DEBUG (llvm::dbgs ().indent (2 ) << " Found reference to global " << name
163
247
<< " at " << *op << " \n " );
164
- tag = state.getFuncTree (func).globalDataTree .getTag (name);
248
+ tag = state.getFuncTreeWithScope (func, scopeOp ).globalDataTree .getTag (name);
165
249
166
250
// TBAA for SourceKind::Direct
167
251
} else if (enableDirect &&
@@ -172,7 +256,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
172
256
const char *name = glbl.getRootReference ().data ();
173
257
LLVM_DEBUG (llvm::dbgs ().indent (2 ) << " Found reference to direct " << name
174
258
<< " at " << *op << " \n " );
175
- tag = state.getFuncTree (func).directDataTree .getTag (name);
259
+ tag =
260
+ state.getFuncTreeWithScope (func, scopeOp).directDataTree .getTag (name);
176
261
} else {
177
262
// SourceKind::Direct is likely to be extended to cases which are not a
178
263
// SymbolRefAttr in the future
@@ -193,7 +278,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
193
278
if (name) {
194
279
LLVM_DEBUG (llvm::dbgs ().indent (2 ) << " Found reference to allocation "
195
280
<< name << " at " << *op << " \n " );
196
- tag = state.getFuncTree (func).allocatedDataTree .getTag (*name);
281
+ tag = state.getFuncTreeWithScope (func, scopeOp)
282
+ .allocatedDataTree .getTag (*name);
197
283
} else {
198
284
LLVM_DEBUG (llvm::dbgs ().indent (2 )
199
285
<< " WARN: couldn't find a name for allocation " << *op
@@ -219,7 +305,8 @@ void AddAliasTagsPass::runOnOperation() {
219
305
// Instead this pass stores state per mlir::ModuleOp (which is what MLIR
220
306
// thinks the pass operates on), then the real work of the pass is done in
221
307
// runOnAliasInterface
222
- PassState state;
308
+ auto &domInfo = getAnalysis<mlir::DominanceInfo>();
309
+ PassState state (domInfo);
223
310
224
311
mlir::ModuleOp mod = getOperation ();
225
312
mod.walk (
0 commit comments