2018-12-04 01:45:35 +08:00
|
|
|
//===- CSE.cpp - Common Sub-expression Elimination ------------------------===//
|
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-24 01:35:36 +08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-12-04 01:45:35 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2018-12-04 01:45:35 +08:00
|
|
|
//
|
|
|
|
// This transformation pass performs a simple common sub-expression elimination
|
2020-04-08 04:58:12 +08:00
|
|
|
// algorithm on operations within a region.
|
2018-12-04 01:45:35 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-08 04:58:12 +08:00
|
|
|
#include "PassDetail.h"
|
2020-05-01 04:09:13 +08:00
|
|
|
#include "mlir/IR/Dominance.h"
|
2019-02-20 09:17:46 +08:00
|
|
|
#include "mlir/Pass/Pass.h"
|
2018-12-04 01:45:35 +08:00
|
|
|
#include "mlir/Transforms/Passes.h"
|
|
|
|
#include "mlir/Transforms/Utils.h"
|
|
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
|
|
#include "llvm/ADT/Hashing.h"
|
|
|
|
#include "llvm/ADT/ScopedHashTable.h"
|
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
#include "llvm/Support/RecyclingAllocator.h"
|
|
|
|
#include <deque>
|
2020-04-08 04:58:12 +08:00
|
|
|
|
2018-12-04 01:45:35 +08:00
|
|
|
using namespace mlir;
|
|
|
|
|
2021-05-31 03:22:08 +08:00
|
|
|
/// Return true if the specified region is known to follow SSA dominance
|
|
|
|
/// properties, i.e. it isn't a graph region.
|
|
|
|
static bool regionHasSSADominance(Operation &op, size_t regionNo,
|
|
|
|
RegionKindInterface regionKindItf) {
|
|
|
|
// If the op is unregistered, then we don't know if it has SSADominance or
|
|
|
|
// not, so assume not.
|
|
|
|
if (!op.isRegistered())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the op is registered but has no RegionKindInterface, then it defaults to
|
|
|
|
// SSADominance.
|
|
|
|
if (!regionKindItf)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Otherwise, ask the interface.
|
|
|
|
return regionKindItf.hasSSADominance(regionNo);
|
|
|
|
}
|
|
|
|
|
2018-12-04 01:45:35 +08:00
|
|
|
namespace {
|
2019-03-28 05:02:02 +08:00
|
|
|
struct SimpleOperationInfo : public llvm::DenseMapInfo<Operation *> {
|
|
|
|
static unsigned getHashValue(const Operation *opC) {
|
2020-04-30 07:09:20 +08:00
|
|
|
return OperationEquivalence::computeHash(const_cast<Operation *>(opC));
|
2018-12-04 01:45:35 +08:00
|
|
|
}
|
2019-03-28 05:02:02 +08:00
|
|
|
static bool isEqual(const Operation *lhsC, const Operation *rhsC) {
|
|
|
|
auto *lhs = const_cast<Operation *>(lhsC);
|
|
|
|
auto *rhs = const_cast<Operation *>(rhsC);
|
2018-12-04 01:45:35 +08:00
|
|
|
if (lhs == rhs)
|
|
|
|
return true;
|
|
|
|
if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
|
|
|
|
rhs == getTombstoneKey() || rhs == getEmptyKey())
|
|
|
|
return false;
|
2020-04-30 07:09:20 +08:00
|
|
|
return OperationEquivalence::isEquivalentTo(const_cast<Operation *>(lhsC),
|
|
|
|
const_cast<Operation *>(rhsC));
|
2018-12-04 01:45:35 +08:00
|
|
|
}
|
|
|
|
};
|
2018-12-31 15:23:57 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// Simple common sub-expression elimination.
|
2020-04-08 04:58:12 +08:00
|
|
|
struct CSE : public CSEBase<CSE> {
|
2018-12-31 15:23:57 +08:00
|
|
|
/// Shared implementation of operation elimination and scoped map definitions.
|
2018-12-04 01:45:35 +08:00
|
|
|
using AllocatorTy = llvm::RecyclingAllocator<
|
|
|
|
llvm::BumpPtrAllocator,
|
2019-03-28 05:02:02 +08:00
|
|
|
llvm::ScopedHashTableVal<Operation *, Operation *>>;
|
|
|
|
using ScopedMapTy = llvm::ScopedHashTable<Operation *, Operation *,
|
2018-12-04 01:45:35 +08:00
|
|
|
SimpleOperationInfo, AllocatorTy>;
|
|
|
|
|
|
|
|
/// Represents a single entry in the depth first traversal of a CFG.
|
|
|
|
struct CFGStackNode {
|
|
|
|
CFGStackNode(ScopedMapTy &knownValues, DominanceInfoNode *node)
|
|
|
|
: scope(knownValues), node(node), childIterator(node->begin()),
|
|
|
|
processed(false) {}
|
|
|
|
|
|
|
|
/// Scope for the known values.
|
|
|
|
ScopedMapTy::ScopeTy scope;
|
|
|
|
|
|
|
|
DominanceInfoNode *node;
|
DomTree: remove explicit use of DomTreeNodeBase::iterator
Summary:
Almost all uses of these iterators, including implicit ones, really
only need the const variant (as it should be). The only exception is
in NewGVN, which changes the order of dominator tree child nodes.
Change-Id: I4b5bd71e32d71b0c67b03d4927d93fe9413726d4
Reviewers: arsenm, RKSimon, mehdi_amini, courbet, rriddle, aartbik
Subscribers: wdng, Prazek, hiraditya, kuhar, rogfer01, rriddle, jpienaar, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, stephenneuendorffer, Joonsoo, grosul1, vkmr, Kayjukh, jurahul, msifontes, cfe-commits, llvm-commits
Tags: #clang, #mlir, #llvm
Differential Revision: https://reviews.llvm.org/D83087
2020-07-03 02:36:30 +08:00
|
|
|
DominanceInfoNode::const_iterator childIterator;
|
2018-12-04 01:45:35 +08:00
|
|
|
|
|
|
|
/// If this node has been fully processed yet or not.
|
|
|
|
bool processed;
|
|
|
|
};
|
|
|
|
|
2019-06-24 16:27:22 +08:00
|
|
|
/// Attempt to eliminate a redundant operation. Returns success if the
|
|
|
|
/// operation was marked for removal, failure otherwise.
|
2021-03-29 10:25:32 +08:00
|
|
|
LogicalResult simplifyOperation(ScopedMapTy &knownValues, Operation *op,
|
|
|
|
bool hasSSADominance);
|
2021-05-31 03:22:08 +08:00
|
|
|
void simplifyBlock(ScopedMapTy &knownValues, Block *bb, bool hasSSADominance);
|
|
|
|
void simplifyRegion(ScopedMapTy &knownValues, Region ®ion,
|
|
|
|
bool hasSSADominance);
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2019-10-25 06:00:36 +08:00
|
|
|
void runOnOperation() override;
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
private:
|
|
|
|
/// Operations marked as dead and to be erased.
|
2019-03-28 05:02:02 +08:00
|
|
|
std::vector<Operation *> opsToErase;
|
2021-05-31 03:22:08 +08:00
|
|
|
DominanceInfo *domInfo = nullptr;
|
2018-12-31 15:23:57 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
/// Attempt to eliminate a redundant operation.
|
2021-03-29 10:25:32 +08:00
|
|
|
LogicalResult CSE::simplifyOperation(ScopedMapTy &knownValues, Operation *op,
|
|
|
|
bool hasSSADominance) {
|
2020-03-13 05:05:27 +08:00
|
|
|
// Don't simplify terminator operations.
|
2021-02-10 03:41:10 +08:00
|
|
|
if (op->hasTrait<OpTrait::IsTerminator>())
|
2020-03-13 05:05:27 +08:00
|
|
|
return failure();
|
|
|
|
|
2020-03-13 05:06:41 +08:00
|
|
|
// If the operation is already trivially dead just add it to the erase list.
|
|
|
|
if (isOpTriviallyDead(op)) {
|
|
|
|
opsToErase.push_back(op);
|
|
|
|
++numDCE;
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-03-07 03:04:22 +08:00
|
|
|
// Don't simplify operations with nested blocks. We don't currently model
|
|
|
|
// equality comparisons correctly among other things. It is also unclear
|
|
|
|
// whether we would want to CSE such operations.
|
2019-03-15 01:38:44 +08:00
|
|
|
if (op->getNumRegions() != 0)
|
2019-06-24 16:27:22 +08:00
|
|
|
return failure();
|
2019-03-07 03:04:22 +08:00
|
|
|
|
2020-07-07 16:35:23 +08:00
|
|
|
// TODO: We currently only eliminate non side-effecting
|
2018-12-31 15:23:57 +08:00
|
|
|
// operations.
|
2020-03-13 05:06:41 +08:00
|
|
|
if (!MemoryEffectOpInterface::hasNoEffect(op))
|
2019-06-24 16:27:22 +08:00
|
|
|
return failure();
|
2018-12-31 15:23:57 +08:00
|
|
|
|
|
|
|
// Look for an existing definition for the operation.
|
|
|
|
if (auto *existing = knownValues.lookup(op)) {
|
2021-03-29 10:25:32 +08:00
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
// If we find one then replace all uses of the current operation with the
|
2021-03-29 10:25:32 +08:00
|
|
|
// existing one and mark it for deletion. We can only replace an operand in
|
|
|
|
// an operation if it has not been visited yet.
|
|
|
|
if (hasSSADominance) {
|
|
|
|
// If the region has SSA dominance, then we are guaranteed to have not
|
|
|
|
// visited any use of the current operation.
|
|
|
|
op->replaceAllUsesWith(existing);
|
|
|
|
opsToErase.push_back(op);
|
|
|
|
} else {
|
|
|
|
// When the region does not have SSA dominance, we need to check if we
|
|
|
|
// have visited a use before replacing any use.
|
|
|
|
for (auto it : llvm::zip(op->getResults(), existing->getResults())) {
|
|
|
|
std::get<0>(it).replaceUsesWithIf(
|
|
|
|
std::get<1>(it), [&](OpOperand &operand) {
|
|
|
|
return !knownValues.count(operand.getOwner());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// There may be some remaining uses of the operation.
|
|
|
|
if (op->use_empty())
|
|
|
|
opsToErase.push_back(op);
|
|
|
|
}
|
2018-12-31 15:23:57 +08:00
|
|
|
|
|
|
|
// If the existing operation has an unknown location and the current
|
|
|
|
// operation doesn't, then set the existing op's location to that of the
|
|
|
|
// current op.
|
|
|
|
if (existing->getLoc().isa<UnknownLoc>() &&
|
|
|
|
!op->getLoc().isa<UnknownLoc>()) {
|
|
|
|
existing->setLoc(op->getLoc());
|
|
|
|
}
|
2019-12-06 03:52:58 +08:00
|
|
|
|
|
|
|
++numCSE;
|
2019-06-24 16:27:22 +08:00
|
|
|
return success();
|
2018-12-31 15:23:57 +08:00
|
|
|
}
|
2019-01-26 04:48:25 +08:00
|
|
|
|
|
|
|
// Otherwise, we add this operation to the known values map.
|
|
|
|
knownValues.insert(op, op);
|
2019-06-24 16:27:22 +08:00
|
|
|
return failure();
|
2018-12-31 15:23:57 +08:00
|
|
|
}
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2021-05-31 03:22:08 +08:00
|
|
|
void CSE::simplifyBlock(ScopedMapTy &knownValues, Block *bb,
|
|
|
|
bool hasSSADominance) {
|
|
|
|
for (auto &op : *bb) {
|
2019-03-15 01:38:44 +08:00
|
|
|
// If the operation is simplified, we don't process any held regions.
|
2021-05-31 03:22:08 +08:00
|
|
|
if (succeeded(simplifyOperation(knownValues, &op, hasSSADominance)))
|
2019-06-24 16:27:22 +08:00
|
|
|
continue;
|
|
|
|
|
2021-05-31 03:22:08 +08:00
|
|
|
// Most operations don't have regions, so fast path that case.
|
|
|
|
if (op.getNumRegions() == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto regionKindItf = dyn_cast<RegionKindInterface>(op);
|
|
|
|
|
2019-06-24 16:27:22 +08:00
|
|
|
// If this operation is isolated above, we can't process nested regions with
|
|
|
|
// the given 'knownValues' map. This would cause the insertion of implicit
|
|
|
|
// captures in explicit capture only regions.
|
2021-05-31 03:22:08 +08:00
|
|
|
if (op.mightHaveTrait<OpTrait::IsIsolatedFromAbove>()) {
|
2019-06-24 16:27:22 +08:00
|
|
|
ScopedMapTy nestedKnownValues;
|
2021-05-31 03:22:08 +08:00
|
|
|
for (size_t i = 0, e = op.getNumRegions(); i != e; ++i) {
|
|
|
|
simplifyRegion(nestedKnownValues, op.getRegion(i),
|
|
|
|
regionHasSSADominance(op, i, regionKindItf));
|
|
|
|
}
|
2019-02-05 02:38:47 +08:00
|
|
|
continue;
|
2019-06-24 16:27:22 +08:00
|
|
|
}
|
2019-02-05 02:38:47 +08:00
|
|
|
|
2019-06-24 16:27:22 +08:00
|
|
|
// Otherwise, process nested regions normally.
|
2021-05-31 03:22:08 +08:00
|
|
|
for (size_t i = 0, e = op.getNumRegions(); i != e; ++i) {
|
|
|
|
simplifyRegion(knownValues, op.getRegion(i),
|
|
|
|
regionHasSSADominance(op, i, regionKindItf));
|
|
|
|
}
|
2018-12-31 15:23:57 +08:00
|
|
|
}
|
|
|
|
}
|
2019-02-27 02:07:27 +08:00
|
|
|
|
2021-05-31 03:22:08 +08:00
|
|
|
void CSE::simplifyRegion(ScopedMapTy &knownValues, Region ®ion,
|
|
|
|
bool hasSSADominance) {
|
2019-03-15 01:38:44 +08:00
|
|
|
// If the region is empty there is nothing to do.
|
|
|
|
if (region.empty())
|
2019-02-27 02:07:27 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-15 01:38:44 +08:00
|
|
|
// If the region only contains one block, then simplify it directly.
|
|
|
|
if (std::next(region.begin()) == region.end()) {
|
2019-02-27 02:07:27 +08:00
|
|
|
ScopedMapTy::ScopeTy scope(knownValues);
|
2021-05-31 03:22:08 +08:00
|
|
|
simplifyBlock(knownValues, ®ion.front(), hasSSADominance);
|
2019-02-27 02:07:27 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[MLIR] Add RegionKindInterface
Some dialects have semantics which is not well represented by common
SSA structures with dominance constraints. This patch allows
operations to declare the 'kind' of their contained regions.
Currently, two kinds are allowed: "SSACFG" and "Graph". The only
difference between them at the moment is that SSACFG regions are
required to have dominance, while Graph regions are not required to
have dominance. The intention is that this Interface would be
generated by ODS for existing operations, although this has not yet
been implemented. Presumably, if someone were interested in code
generation, we might also have a "CFG" dialect, which defines control
flow, but does not require SSA.
The new behavior is mostly identical to the previous behavior, since
registered operations without a RegionKindInterface are assumed to
contain SSACFG regions. However, the behavior has changed for
unregistered operations. Previously, these were checked for
dominance, however the new behavior allows dominance violations, in
order to allow the processing of unregistered dialects with Graph
regions. One implication of this is that regions in unregistered
operations with more than one op are no longer CSE'd (since it
requires dominance info).
I've also reorganized the LangRef documentation to remove assertions
about "sequential execution", "SSA Values", and "Dominance". Instead,
the core IR is simply "ordered" (i.e. totally ordered) and consists of
"Values". I've also clarified some things about how control flow
passes between blocks in an SSACFG region. Control Flow must enter a
region at the entry block and follow terminator operation successors
or be returned to the containing op. Graph regions do not define a
notion of control flow.
see discussion here:
https://llvm.discourse.group/t/rfc-allowing-dialects-to-relax-the-ssa-dominance-condition/833/53
Differential Revision: https://reviews.llvm.org/D80358
2020-05-16 01:33:13 +08:00
|
|
|
// If the region does not have dominanceInfo, then skip it.
|
|
|
|
// TODO: Regions without SSA dominance should define a different
|
|
|
|
// traversal order which is appropriate and can be used here.
|
2021-03-29 10:25:32 +08:00
|
|
|
if (!hasSSADominance)
|
[MLIR] Add RegionKindInterface
Some dialects have semantics which is not well represented by common
SSA structures with dominance constraints. This patch allows
operations to declare the 'kind' of their contained regions.
Currently, two kinds are allowed: "SSACFG" and "Graph". The only
difference between them at the moment is that SSACFG regions are
required to have dominance, while Graph regions are not required to
have dominance. The intention is that this Interface would be
generated by ODS for existing operations, although this has not yet
been implemented. Presumably, if someone were interested in code
generation, we might also have a "CFG" dialect, which defines control
flow, but does not require SSA.
The new behavior is mostly identical to the previous behavior, since
registered operations without a RegionKindInterface are assumed to
contain SSACFG regions. However, the behavior has changed for
unregistered operations. Previously, these were checked for
dominance, however the new behavior allows dominance violations, in
order to allow the processing of unregistered dialects with Graph
regions. One implication of this is that regions in unregistered
operations with more than one op are no longer CSE'd (since it
requires dominance info).
I've also reorganized the LangRef documentation to remove assertions
about "sequential execution", "SSA Values", and "Dominance". Instead,
the core IR is simply "ordered" (i.e. totally ordered) and consists of
"Values". I've also clarified some things about how control flow
passes between blocks in an SSACFG region. Control Flow must enter a
region at the entry block and follow terminator operation successors
or be returned to the containing op. Graph regions do not define a
notion of control flow.
see discussion here:
https://llvm.discourse.group/t/rfc-allowing-dialects-to-relax-the-ssa-dominance-condition/833/53
Differential Revision: https://reviews.llvm.org/D80358
2020-05-16 01:33:13 +08:00
|
|
|
return;
|
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
// Note, deque is being used here because there was significant performance
|
|
|
|
// gains over vector when the container becomes very large due to the
|
|
|
|
// specific access patterns. If/when these performance issues are no
|
|
|
|
// longer a problem we can change this to vector. For more information see
|
|
|
|
// the llvm mailing list discussion on this:
|
|
|
|
// http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20120116/135228.html
|
|
|
|
std::deque<std::unique_ptr<CFGStackNode>> stack;
|
|
|
|
|
2019-03-15 01:38:44 +08:00
|
|
|
// Process the nodes of the dom tree for this region.
|
2019-08-18 02:05:35 +08:00
|
|
|
stack.emplace_back(std::make_unique<CFGStackNode>(
|
2021-05-31 03:22:08 +08:00
|
|
|
knownValues, domInfo->getRootNode(®ion)));
|
2018-12-31 15:23:57 +08:00
|
|
|
|
|
|
|
while (!stack.empty()) {
|
|
|
|
auto ¤tNode = stack.back();
|
|
|
|
|
|
|
|
// Check to see if we need to process this node.
|
|
|
|
if (!currentNode->processed) {
|
|
|
|
currentNode->processed = true;
|
2021-05-31 03:22:08 +08:00
|
|
|
simplifyBlock(knownValues, currentNode->node->getBlock(),
|
2021-03-29 10:25:32 +08:00
|
|
|
hasSSADominance);
|
2018-12-31 15:23:57 +08:00
|
|
|
}
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
// Otherwise, check to see if we need to process a child node.
|
|
|
|
if (currentNode->childIterator != currentNode->node->end()) {
|
|
|
|
auto *childNode = *(currentNode->childIterator++);
|
|
|
|
stack.emplace_back(
|
2019-08-18 02:05:35 +08:00
|
|
|
std::make_unique<CFGStackNode>(knownValues, childNode));
|
2018-12-31 15:23:57 +08:00
|
|
|
} else {
|
|
|
|
// Finally, if the node and all of its children have been processed
|
|
|
|
// then we delete the node.
|
|
|
|
stack.pop_back();
|
|
|
|
}
|
|
|
|
}
|
2019-02-27 02:07:27 +08:00
|
|
|
}
|
|
|
|
|
2019-10-25 06:00:36 +08:00
|
|
|
void CSE::runOnOperation() {
|
|
|
|
/// A scoped hash table of defining operations within a region.
|
2019-06-24 16:27:22 +08:00
|
|
|
ScopedMapTy knownValues;
|
2019-10-25 06:00:36 +08:00
|
|
|
|
2021-05-31 03:22:08 +08:00
|
|
|
domInfo = &getAnalysis<DominanceInfo>();
|
|
|
|
Operation *rootOp = getOperation();
|
|
|
|
|
|
|
|
auto regionKindItf = dyn_cast<RegionKindInterface>(getOperation());
|
|
|
|
for (size_t i = 0, e = rootOp->getNumRegions(); i != e; ++i) {
|
|
|
|
simplifyRegion(knownValues, rootOp->getRegion(i),
|
|
|
|
regionHasSSADominance(*rootOp, i, regionKindItf));
|
|
|
|
}
|
Implement the initial AnalysisManagement infrastructure, with the introduction of the FunctionAnalysisManager and ModuleAnalysisManager classes. These classes provide analysis computation, caching, and invalidation for a specific IR unit. The invalidation is currently limited to either all or none, i.e. you cannot yet preserve specific analyses.
An analysis can be any class, but it must provide the following:
* A constructor for a given IR unit.
struct MyAnalysis {
// Compute this analysis with the provided module.
MyAnalysis(Module *module);
};
Analyses can be accessed from a Pass by calling either the 'getAnalysisResult<AnalysisT>' or 'getCachedAnalysisResult<AnalysisT>' methods. A FunctionPass may query for a cached analysis on the parent module with 'getCachedModuleAnalysisResult'. Similary, a ModulePass may query an analysis, it doesn't need to be cached, on a child function with 'getFunctionAnalysisResult'.
By default, when running a pass all cached analyses are set to be invalidated. If no transformation was performed, a pass can use the method 'markAllAnalysesPreserved' to preserve all analysis results. As noted above, preserving specific analyses is not yet supported.
PiperOrigin-RevId: 236505642
2019-03-03 13:46:58 +08:00
|
|
|
|
|
|
|
// If no operations were erased, then we mark all analyses as preserved.
|
2019-06-24 16:27:22 +08:00
|
|
|
if (opsToErase.empty())
|
|
|
|
return markAllAnalysesPreserved();
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-31 15:23:57 +08:00
|
|
|
/// Erase any operations that were marked as dead during simplification.
|
|
|
|
for (auto *op : opsToErase)
|
|
|
|
op->erase();
|
|
|
|
opsToErase.clear();
|
2019-03-07 03:04:22 +08:00
|
|
|
|
|
|
|
// We currently don't remove region operations, so mark dominance as
|
|
|
|
// preserved.
|
|
|
|
markAnalysesPreserved<DominanceInfo, PostDominanceInfo>();
|
2021-05-31 03:22:08 +08:00
|
|
|
domInfo = nullptr;
|
2018-12-04 01:45:35 +08:00
|
|
|
}
|
|
|
|
|
2019-10-25 06:00:36 +08:00
|
|
|
std::unique_ptr<Pass> mlir::createCSEPass() { return std::make_unique<CSE>(); }
|