21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SetVector.h"
23#include "llvm/Support/DebugLog.h"
24#include "llvm/Support/GenericIteratedDominanceFrontier.h"
27#define GEN_PASS_DEF_MEM2REG
28#include "mlir/Transforms/Passes.h.inc"
31#define DEBUG_TYPE "mem2reg"
134using BlockingUsesMap =
135 llvm::MapVector<Operation *, SmallPtrSet<OpOperand *, 4>>;
136using RegionBlockingUsesMap =
137 llvm::SmallMapVector<Region *, BlockingUsesMap, 2>;
143struct RegionPromotionInfo {
150struct MemorySlotPromotionInfo {
159 RegionBlockingUsesMap userToBlockingUses;
168 bool needsAnyReplacedValuesVisit =
false;
174class MemorySlotPromotionAnalyzer {
178 : slot(slot), dominance(dominance), dataLayout(dataLayout) {}
182 std::optional<MemorySlotPromotionInfo> computeInfo();
196 computeBlockingUses(RegionBlockingUsesMap &userToBlockingUses,
199 bool &needsAnyReplacedValuesVisit);
205 void computeMergePoints(
Region *region,
231class MemorySlotPromoter {
233 MemorySlotPromoter(
MemorySlot slot, PromotableAllocationOpInterface allocator,
235 const DataLayout &dataLayout, MemorySlotPromotionInfo info,
237 BlockIndexCache &blockIndexCache);
244 std::optional<PromotableAllocationOpInterface> promoteSlot();
271 void promoteInRegion(
Region *region,
Value reachingDef);
276 void visitReplacedValuesForRegion(
277 Region *region,
ArrayRef<std::pair<Operation *, Value>> replacedValues);
282 void removeBlockingUses(
Region *region);
286 void removeUnusedItems();
290 Value getOrCreateDefaultValue();
293 PromotableAllocationOpInterface allocator;
311 llvm::SmallSetVector<Operation *, 8> toErase;
315 MemorySlotPromotionInfo info;
323 BlockIndexCache &blockIndexCache;
328MemorySlotPromoter::MemorySlotPromoter(
329 MemorySlot slot, PromotableAllocationOpInterface allocator,
332 BlockIndexCache &blockIndexCache)
333 : slot(slot), allocator(allocator), builder(builder), dominance(dominance),
334 dataLayout(dataLayout), info(std::move(info)), statistics(statistics),
335 blockIndexCache(blockIndexCache) {
337 auto isResultOrNewBlockArgument = [&]() {
339 return arg.getOwner()->getParentOp() == allocator;
343 assert(isResultOrNewBlockArgument() &&
344 "a slot must be a result of the allocator or an argument of the child "
345 "regions of the allocator");
349Value MemorySlotPromoter::getOrCreateDefaultValue() {
353 OpBuilder::InsertionGuard guard(builder);
355 return defaultValue = allocator.getDefaultValue(slot, builder);
358LogicalResult MemorySlotPromotionAnalyzer::computeBlockingUses(
359 RegionBlockingUsesMap &userToBlockingUses,
369 auto slotPtrRegionOp =
370 dyn_cast<RegionKindInterface>(slotPtrRegion->
getParentOp());
371 if (slotPtrRegionOp &&
379 SmallPtrSet<OpOperand *, 4> &blockingUses =
380 userToBlockingUses[use.getOwner()->getParentRegion()][use.getOwner()];
381 blockingUses.insert(&use);
385 RegionSet regionsWithDirectUse;
387 RegionSet regionsWithDirectStore;
396 for (Operation *user : forwardSlice) {
398 auto *blockingUsesMapIt = userToBlockingUses.find(user->getParentRegion());
399 if (blockingUsesMapIt == userToBlockingUses.end())
401 BlockingUsesMap &blockingUsesMap = blockingUsesMapIt->second;
402 auto *it = blockingUsesMap.find(user);
403 if (it == blockingUsesMap.end())
407 if (
auto aliaser = dyn_cast<PromotableAliaserInterface>(user))
410 SmallPtrSet<OpOperand *, 4> &blockingUses = it->second;
412 SmallVector<OpOperand *> newBlockingUses;
415 if (
auto promotable = dyn_cast<PromotableOpInterface>(user)) {
416 if (!promotable.canUsesBeRemoved(blockingUses, newBlockingUses,
419 regionsWithDirectUse.insert(user->getParentRegion());
420 if (promotable.requiresReplacedValues())
421 needsAnyReplacedValuesVisit =
true;
422 }
else if (
auto promotable = dyn_cast<PromotableMemOpInterface>(user)) {
429 MemorySlot aliasSlot =
431 if (!promotable.canUsesBeRemoved(aliasSlot, blockingUses, newBlockingUses,
438 if (promotable.storesTo(aliasSlot))
439 regionsWithDirectStore.insert(user->getParentRegion());
441 regionsWithDirectUse.insert(user->getParentRegion());
449 for (OpOperand *blockingUse : newBlockingUses) {
450 assert(llvm::is_contained(user->getResults(), blockingUse->get()));
452 Operation *useOwner = blockingUse->getOwner();
453 SmallPtrSetImpl<OpOperand *> &newUserBlockingUseSet =
455 newUserBlockingUseSet.insert(blockingUse);
461 auto visitRegions = [&](SmallVector<Region *> ®ionsToPropagateFrom,
462 bool hasValueStores) {
463 while (!regionsToPropagateFrom.empty()) {
464 Region *region = regionsToPropagateFrom.pop_back_val();
467 regionsToPromote.contains(region))
470 RegionPromotionInfo ®ionInfo = regionsToPromote[region];
471 regionInfo.hasValueStores = hasValueStores;
473 auto promotableParentOp =
474 dyn_cast<PromotableRegionOpInterface>(region->
getParentOp());
475 if (!promotableParentOp)
478 if (!promotableParentOp.isRegionPromotable(slot, region, hasValueStores))
489 SmallVector<Region *> regionsToPropagateFrom(regionsWithDirectStore.begin(),
490 regionsWithDirectStore.end());
491 if (
failed(visitRegions(regionsToPropagateFrom,
true)))
495 regionsToPropagateFrom.clear();
496 regionsToPropagateFrom.append(regionsWithDirectUse.begin(),
497 regionsWithDirectUse.end());
498 if (
failed(visitRegions(regionsToPropagateFrom,
false)))
505void MemorySlotPromotionAnalyzer::computeMergePoints(
512 idfCalculator.setDefiningBlocks(definingBlocks);
515 idfCalculator.calculate(mergePointsVec);
517 mergePoints.insert_range(mergePointsVec);
520bool MemorySlotPromotionAnalyzer::areMergePointsUsable(
521 SmallPtrSetImpl<Block *> &mergePoints) {
522 for (
Block *mergePoint : mergePoints)
523 for (
Block *pred : mergePoint->getPredecessors())
524 if (!isa<BranchOpInterface>(pred->getTerminator()))
530std::optional<MemorySlotPromotionInfo>
531MemorySlotPromotionAnalyzer::computeInfo() {
532 MemorySlotPromotionInfo info;
540 if (
failed(computeBlockingUses(info.userToBlockingUses, info.regionsToPromote,
542 info.needsAnyReplacedValuesVisit)))
554 auto collectStoringBlocks = [&](Value ptr,
const MemorySlot &ptrSlot) {
555 for (OpOperand &use : ptr.
getUses()) {
556 Operation *user = use.getOwner();
557 if (
auto storeOp = dyn_cast<PromotableMemOpInterface>(user))
558 if (storeOp.storesTo(ptrSlot))
562 collectStoringBlocks(slot.
ptr, slot);
563 for (
auto &[aliasPtr, aliasInfo] : info.aliasMap)
564 collectStoringBlocks(aliasPtr, aliasInfo.slot);
565 for (
auto &[region, regionInfo] : info.regionsToPromote)
566 if (regionInfo.hasValueStores)
573 for (
auto &[region, defBlocks] : definingBlocks)
574 computeMergePoints(region, defBlocks, info.mergePoints);
579 if (!areMergePointsUsable(info.mergePoints))
585Value MemorySlotPromoter::promoteInBlock(
Block *block, Value reachingDef) {
586 SmallVector<Operation *> blockOps;
588 blockOps.push_back(&op);
589 for (Operation *op : blockOps) {
591 if (
auto memOp = dyn_cast<PromotableMemOpInterface>(op)) {
592 if (info.userToBlockingUses[memOp->getParentRegion()].contains(memOp))
593 reachingDefs.insert({memOp, reachingDef});
595 MemorySlot aliasSlot =
597 if (memOp.storesTo(aliasSlot)) {
607 reachingDef = getOrCreateDefaultValue();
608 Value reachingDefAtStore = reachingDef;
609 if (slot.
ptr != aliasSlot.
ptr) {
614 reachingDef, aliasSlot, slot, info.aliasMap, builder);
615 assert(reachingDefAtStore &&
616 "projectSlotValueToAliasValue contract violation");
619 memOp.getStored(aliasSlot, builder, reachingDefAtStore, dataLayout);
620 assert(stored &&
"a memory operation storing to a slot must provide a "
621 "new definition of the slot");
625 replacedValuesMap[memOp] = stored;
626 if (aliasSlot.
ptr != slot.
ptr) {
628 slot, info.aliasMap, builder);
629 assert(stored &&
"projectAliasValueToSlotValue contract violation");
631 reachingDef = stored;
637 if (
auto promotableRegionOp = dyn_cast<PromotableRegionOpInterface>(op)) {
638 bool needsPromotion =
false;
639 bool hasValueStores =
false;
640 for (Region ®ion : op->getRegions()) {
641 auto regionInfoIt = info.regionsToPromote.find(®ion);
642 if (regionInfoIt == info.regionsToPromote.end())
644 needsPromotion =
true;
645 if (!regionInfoIt->second.hasValueStores)
648 hasValueStores =
true;
652 if (needsPromotion) {
653 llvm::SmallMapVector<Region *, Value, 2> regionsToProcess;
659 reachingDef = getOrCreateDefaultValue();
661 promotableRegionOp.setupPromotion(slot, reachingDef, hasValueStores,
665 for (Region ®ion : op->getRegions())
666 if (info.regionsToPromote.contains(®ion))
668 regionsToProcess.contains(®ion) &&
669 "reaching definition must be provided for a required region");
672 for (
auto &[region, reachingDef] : regionsToProcess) {
674 "region must be part of the operation");
675 if (!info.regionsToPromote.contains(region))
677 promoteInRegion(region, reachingDef);
684 for (Region ®ion : op->getRegions())
688 reachingDef = promotableRegionOp.finalizePromotion(
689 slot, reachingDef, hasValueStores, reachingAtBlockEnd, builder);
694 reachingAtBlockEnd[block] = reachingDef;
698void MemorySlotPromoter::promoteInRegion(Region *region, Value reachingDef) {
700 promoteInBlock(®ion->
front(), reachingDef);
701 regionsInPostOrder.push_back(region);
706 llvm::DomTreeNodeBase<Block> *block;
710 SmallVector<DfsJob> dfsStack;
714 dfsStack.emplace_back<DfsJob>(
715 {domTree.getNode(®ion->
front()), reachingDef});
717 while (!dfsStack.empty()) {
718 DfsJob job = dfsStack.pop_back_val();
719 Block *block = job.block->getBlock();
721 if (info.mergePoints.contains(block)) {
722 BlockArgument blockArgument =
724 job.reachingDef = blockArgument;
727 job.reachingDef = promoteInBlock(block, job.reachingDef);
729 if (
auto terminator = dyn_cast<BranchOpInterface>(block->
getTerminator())) {
730 for (BlockOperand &blockOperand : terminator->getBlockOperands()) {
731 if (info.mergePoints.contains(blockOperand.get())) {
732 if (!job.reachingDef)
733 job.reachingDef = getOrCreateDefaultValue();
735 terminator.getSuccessorOperands(blockOperand.getOperandNumber())
736 .append(job.reachingDef);
741 for (
auto *child : job.block->children())
742 dfsStack.emplace_back<DfsJob>({child, job.reachingDef});
748 regionsInPostOrder.push_back(region);
755 Block *regionEntryBlock) {
756 auto [it,
inserted] = blockIndexCache.try_emplace(regionEntryBlock);
763 for (
auto [
index, block] : llvm::enumerate(topologicalOrder))
764 blockIndices[block] =
index;
774 BlockIndexCache &blockIndexCache) {
787 size_t lhsBlockIndex = topoBlockIndices.at(
lhs->getBlock());
788 size_t rhsBlockIndex = topoBlockIndices.at(
rhs->getBlock());
789 if (lhsBlockIndex == rhsBlockIndex)
790 return lhs->isBeforeInBlock(
rhs);
791 return lhsBlockIndex < rhsBlockIndex;
795void MemorySlotPromoter::removeBlockingUses(Region *region) {
796 auto *blockingUsesMapIt = info.userToBlockingUses.find(region);
797 if (blockingUsesMapIt == info.userToBlockingUses.end())
799 BlockingUsesMap &blockingUsesMap = blockingUsesMapIt->second;
800 if (blockingUsesMap.empty())
806 region = blockingUsesMap.
front().first->getParentRegion();
808 for (
auto &[op, blockingUses] : blockingUsesMap)
809 assert(op->getParentRegion() == region &&
810 "all operations must still be in the same region");
813 llvm::SmallVector<Operation *> usersToRemoveUses(
814 llvm::make_first_range(blockingUsesMap));
820 for (Operation *toPromote : llvm::reverse(usersToRemoveUses)) {
821 if (
auto toPromoteMemOp = dyn_cast<PromotableMemOpInterface>(toPromote)) {
822 Value reachingDef = reachingDefs.lookup(toPromoteMemOp);
829 reachingDef = getOrCreateDefaultValue();
832 MemorySlot aliasSlot =
834 Value reachingDefAtBlockingUse = reachingDef;
835 if (aliasSlot.
ptr != slot.
ptr) {
839 reachingDef, aliasSlot, slot, info.aliasMap, builder);
840 assert(reachingDefAtBlockingUse &&
841 "projectSlotValueToAliasValue contract violation");
843 if (toPromoteMemOp.removeBlockingUses(
844 aliasSlot, blockingUsesMap[toPromote], builder,
845 reachingDefAtBlockingUse, dataLayout) == DeletionKind::Delete)
846 toErase.insert(toPromote);
850 auto toPromoteBasic = cast<PromotableOpInterface>(toPromote);
852 if (toPromoteBasic.removeBlockingUses(blockingUsesMap[toPromote],
853 builder) == DeletionKind::Delete)
854 toErase.insert(toPromote);
858void MemorySlotPromoter::visitReplacedValuesForRegion(
859 Region *region, ArrayRef<std::pair<Operation *, Value>> replacedValues) {
860 auto *blockingUsesMapIt = info.userToBlockingUses.find(region);
861 if (blockingUsesMapIt == info.userToBlockingUses.end())
863 BlockingUsesMap &blockingUsesMap = blockingUsesMapIt->second;
864 if (blockingUsesMap.empty())
867 for (
auto &[op, _] : blockingUsesMap) {
868 auto toVisit = dyn_cast<PromotableOpInterface>(op);
869 if (!toVisit || !toVisit.requiresReplacedValues())
872 toVisit.visitReplacedValues(replacedValues, builder);
876void MemorySlotPromoter::removeUnusedItems() {
882 SmallPtrSet<BlockArgument, 8> mergePointArgsUnused;
883 SmallVector<BlockArgument> usedMergePointArgsToProcess;
890 auto isDefinitelyUsed = [&](BlockArgument arg) {
891 for (
auto &use : arg.getUses()) {
892 if (llvm::is_contained(toErase, use.getOwner()))
898 auto branchOp = dyn_cast<BranchOpInterface>(use.getOwner());
902 std::optional<BlockArgument> successorArgument =
903 branchOp.getSuccessorBlockArgument(use.getOperandNumber());
904 if (!successorArgument)
907 if (!info.mergePoints.contains(successorArgument->getOwner()))
913 bool isLastBlockArgument =
914 successorArgument->getArgNumber() ==
915 successorArgument->getOwner()->getNumArguments() - 1;
916 if (!isLastBlockArgument)
922 for (
Block *mergePoint : info.mergePoints) {
924 if (isDefinitelyUsed(arg))
925 usedMergePointArgsToProcess.push_back(arg);
927 mergePointArgsUnused.insert(arg);
932 while (!usedMergePointArgsToProcess.empty()) {
933 BlockArgument arg = usedMergePointArgsToProcess.pop_back_val();
937 "merge point argument must be the last argument of the merge point");
939 for (BlockOperand &use : mergePoint->
getUses()) {
944 auto branch = cast<BranchOpInterface>(use.getOwner());
945 SuccessorOperands succOperands =
946 branch.getSuccessorOperands(use.getOperandNumber());
956 succOperands.
append(getOrCreateDefaultValue());
958 Value populatedValue = succOperands[arg.
getArgNumber()];
959 auto populatedValueAsArg = dyn_cast<BlockArgument>(populatedValue);
960 if (populatedValueAsArg &&
961 mergePointArgsUnused.erase(populatedValueAsArg))
962 usedMergePointArgsToProcess.push_back(populatedValueAsArg);
966 allocator.handleBlockArgument(slot, arg, builder);
968 (*statistics.newBlockArgumentAmount)++;
981 auto branch = cast<BranchOpInterface>(use.getOwner());
983 branch.getSuccessorOperands(use.getOperandNumber());
996std::optional<PromotableAllocationOpInterface>
997MemorySlotPromoter::promoteSlot() {
1006 if (info.needsAnyReplacedValuesVisit) {
1008 replacedValues.reserve(replacedValuesMap.size());
1009 for (
const auto &[memOp, value] : replacedValuesMap)
1011 replacedValues.push_back({memOp, value});
1012 for (
Region *region : regionsInPostOrder)
1013 visitReplacedValuesForRegion(region, replacedValues);
1019 removeBlockingUses(region);
1022 removeUnusedItems();
1025 "after promotion, the slot pointer should not be used anymore");
1027 LDBG() <<
"Promoted memory slot: " << slot.
ptr;
1029 if (statistics.promotedAmount)
1030 (*statistics.promotedAmount)++;
1032 return allocator.handlePromotionComplete(slot, defaultValue, builder);
1039 bool promotedAny =
false;
1044 BlockIndexCache blockIndexCache;
1049 newWorkList.reserve(workList.size());
1051 bool changesInThisRound =
false;
1052 for (PromotableAllocationOpInterface allocator : workList) {
1053 bool changedAllocator =
false;
1054 for (
MemorySlot slot : allocator.getPromotableSlots()) {
1058 MemorySlotPromotionAnalyzer analyzer(slot, dominance, dataLayout);
1059 std::optional<MemorySlotPromotionInfo> info = analyzer.computeInfo();
1061 std::optional<PromotableAllocationOpInterface> newAllocator =
1062 MemorySlotPromoter(slot, allocator, builder, dominance,
1063 dataLayout, std::move(*info), statistics,
1066 changedAllocator =
true;
1070 newWorkList.push_back(*newAllocator);
1077 if (!changedAllocator)
1078 newWorkList.push_back(allocator);
1079 changesInThisRound |= changedAllocator;
1081 if (!changesInThisRound)
1087 workList.swap(newWorkList);
1088 newWorkList.clear();
1099 void runOnOperation()
override {
1104 bool changed =
false;
1106 auto &dataLayoutAnalysis = getAnalysis<DataLayoutAnalysis>();
1107 const DataLayout &dataLayout = dataLayoutAnalysis.getAtOrAbove(scopeOp);
1108 auto &dominance = getAnalysis<DominanceInfo>();
1110 for (Region ®ion : scopeOp->
getRegions()) {
1116 SmallVector<PromotableAllocationOpInterface> allocators;
1118 region.
walk([&](PromotableAllocationOpInterface allocator) {
1119 allocators.emplace_back(allocator);
1124 dominance, statistics)))
1128 markAllAnalysesPreserved();
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
static void dominanceSort(SmallVector< Operation * > &ops, Region ®ion, BlockIndexCache &blockIndexCache)
Sorts ops according to dominance.
static const DenseMap< Block *, size_t > & getOrCreateBlockIndices(BlockIndexCache &blockIndexCache, Block *regionEntryBlock)
Gets or creates a block index mapping for the region of which the entry block is regionEntryBlock.
llvm::IDFCalculatorBase< Block, false > IDFCalculator
This class represents an argument of a Block.
unsigned getArgNumber() const
Returns the number of this argument.
Block * getOwner() const
Returns the block that owns this argument.
A block operand represents an operand that holds a reference to a Block, e.g.
Block represents an ordered list of Operations.
unsigned getNumArguments()
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
void eraseArgument(unsigned index)
Erase the argument at 'index' and remove it from the argument list.
The main mechanism for performing data layout queries.
A class for computing basic dominance information.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
This class helps build Operations.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Operation is the basic unit of execution within MLIR.
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Region * getParentRegion()
Returns the region to which the instruction belongs.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Operation * getParentOp()
Return the parent operation this region is attached to.
BlockListType & getBlocks()
bool hasOneBlock()
Return true if this region has exactly one block.
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
This class models how operands are forwarded to block arguments in control flow.
void erase(unsigned subStart, unsigned subLen=1)
Erase operands forwarded to the successor.
void append(ValueRange valueRange)
Add new operands that are forwarded to the successor.
unsigned size() const
Returns the amount of operands passed to the successor.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
DomTree & getDomTree(Region *region) const
void invalidate()
Invalidate dominance info.
Include the generated interface declarations.
SetVector< Block * > getBlocksSortedByDominance(Region ®ion)
Gets a list of blocks that is sorted according to dominance.
bool referencesAtMostOneAliasOfSlot(Operation *op, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap)
Returns true if op's operands reach rootSlot through at most one distinct alias pointer (the root its...
Value convertSlotValueToAliasValue(Value slotValue, const MemorySlot &aliasSlot, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap, OpBuilder &builder)
Walks the alias chain from rootSlot down to aliasSlot.
void populatePromotableAliasMap(PromotableAliaserInterface aliaser, const MemorySlot &rootSlot, PromotableAliasMap &aliasMap)
Populates aliasMap with alias entries produced by aliaser for operands that already alias rootSlot.
llvm::SetVector< T, Vector, Set, N > SetVector
Value convertAliasValueToSlotValue(Value aliasValue, const MemorySlot &aliasSlot, Value rootReachingDef, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap, OpBuilder &builder)
Walks the alias chain from aliasSlot back up to rootSlot.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::SmallDenseMap< Value, PromotableSlotAliasInfo, 4 > PromotableAliasMap
Maps an alias slot pointer (a result of a PromotableAliaserInterface op) reachable from a root slot t...
std::optional< MemorySlot > getOpAliasSlot(Operation *op, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap)
Returns a MemorySlot for the operand of op that aliases rootSlot.ptr (either the root itself or a kno...
LogicalResult tryToPromoteMemorySlots(ArrayRef< PromotableAllocationOpInterface > allocators, OpBuilder &builder, const DataLayout &dataLayout, DominanceInfo &dominance, Mem2RegStatistics statistics={})
Attempts to promote the memory slots of the provided allocators.
void getForwardSlice(Operation *op, SetVector< Operation * > *forwardSlice, const ForwardSliceOptions &options={})
Fills forwardSlice with the computed forward slice (i.e.
Statistics collected while applying mem2reg.
llvm::Statistic * newBlockArgumentAmount
Total amount of new block arguments inserted in blocks.
Represents a slot in memory.
Value ptr
Pointer to the memory slot, used by operations to refer to it.
Type elemType
Type of the value contained in the slot.