//===-- MemorySlotInterfaces.cpp - MemorySlot interfaces --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "mlir/Interfaces/MemorySlotInterfaces.h" #include "llvm/ADT/SmallVector.h" #include "mlir/Interfaces/MemorySlotOpInterfaces.cpp.inc" #include "mlir/Interfaces/MemorySlotTypeInterfaces.cpp.inc" using namespace mlir; /// Returns the slot describing `aliasPtr`: `rootSlot` if it is the root, /// the entry in `aliasMap` if it's a known alias, or `nullopt` otherwise. static std::optional getParentSlot(Value aliasPtr, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap) { if (aliasPtr == rootSlot.ptr) return rootSlot; auto it = aliasMap.find(aliasPtr); if (it == aliasMap.end()) return std::nullopt; return it->second.slot; } void mlir::populatePromotableAliasMap(PromotableAliaserInterface aliaser, const MemorySlot &rootSlot, PromotableAliasMap &aliasMap) { for (OpOperand &operand : aliaser->getOpOperands()) { std::optional parentSlot = getParentSlot(operand.get(), rootSlot, aliasMap); if (!parentSlot) continue; SmallVector newSlots; aliaser.getPromotableSlotAliases(operand, *parentSlot, newSlots); for (const MemorySlot &alias : newSlots) aliasMap.try_emplace(alias.ptr, PromotableSlotAliasInfo{alias, &operand}); } } std::optional mlir::getOpAliasSlot(Operation *op, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap) { for (Value operand : op->getOperands()) if (std::optional slot = getParentSlot(operand, rootSlot, aliasMap)) return slot; return std::nullopt; } bool mlir::referencesAtMostOneAliasOfSlot(Operation *op, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap) { Value uniqueAliasPtr; for (Value operand : op->getOperands()) { std::optional slot = getParentSlot(operand, rootSlot, aliasMap); if (!slot) continue; if (uniqueAliasPtr && uniqueAliasPtr != slot->ptr) return false; uniqueAliasPtr = slot->ptr; } return true; } namespace { /// A step in an alias chain, from leaf to root. `parentSlot` is one step /// closer to the root; `aliasSlot` is the slot exposed at this step. struct ChainStep { PromotableAliaserInterface aliaser; OpOperand *aliasedSlotPointerOperand; MemorySlot parentSlot; MemorySlot aliasSlot; }; } // namespace /// Walks from `aliasSlot` back to `rootSlot` via `aliasMap`. Returns the /// leaf-to-root chain, or `nullopt` if `aliasSlot` is not a known alias. static std::optional> buildAliasChain(const MemorySlot &aliasSlot, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap) { SmallVector chain; Value current = aliasSlot.ptr; while (current != rootSlot.ptr) { auto it = aliasMap.find(current); if (it == aliasMap.end()) return std::nullopt; OpOperand *operand = it->second.aliasedSlotPointerOperand; auto aliaser = cast(operand->getOwner()); std::optional parent = getParentSlot(operand->get(), rootSlot, aliasMap); if (!parent) return std::nullopt; chain.push_back(ChainStep{aliaser, operand, *parent, it->second.slot}); current = operand->get(); } return chain; } Value mlir::convertSlotValueToAliasValue(Value slotValue, const MemorySlot &aliasSlot, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap, OpBuilder &builder) { std::optional> chain = buildAliasChain(aliasSlot, rootSlot, aliasMap); if (!chain) return {}; Value current = slotValue; // Root-to-leaf walk: reverse the leaf-first chain. for (ChainStep &step : llvm::reverse(*chain)) { current = step.aliaser.projectSlotValueToAliasValue( *step.aliasedSlotPointerOperand, step.parentSlot, step.aliasSlot, current, builder); if (!current) return {}; } return current; } Value mlir::convertAliasValueToSlotValue(Value aliasValue, const MemorySlot &aliasSlot, Value rootReachingDef, const MemorySlot &rootSlot, const PromotableAliasMap &aliasMap, OpBuilder &builder) { std::optional> chainOpt = buildAliasChain(aliasSlot, rootSlot, aliasMap); if (!chainOpt) return {}; SmallVector &chain = *chainOpt; // Project `rootReachingDef` down to each step's parent level so the // per-step projector can use it (needed for partial sub-aliases; full // aliases ignore it). The chain is leaf-first, so `chain.back()` is the // root-most step (parent = rootSlot) and `chain.front()` is the leaf. SmallVector perStepReachingDef(chain.size()); Value current = rootReachingDef; for (int i = static_cast(chain.size()) - 1; i >= 0; --i) { perStepReachingDef[i] = current; current = chain[i].aliaser.projectSlotValueToAliasValue( *chain[i].aliasedSlotPointerOperand, chain[i].parentSlot, chain[i].aliasSlot, current, builder); if (!current) return {}; } // Walk leaf-to-root, combining `aliasValue` with the projected reaching // definition at each step. current = aliasValue; for (size_t i = 0; i < chain.size(); ++i) { current = chain[i].aliaser.projectAliasValueToSlotValue( *chain[i].aliasedSlotPointerOperand, chain[i].parentSlot, chain[i].aliasSlot, current, perStepReachingDef[i], builder); if (!current) return {}; } return current; }