#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/IR/SymbolTable.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace mlir;
#include "mlir/Interfaces/SideEffectInterfaces.cpp.inc"
bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) {
return isa<Allocate, Free, Read, Write>(effect);
}
bool mlir::isOpTriviallyDead(Operation *op) {
return op->use_empty() && wouldOpBeTriviallyDead(op);
}
static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
SmallVector<Operation *, 1> effectingOps(1, rootOp);
while (!effectingOps.empty()) {
Operation *op = effectingOps.pop_back_val();
bool hasRecursiveEffects =
op->hasTrait<OpTrait::HasRecursiveMemoryEffects>();
if (hasRecursiveEffects) {
for (Region ®ion : op->getRegions()) {
for (auto &block : region) {
for (auto &nestedOp : block)
effectingOps.push_back(&nestedOp);
}
}
}
if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
SmallVector<MemoryEffects::EffectInstance, 1> effects;
effectInterface.getEffects(effects);
SmallPtrSet<Value, 4> allocResults;
for (const MemoryEffects::EffectInstance &it : effects)
if (isa<MemoryEffects::Allocate>(it.getEffect()) && it.getValue() &&
it.getValue().getDefiningOp() == op)
allocResults.insert(it.getValue());
if (!llvm::all_of(effects, [&allocResults](
const MemoryEffects::EffectInstance &it) {
if (allocResults.contains(it.getValue()))
return true;
return isa<MemoryEffects::Read>(it.getEffect());
})) {
return false;
}
continue;
}
if (hasRecursiveEffects)
continue;
return false;
}
return true;
}
template <typename EffectTy>
bool mlir::hasSingleEffect(Operation *op) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
bool hasSingleEffectOnVal = false;
for (auto &effect : effects) {
hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
if (!hasSingleEffectOnVal)
return false;
}
return hasSingleEffectOnVal;
}
template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *);
template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *);
template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *);
template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *);
template <typename EffectTy>
bool mlir::hasSingleEffect(Operation *op, Value value) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
bool hasSingleEffectOnVal = false;
for (auto &effect : effects) {
if (effect.getValue() != value)
continue;
hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
if (!hasSingleEffectOnVal)
return false;
}
return hasSingleEffectOnVal;
}
template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *,
Value value);
template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *,
Value value);
template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *,
Value value);
template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *,
Value value);
template <typename ValueTy, typename EffectTy>
bool mlir::hasSingleEffect(Operation *op, ValueTy value) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
bool hasSingleEffectOnVal = false;
for (auto &effect : effects) {
if (effect.getEffectValue<ValueTy>() != value)
continue;
hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
if (!hasSingleEffectOnVal)
return false;
}
return hasSingleEffectOnVal;
}
template bool
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Allocate>(Operation *,
OpOperand *);
template bool
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Free>(Operation *,
OpOperand *);
template bool
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Read>(Operation *,
OpOperand *);
template bool
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Write>(Operation *,
OpOperand *);
template bool
mlir::hasSingleEffect<OpResult, MemoryEffects::Allocate>(Operation *, OpResult);
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Free>(Operation *,
OpResult);
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Read>(Operation *,
OpResult);
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Write>(Operation *,
OpResult);
template bool
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
BlockArgument);
template bool
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Free>(Operation *,
BlockArgument);
template bool
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Read>(Operation *,
BlockArgument);
template bool
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Write>(Operation *,
BlockArgument);
template <typename... EffectTys>
bool mlir::hasEffect(Operation *op) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
return isa<EffectTys...>(effect.getEffect());
});
}
template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *);
template bool mlir::hasEffect<MemoryEffects::Free>(Operation *);
template bool mlir::hasEffect<MemoryEffects::Read>(Operation *);
template bool mlir::hasEffect<MemoryEffects::Write>(Operation *);
template bool
mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *);
template <typename... EffectTys>
bool mlir::hasEffect(Operation *op, Value value) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
if (effect.getValue() != value)
return false;
return isa<EffectTys...>(effect.getEffect());
});
}
template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *,
Value value);
template bool mlir::hasEffect<MemoryEffects::Free>(Operation *, Value value);
template bool mlir::hasEffect<MemoryEffects::Read>(Operation *, Value value);
template bool mlir::hasEffect<MemoryEffects::Write>(Operation *, Value value);
template bool
mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *,
Value value);
template <typename ValueTy, typename... EffectTys>
bool mlir::hasEffect(Operation *op, ValueTy value) {
auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
if (!memOp)
return false;
SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
memOp.getEffects(effects);
return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
if (effect.getEffectValue<ValueTy>() != value)
return false;
return isa<EffectTys...>(effect.getEffect());
});
}
template bool
mlir::hasEffect<OpOperand *, MemoryEffects::Allocate>(Operation *, OpOperand *);
template bool mlir::hasEffect<OpOperand *, MemoryEffects::Free>(Operation *,
OpOperand *);
template bool mlir::hasEffect<OpOperand *, MemoryEffects::Read>(Operation *,
OpOperand *);
template bool mlir::hasEffect<OpOperand *, MemoryEffects::Write>(Operation *,
OpOperand *);
template bool
mlir::hasEffect<OpOperand *, MemoryEffects::Write, MemoryEffects::Free>(
Operation *, OpOperand *);
template bool mlir::hasEffect<OpResult, MemoryEffects::Allocate>(Operation *,
OpResult);
template bool mlir::hasEffect<OpResult, MemoryEffects::Free>(Operation *,
OpResult);
template bool mlir::hasEffect<OpResult, MemoryEffects::Read>(Operation *,
OpResult);
template bool mlir::hasEffect<OpResult, MemoryEffects::Write>(Operation *,
OpResult);
template bool
mlir::hasEffect<OpResult, MemoryEffects::Write, MemoryEffects::Free>(
Operation *, OpResult);
template bool
mlir::hasEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
BlockArgument);
template bool
mlir::hasEffect<BlockArgument, MemoryEffects::Free>(Operation *, BlockArgument);
template bool
mlir::hasEffect<BlockArgument, MemoryEffects::Read>(Operation *, BlockArgument);
template bool
mlir::hasEffect<BlockArgument, MemoryEffects::Write>(Operation *,
BlockArgument);
template bool
mlir::hasEffect<BlockArgument, MemoryEffects::Write, MemoryEffects::Free>(
Operation *, BlockArgument);
bool mlir::wouldOpBeTriviallyDead(Operation *op) {
if (op->mightHaveTrait<OpTrait::IsTerminator>())
return false;
if (isa<SymbolOpInterface>(op))
return false;
return wouldOpBeTriviallyDeadImpl(op);
}
bool mlir::isMemoryEffectFree(Operation *op) {
if (auto memInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
if (!memInterface.hasNoEffect())
return false;
if (!op->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
return true;
} else if (!op->hasTrait<OpTrait::HasRecursiveMemoryEffects>()) {
return false;
}
for (Region ®ion : op->getRegions())
for (Operation &op : region.getOps())
if (!isMemoryEffectFree(&op))
return false;
return true;
}
std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>>
mlir::getEffectsRecursively(Operation *rootOp) {
SmallVector<MemoryEffects::EffectInstance> effects;
SmallVector<Operation *> effectingOps(1, rootOp);
while (!effectingOps.empty()) {
Operation *op = effectingOps.pop_back_val();
bool hasRecursiveEffects =
op->hasTrait<OpTrait::HasRecursiveMemoryEffects>();
if (hasRecursiveEffects) {
for (Region ®ion : op->getRegions()) {
for (Block &block : region) {
for (Operation &nestedOp : block) {
effectingOps.push_back(&nestedOp);
}
}
}
}
if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
effectInterface.getEffects(effects);
} else if (!hasRecursiveEffects) {
return std::nullopt;
}
}
return effects;
}
bool mlir::isSpeculatable(Operation *op) {
auto conditionallySpeculatable = dyn_cast<ConditionallySpeculatable>(op);
if (!conditionallySpeculatable)
return false;
switch (conditionallySpeculatable.getSpeculatability()) {
case Speculation::RecursivelySpeculatable:
for (Region ®ion : op->getRegions()) {
for (Operation &op : region.getOps())
if (!isSpeculatable(&op))
return false;
}
return true;
case Speculation::Speculatable:
return true;
case Speculation::NotSpeculatable:
return false;
}
llvm_unreachable("Unhandled enum in mlir::isSpeculatable!");
}
bool mlir::isPure(Operation *op) {
return isSpeculatable(op) && isMemoryEffectFree(op);
}