Skip to content

Commit 677e762

Browse files
author
git apple-llvm automerger
committed
Merge commit '6cd86d0fae8c' from llvm.org/main into next
2 parents 8a171f4 + 6cd86d0 commit 677e762

File tree

10 files changed

+469
-34
lines changed

10 files changed

+469
-34
lines changed

flang/include/flang/Optimizer/Analysis/AliasAnalysis.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ struct AliasAnalysis {
120120
/// Source definition of a value.
121121
SourceUnion u;
122122

123+
/// A value definition denoting the place where the corresponding
124+
/// source variable was instantiated by the front-end.
125+
/// Currently, it is the result of [hl]fir.declare of the source,
126+
/// if we can reach it.
127+
/// It helps to identify the scope where the corresponding variable
128+
/// was defined in the original Fortran source, e.g. when MLIR
129+
/// inlining happens an inlined fir.declare of the callee's
130+
/// dummy argument identifies the scope where the source
131+
/// may be treated as a dummy argument.
132+
mlir::Value instantiationPoint;
133+
123134
/// Whether the source was reached following data or box reference
124135
bool isData{false};
125136
};
@@ -168,7 +179,10 @@ struct AliasAnalysis {
168179
mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location);
169180

170181
/// Return the memory source of a value.
171-
Source getSource(mlir::Value);
182+
/// If getInstantiationPoint is true, the search for the source
183+
/// will stop at [hl]fir.declare if it represents a dummy
184+
/// argument declaration (i.e. it has the dummy_scope operand).
185+
Source getSource(mlir::Value, bool getInstantiationPoint = false);
172186
};
173187

174188
inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,

flang/include/flang/Optimizer/Analysis/TBAAForest.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ class TBAAForrest {
9292
}
9393
return getFuncTree(func.getSymNameAttr());
9494
}
95+
// Returns the TBAA tree associated with the scope enclosed
96+
// within the given function. With MLIR inlining, there may
97+
// be multiple scopes within a single function. It is the caller's
98+
// responsibility to provide unique name for the scope.
99+
// If the scope string is empty, returns the TBAA tree for the
100+
// "root" scope of the given function.
101+
inline const TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
102+
llvm::StringRef scope) {
103+
mlir::StringAttr name = func.getSymNameAttr();
104+
if (!scope.empty())
105+
name = mlir::StringAttr::get(name.getContext(),
106+
llvm::Twine(name) + " - " + scope);
107+
return getFuncTree(name);
108+
}
95109

96110
private:
97111
const TBAATree &getFuncTree(mlir::StringAttr symName) {

flang/lib/Optimizer/Analysis/AliasAnalysis.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ bool AliasAnalysis::Source::isRecordWithPointerComponent() const {
9595
}
9696

9797
AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
98+
// TODO: alias() has to be aware of the function scopes.
99+
// After MLIR inlining, the current implementation may
100+
// not recognize non-aliasing entities.
98101
auto lhsSrc = getSource(lhs);
99102
auto rhsSrc = getSource(rhs);
100103
bool approximateSource = lhsSrc.approximateSource || rhsSrc.approximateSource;
@@ -232,7 +235,8 @@ getAttrsFromVariable(fir::FortranVariableOpInterface var) {
232235
return attrs;
233236
}
234237

235-
AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
238+
AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
239+
bool getInstantiationPoint) {
236240
auto *defOp = v.getDefiningOp();
237241
SourceKind type{SourceKind::Unknown};
238242
mlir::Type ty;
@@ -244,6 +248,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
244248
bool followingData = !isBoxRef;
245249
mlir::SymbolRefAttr global;
246250
Source::Attributes attributes;
251+
mlir::Value instantiationPoint;
247252
while (defOp && !breakFromLoop) {
248253
ty = defOp->getResultTypes()[0];
249254
llvm::TypeSwitch<Operation *>(defOp)
@@ -334,6 +339,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
334339
breakFromLoop = true;
335340
return;
336341
}
342+
if (getInstantiationPoint) {
343+
// Fetch only the innermost instantiation point.
344+
if (!instantiationPoint)
345+
instantiationPoint = op->getResult(0);
346+
347+
if (op.getDummyScope()) {
348+
// Do not track past DeclareOp that has the dummy_scope
349+
// operand. This DeclareOp is known to represent
350+
// a dummy argument for some runtime instantiation
351+
// of a procedure.
352+
type = SourceKind::Argument;
353+
breakFromLoop = true;
354+
return;
355+
}
356+
}
337357
// TODO: Look for the fortran attributes present on the operation
338358
// Track further through the operand
339359
v = op.getMemref();
@@ -372,9 +392,17 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
372392
}
373393

374394
if (type == SourceKind::Global) {
375-
return {{global, followingData}, type, ty, attributes, approximateSource};
395+
return {{global, instantiationPoint, followingData},
396+
type,
397+
ty,
398+
attributes,
399+
approximateSource};
376400
}
377-
return {{v, followingData}, type, ty, attributes, approximateSource};
401+
return {{v, instantiationPoint, followingData},
402+
type,
403+
ty,
404+
attributes,
405+
approximateSource};
378406
}
379407

380408
} // namespace fir

flang/lib/Optimizer/CodeGen/TBAABuilder.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,38 @@ TBAABuilder::TBAABuilder(MLIRContext *context, bool applyTBAA,
5252
bool forceUnifiedTree)
5353
: enableTBAA(applyTBAA && !disableTBAA),
5454
trees(/*separatePerFunction=*/perFunctionTBAATrees && !forceUnifiedTree) {
55+
// TODO: the TBAA tags created here are rooted in the root scope
56+
// of the enclosing function. This does not work best with MLIR inlining.
57+
// A better approach is to root them according to the scopes they belong to
58+
// and that were used by AddAliasTagsPass to create TBAA tags before
59+
// the CodeGen. For example:
60+
// subroutine caller(a, b, ptr)
61+
// real, target :: a(:), b(:)
62+
// integer, pointer :: ptr(:)
63+
// call callee(a, b, ptr)
64+
// end
65+
// subroutine callee(a, b, ptr)
66+
// real :: a(:), b(:)
67+
// integer, pointer :: ptr(:)
68+
// do i=...
69+
// a(ptr(i)) = b(ptr(i))
70+
// end do
71+
// end
72+
//
73+
// When callee is inlined, the dummy arguments 'a' and 'b' will
74+
// be rooted in TBAA tree corresponding to the `call callee` call site,
75+
// saying that the references to 'a' and 'b' cannot alias each other.
76+
// These tags will be created by AddAliasTagsPass, but it will not be able
77+
// to create any tags for 'ptr' references.
78+
// During the CodeGen, we create 'any data access' tags for the
79+
// 'ptr' acceses. If they are rooted within the root scope of `caller`,
80+
// they end up in a different TBAA tree with the 'a' and 'b' access
81+
// tags, so 'ptr', 'a' and 'b' references MayAlias. Moreover,
82+
// the box access of 'ptr' will also be in a different TBAA tree
83+
// with 'a' and 'b' tags, meaning they can also alias.
84+
// This will prevent LLVM vectorization even with memory conflict checks.
85+
// It seems that we'd better move all TBAA tags assignment to
86+
// AddAliasTagsPass, which can at least rely on the dummy arguments scopes.
5587
if (!enableTBAA)
5688
return;
5789
}

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3910,8 +3910,15 @@ std::optional<std::int64_t> fir::getIntIfConstant(mlir::Value value) {
39103910

39113911
bool fir::isDummyArgument(mlir::Value v) {
39123912
auto blockArg{mlir::dyn_cast<mlir::BlockArgument>(v)};
3913-
if (!blockArg)
3913+
if (!blockArg) {
3914+
auto defOp = v.getDefiningOp();
3915+
if (defOp) {
3916+
if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(defOp))
3917+
if (declareOp.getDummyScope())
3918+
return true;
3919+
}
39143920
return false;
3921+
}
39153922

39163923
auto *owner{blockArg.getOwner()};
39173924
return owner->isEntryBlock() &&

flang/lib/Optimizer/Transforms/AddAliasTags.cpp

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
#include "flang/Optimizer/Dialect/FIRDialect.h"
1818
#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
1919
#include "flang/Optimizer/Transforms/Passes.h"
20+
#include "mlir/IR/Dominance.h"
2021
#include "mlir/Pass/Pass.h"
2122
#include "llvm/ADT/DenseMap.h"
2223
#include "llvm/ADT/StringRef.h"
24+
#include "llvm/ADT/Twine.h"
2325
#include "llvm/Support/CommandLine.h"
2426
#include "llvm/Support/Debug.h"
2527
#include "llvm/Support/raw_ostream.h"
@@ -54,24 +56,85 @@ namespace {
5456
/// Shared state per-module
5557
class PassState {
5658
public:
59+
PassState(mlir::DominanceInfo &domInfo) : domInfo(domInfo) {}
5760
/// memoised call to fir::AliasAnalysis::getSource
5861
inline const fir::AliasAnalysis::Source &getSource(mlir::Value value) {
5962
if (!analysisCache.contains(value))
60-
analysisCache.insert({value, analysis.getSource(value)});
63+
analysisCache.insert(
64+
{value, analysis.getSource(value, /*getInstantiationPoint=*/true)});
6165
return analysisCache[value];
6266
}
6367

6468
/// get the per-function TBAATree for this function
6569
inline const fir::TBAATree &getFuncTree(mlir::func::FuncOp func) {
6670
return forrest[func];
6771
}
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);
6880

6981
private:
82+
mlir::DominanceInfo &domInfo;
7083
fir::AliasAnalysis analysis;
7184
llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
7285
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;
7396
};
7497

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+
75138
class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
76139
public:
77140
void runOnOperation() override;
@@ -85,6 +148,9 @@ class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
85148
} // namespace
86149

87150
static fir::DeclareOp getDeclareOp(mlir::Value arg) {
151+
if (auto declare =
152+
mlir::dyn_cast_or_null<fir::DeclareOp>(arg.getDefiningOp()))
153+
return declare;
88154
for (mlir::Operation *use : arg.getUsers())
89155
if (fir::DeclareOp declare = mlir::dyn_cast<fir::DeclareOp>(use))
90156
return declare;
@@ -94,7 +160,7 @@ static fir::DeclareOp getDeclareOp(mlir::Value arg) {
94160
/// Get the name of a function argument using the "fir.bindc_name" attribute,
95161
/// or ""
96162
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
98164
if (fir::DeclareOp declare = getDeclareOp(arg))
99165
return declare.getUniqName().str();
100166

@@ -139,6 +205,23 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
139205
return;
140206
}
141207

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+
142225
mlir::LLVM::TBAATagAttr tag;
143226
// TBAA for dummy arguments
144227
if (enableDummyArgs &&
@@ -147,7 +230,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
147230
<< "Found reference to dummy argument at " << *op << "\n");
148231
std::string name = getFuncArgName(source.origin.u.get<mlir::Value>());
149232
if (!name.empty())
150-
tag = state.getFuncTree(func).dummyArgDataTree.getTag(name);
233+
tag = state.getFuncTreeWithScope(func, scopeOp)
234+
.dummyArgDataTree.getTag(name);
151235
else
152236
LLVM_DEBUG(llvm::dbgs().indent(2)
153237
<< "WARN: couldn't find a name for dummy argument " << *op
@@ -161,7 +245,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
161245
const char *name = glbl.getRootReference().data();
162246
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global " << name
163247
<< " at " << *op << "\n");
164-
tag = state.getFuncTree(func).globalDataTree.getTag(name);
248+
tag = state.getFuncTreeWithScope(func, scopeOp).globalDataTree.getTag(name);
165249

166250
// TBAA for SourceKind::Direct
167251
} else if (enableDirect &&
@@ -172,7 +256,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
172256
const char *name = glbl.getRootReference().data();
173257
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to direct " << name
174258
<< " at " << *op << "\n");
175-
tag = state.getFuncTree(func).directDataTree.getTag(name);
259+
tag =
260+
state.getFuncTreeWithScope(func, scopeOp).directDataTree.getTag(name);
176261
} else {
177262
// SourceKind::Direct is likely to be extended to cases which are not a
178263
// SymbolRefAttr in the future
@@ -193,7 +278,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
193278
if (name) {
194279
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to allocation "
195280
<< name << " at " << *op << "\n");
196-
tag = state.getFuncTree(func).allocatedDataTree.getTag(*name);
281+
tag = state.getFuncTreeWithScope(func, scopeOp)
282+
.allocatedDataTree.getTag(*name);
197283
} else {
198284
LLVM_DEBUG(llvm::dbgs().indent(2)
199285
<< "WARN: couldn't find a name for allocation " << *op
@@ -219,7 +305,8 @@ void AddAliasTagsPass::runOnOperation() {
219305
// Instead this pass stores state per mlir::ModuleOp (which is what MLIR
220306
// thinks the pass operates on), then the real work of the pass is done in
221307
// runOnAliasInterface
222-
PassState state;
308+
auto &domInfo = getAnalysis<mlir::DominanceInfo>();
309+
PassState state(domInfo);
223310

224311
mlir::ModuleOp mod = getOperation();
225312
mod.walk(

flang/lib/Optimizer/Transforms/AddDebugInfo.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,13 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
9292

9393
// FIXME: There may be cases where an argument is processed a bit before
9494
// DeclareOp is generated. In that case, DeclareOp may point to an
95-
// intermediate op and not to BlockArgument. We need to find those cases and
96-
// walk the chain to get to the actual argument.
95+
// intermediate op and not to BlockArgument.
96+
// Moreover, with MLIR inlining we cannot use the BlockArgument
97+
// position to identify the original number of the dummy argument.
98+
// If we want to keep running AddDebugInfoPass late, the dummy argument
99+
// position in the argument list has to be expressed in FIR (e.g. as a
100+
// constant attribute of [hl]fir.declare/fircg.ext_declare operation that has
101+
// a dummy_scope operand).
97102
unsigned argNo = 0;
98103
if (fir::isDummyArgument(declOp.getMemref())) {
99104
auto arg = llvm::cast<mlir::BlockArgument>(declOp.getMemref());

0 commit comments

Comments
 (0)