Skip to content

Commit 9ce286b

Browse files
author
git apple-llvm automerger
committed
Merge commit '54aa9282edb5' from llvm.org/main into next
2 parents 9651a13 + 54aa928 commit 9ce286b

File tree

2 files changed

+373
-0
lines changed

2 files changed

+373
-0
lines changed

flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@
2424
#include "flang/Optimizer/Builder/Todo.h"
2525
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
2626
#include "flang/Optimizer/HLFIR/Passes.h"
27+
#include "mlir/Analysis/Liveness.h"
2728
#include "mlir/IR/Dominance.h"
2829
#include "mlir/IR/IRMapping.h"
2930
#include "mlir/Transforms/DialectConversion.h"
31+
#include "mlir/Transforms/RegionUtils.h"
3032
#include "llvm/ADT/SmallSet.h"
3133
#include "llvm/ADT/TypeSwitch.h"
3234
#include "llvm/Support/Debug.h"
35+
#include <unordered_set>
3336

3437
namespace hlfir {
3538
#define GEN_PASS_DEF_LOWERHLFIRORDEREDASSIGNMENTS
@@ -263,6 +266,19 @@ class OrderedAssignmentRewriter {
263266
return &inserted.first->second;
264267
}
265268

269+
/// Given a top-level hlfir.where, look for hlfir.exactly_once operations
270+
/// inside it and see if any of the values live into hlfir.exactly_once
271+
/// do not dominate hlfir.where. This may happen due to CSE reusing
272+
/// results of operations from the region parent to hlfir.exactly_once.
273+
/// Since we are going to clone the body of hlfir.exactly_once before
274+
/// the top-level hlfir.where, such def-use will cause problems.
275+
/// There are options how to resolve this in a different way,
276+
/// e.g. making hlfir.exactly_once IsolatedFromAbove or making
277+
/// it a region of hlfir.where and wiring the result(s) through
278+
/// the block arguments. For the time being, this canonicalization
279+
/// tries to undo the effects of CSE.
280+
void canonicalizeExactlyOnceInsideWhere(hlfir::WhereOp whereOp);
281+
266282
fir::FirOpBuilder &builder;
267283

268284
/// Map containing the mapping between the original order assignment tree
@@ -523,6 +539,10 @@ void OrderedAssignmentRewriter::generateMaskIfOp(mlir::Value cdt) {
523539
void OrderedAssignmentRewriter::pre(hlfir::WhereOp whereOp) {
524540
mlir::Location loc = whereOp.getLoc();
525541
if (!whereLoopNest) {
542+
// Make sure liveness information is valid for the inner hlfir.exactly_once
543+
// operations, and their bodies can be cloned before the top-level
544+
// hlfir.where.
545+
canonicalizeExactlyOnceInsideWhere(whereOp);
526546
// This is the top-level WHERE. Start a loop nest iterating on the shape of
527547
// the where mask.
528548
if (auto maybeSaved = getIfSaved(whereOp.getMaskRegion())) {
@@ -1350,6 +1370,105 @@ void OrderedAssignmentRewriter::saveLeftHandSide(
13501370
}
13511371
}
13521372

1373+
void OrderedAssignmentRewriter::canonicalizeExactlyOnceInsideWhere(
1374+
hlfir::WhereOp whereOp) {
1375+
auto getDefinition = [](mlir::Value v) {
1376+
mlir::Operation *op = v.getDefiningOp();
1377+
bool isValid = true;
1378+
if (!op) {
1379+
LLVM_DEBUG(
1380+
llvm::dbgs()
1381+
<< "Value live into hlfir.exactly_once has no defining operation: "
1382+
<< v << "\n");
1383+
isValid = false;
1384+
}
1385+
if (op->getNumRegions() != 0) {
1386+
LLVM_DEBUG(
1387+
llvm::dbgs()
1388+
<< "Cannot pull an operation with regions into hlfir.exactly_once"
1389+
<< *op << "\n");
1390+
isValid = false;
1391+
}
1392+
auto effects = mlir::getEffectsRecursively(op);
1393+
if (!effects || !effects->empty()) {
1394+
LLVM_DEBUG(llvm::dbgs() << "Side effects on operation with result live "
1395+
"into hlfir.exactly_once"
1396+
<< *op << "\n");
1397+
isValid = false;
1398+
}
1399+
assert(isValid && "invalid live-in");
1400+
return op;
1401+
};
1402+
mlir::Liveness liveness(whereOp.getOperation());
1403+
whereOp->walk([&](hlfir::ExactlyOnceOp op) {
1404+
std::unordered_set<mlir::Operation *> liveInSet;
1405+
LLVM_DEBUG(llvm::dbgs() << "Canonicalizing:\n" << op << "\n");
1406+
auto &liveIns = liveness.getLiveIn(&op.getBody().front());
1407+
if (liveIns.empty())
1408+
return;
1409+
// Note that the liveIns set is not ordered.
1410+
for (mlir::Value liveIn : liveIns) {
1411+
if (!dominanceInfo.properlyDominates(liveIn, whereOp)) {
1412+
LLVM_DEBUG(llvm::dbgs()
1413+
<< "Does not dominate top-level where: " << liveIn << "\n");
1414+
liveInSet.insert(getDefinition(liveIn));
1415+
}
1416+
}
1417+
1418+
// Populate the set of operations that we need to pull into
1419+
// hlfir.exactly_once, so that the only live-ins left are the ones
1420+
// that dominate whereOp.
1421+
std::unordered_set<mlir::Operation *> cloneSet(liveInSet);
1422+
llvm::SmallVector<mlir::Operation *> workList(cloneSet.begin(),
1423+
cloneSet.end());
1424+
while (!workList.empty()) {
1425+
mlir::Operation *current = workList.pop_back_val();
1426+
for (mlir::Value operand : current->getOperands()) {
1427+
if (dominanceInfo.properlyDominates(operand, whereOp))
1428+
continue;
1429+
mlir::Operation *def = getDefinition(operand);
1430+
if (cloneSet.count(def))
1431+
continue;
1432+
cloneSet.insert(def);
1433+
workList.push_back(def);
1434+
}
1435+
}
1436+
1437+
// Sort the operations by dominance. This preserves their order
1438+
// after the cloning, and also guarantees stable IR generation.
1439+
llvm::SmallVector<mlir::Operation *> cloneList(cloneSet.begin(),
1440+
cloneSet.end());
1441+
llvm::sort(cloneList, [&](mlir::Operation *L, mlir::Operation *R) {
1442+
return dominanceInfo.properlyDominates(L, R);
1443+
});
1444+
1445+
// Clone the operations.
1446+
mlir::IRMapping mapper;
1447+
mlir::Operation::CloneOptions options;
1448+
options.cloneOperands();
1449+
mlir::OpBuilder::InsertionGuard guard(builder);
1450+
builder.setInsertionPointToStart(&op.getBody().front());
1451+
1452+
for (auto *toClone : cloneList) {
1453+
LLVM_DEBUG(llvm::dbgs() << "Cloning: " << *toClone << "\n");
1454+
builder.insert(toClone->clone(mapper, options));
1455+
}
1456+
for (mlir::Operation *oldOps : liveInSet)
1457+
for (mlir::Value oldVal : oldOps->getResults()) {
1458+
mlir::Value newVal = mapper.lookup(oldVal);
1459+
if (!newVal) {
1460+
LLVM_DEBUG(llvm::dbgs() << "No clone found for: " << oldVal << "\n");
1461+
assert(false && "missing clone");
1462+
}
1463+
mlir::replaceAllUsesInRegionWith(oldVal, newVal, op.getBody());
1464+
}
1465+
1466+
LLVM_DEBUG(llvm::dbgs() << "Finished canonicalization\n");
1467+
if (!liveInSet.empty())
1468+
LLVM_DEBUG(llvm::dbgs() << op << "\n");
1469+
});
1470+
}
1471+
13531472
/// Lower an ordered assignment tree to fir.do_loop and hlfir.assign given
13541473
/// a schedule.
13551474
static void lower(hlfir::OrderedAssignmentTreeOpInterface root,

0 commit comments

Comments
 (0)