21#include "llvm/ADT/ScopeExit.h"
22#include "llvm/Support/Debug.h"
24#include "llvm/Support/DebugLog.h"
26#define DEBUG_TYPE "llvm-inliner"
35 allocaOp->getUsers().end());
36 while (!stack.empty()) {
38 if (isa<LLVM::LifetimeStartOp, LLVM::LifetimeEndOp>(op))
40 if (isa<LLVM::BitcastOp>(op))
64 Block *callerEntryBlock =
nullptr;
78 Block *calleeEntryBlock = &(*inlinedBlocks.begin());
79 if (!callerEntryBlock || callerEntryBlock == calleeEntryBlock)
83 bool shouldInsertLifetimes =
false;
84 bool hasDynamicAlloca =
false;
88 for (
auto allocaOp : calleeEntryBlock->
getOps<LLVM::AllocaOp>()) {
89 IntegerAttr arraySize;
91 hasDynamicAlloca =
true;
94 bool shouldInsertLifetime =
96 shouldInsertLifetimes |= shouldInsertLifetime;
97 allocasToMove.emplace_back(allocaOp, arraySize, shouldInsertLifetime);
100 for (
Block &block : llvm::drop_begin(inlinedBlocks)) {
101 if (hasDynamicAlloca)
104 llvm::any_of(block.getOps<LLVM::AllocaOp>(), [](
auto allocaOp) {
105 return !matchPattern(allocaOp.getArraySize(), m_Constant());
108 if (allocasToMove.empty() && !hasDynamicAlloca)
112 if (hasDynamicAlloca) {
117 stackPtr = LLVM::StackSaveOp::create(
119 LLVM::LLVMPointerType::get(call->
getContext()));
122 for (
auto &[allocaOp, arraySize, shouldInsertLifetime] : allocasToMove) {
124 LLVM::ConstantOp::create(builder, allocaOp->getLoc(),
125 allocaOp.getArraySize().
getType(), arraySize);
127 if (shouldInsertLifetime) {
130 LLVM::LifetimeStartOp::create(builder, allocaOp.getLoc(),
131 allocaOp.getResult());
133 allocaOp->moveAfter(newConstant);
134 allocaOp.getArraySizeMutable().assign(newConstant.getResult());
136 if (!shouldInsertLifetimes && !hasDynamicAlloca)
139 for (
Block &block : inlinedBlocks) {
143 if (hasDynamicAlloca)
144 LLVM::StackRestoreOp::create(builder, call->
getLoc(), stackPtr);
145 for (
auto &[allocaOp, arraySize, shouldInsertLifetime] : allocasToMove) {
146 if (shouldInsertLifetime)
147 LLVM::LifetimeEndOp::create(builder, allocaOp.getLoc(),
148 allocaOp.getResult());
168 walker.
addWalk([&](LLVM::AliasScopeDomainAttr domainAttr) {
169 mapping[domainAttr] = LLVM::AliasScopeDomainAttr::get(
170 domainAttr.getContext(), domainAttr.getDescription());
173 walker.
addWalk([&](LLVM::AliasScopeAttr scopeAttr) {
174 mapping[scopeAttr] = LLVM::AliasScopeAttr::get(
175 cast<LLVM::AliasScopeDomainAttr>(mapping.lookup(scopeAttr.getDomain())),
176 scopeAttr.getDescription());
185 walker.
walk(arrayAttr);
187 return ArrayAttr::get(arrayAttr.getContext(),
188 llvm::map_to_vector(arrayAttr, [&](
Attribute attr) {
189 return mapping.lookup(attr);
193 for (
Block &block : inlinedBlocks) {
195 if (
auto aliasInterface = dyn_cast<LLVM::AliasAnalysisOpInterface>(op)) {
196 aliasInterface.setAliasScopes(
197 convertScopeList(aliasInterface.getAliasScopesOrNull()));
198 aliasInterface.setNoAliasScopes(
199 convertScopeList(aliasInterface.getNoAliasScopesOrNull()));
202 if (
auto noAliasScope = dyn_cast<LLVM::NoAliasScopeDeclOp>(op)) {
204 walker.
walk(noAliasScope.getScopeAttr());
206 noAliasScope.setScopeAttr(cast<LLVM::AliasScopeAttr>(
207 mapping.lookup(noAliasScope.getScopeAttr())));
223 llvm::append_range(
result, lhs);
224 llvm::append_range(
result, rhs);
225 return ArrayAttr::get(lhs.getContext(),
result);
231static FailureOr<SmallVector<Value>>
237 if (
auto viewOp = val.
getDefiningOp<ViewLikeOpInterface>()) {
238 if (val == viewOp.getViewDest())
243 std::optional<SmallVector<Value>> controlFlowPredecessors =
245 if (controlFlowPredecessors)
249 if (isa<OpResult>(val)) {
282 for (
Value argument : cast<LLVM::CallOp>(call).getArgOperands()) {
284 llvm::make_isa_range<LLVM::SSACopyOp>(argument.getUsers())) {
285 ssaCopies.insert(ssaCopy);
287 if (!ssaCopy->hasDiscardableAttr(LLVM::LLVMDialect::getNoAliasAttrName()))
289 noAliasParams.insert(ssaCopy);
295 llvm::scope_exit exit([&] {
296 for (LLVM::SSACopyOp ssaCopyOp : ssaCopies) {
297 ssaCopyOp.replaceAllUsesWith(ssaCopyOp.getOperand());
303 if (noAliasParams.empty())
308 auto functionDomain = LLVM::AliasScopeDomainAttr::get(
309 call->
getContext(), cast<LLVM::CallOp>(call).getCalleeAttr().getAttr());
311 for (LLVM::SSACopyOp copyOp : noAliasParams) {
312 auto scope = LLVM::AliasScopeAttr::get(functionDomain);
313 pointerScopes[copyOp] = scope;
316 LLVM::NoAliasScopeDeclOp::create(builder, call->
getLoc(), scope);
321 for (
Block &inlinedBlock : inlinedBlocks) {
322 inlinedBlock.walk([&](LLVM::AliasAnalysisOpInterface aliasInterface) {
328 for (
Value pointer : pointerArgs) {
329 FailureOr<SmallVector<Value>> underlyingObjectSet =
331 if (failed(underlyingObjectSet))
333 llvm::copy(*underlyingObjectSet,
334 std::inserter(basedOnPointers, basedOnPointers.begin()));
337 bool aliasesOtherKnownObject =
false;
347 if (llvm::any_of(basedOnPointers, [&](
Value object) {
351 if (
auto ssaCopy =
object.getDefiningOp<LLVM::SSACopyOp>()) {
354 aliasesOtherKnownObject |= !noAliasParams.contains(ssaCopy);
358 if (isa_and_nonnull<LLVM::AllocaOp, LLVM::AddressOfOp>(
359 object.getDefiningOp())) {
360 aliasesOtherKnownObject =
true;
370 for (LLVM::SSACopyOp noAlias : noAliasParams) {
371 if (basedOnPointers.contains(noAlias))
374 noAliasScopes.push_back(pointerScopes[noAlias]);
377 if (!noAliasScopes.empty())
378 aliasInterface.setNoAliasScopes(
380 ArrayAttr::get(call->
getContext(), noAliasScopes)));
406 if (aliasesOtherKnownObject ||
407 isa<LLVM::CallOp>(aliasInterface.getOperation()))
411 for (LLVM::SSACopyOp noAlias : noAliasParams)
412 if (basedOnPointers.contains(noAlias))
413 aliasScopes.push_back(pointerScopes[noAlias]);
415 if (!aliasScopes.empty())
416 aliasInterface.setAliasScopes(
418 ArrayAttr::get(call->
getContext(), aliasScopes)));
428 auto callAliasInterface = dyn_cast<LLVM::AliasAnalysisOpInterface>(call);
429 if (!callAliasInterface)
432 ArrayAttr aliasScopes = callAliasInterface.getAliasScopesOrNull();
433 ArrayAttr noAliasScopes = callAliasInterface.getNoAliasScopesOrNull();
436 if (!aliasScopes && !noAliasScopes)
441 for (
Block &block : inlinedBlocks) {
442 block.walk([&](LLVM::AliasAnalysisOpInterface aliasInterface) {
445 aliasInterface.getAliasScopesOrNull(), aliasScopes));
449 aliasInterface.getNoAliasScopesOrNull(), noAliasScopes));
466 auto callAccessGroupInterface = dyn_cast<LLVM::AccessGroupOpInterface>(call);
467 if (!callAccessGroupInterface)
470 auto accessGroups = callAccessGroupInterface.getAccessGroupsOrNull();
476 for (
Block &block : inlinedBlocks)
477 for (
auto accessGroupOpInterface :
478 block.getOps<LLVM::AccessGroupOpInterface>())
480 accessGroupOpInterface.getAccessGroupsOrNull(), accessGroups));
489 size_t len = std::min(mibStack.size(), callsiteStack.size());
490 return mibStack.take_front(len) == callsiteStack.take_front(len);
511 StringRef callsiteName = LLVM::LLVMDialect::getCallsiteAttrName();
512 StringRef memprofName = LLVM::LLVMDialect::getMemProfAttrName();
521 for (
Block &block : inlinedBlocks) {
526 if (!origCallsite && !memprof)
535 if (inlinedStack.empty()) {
543 newStack.append(inlinedStack.begin(), inlinedStack.end());
549 bool malformed =
false;
551 auto mib = dyn_cast<LLVM::MemProfMIBAttr>(mibAttr);
557 keptMIBs.push_back(mibAttr);
559 if (malformed || keptMIBs.empty()) {
562 }
else if (keptMIBs.size() != memprof.size()) {
578 auto fusedLoc = dyn_cast_if_present<FusedLoc>(funcLoc);
582 dyn_cast_if_present<LLVM::DISubprogramAttr>(fusedLoc.getMetadata());
592 return FusedLoc::get(loc.getContext(), callSiteLoc, scope);
596 replacer.
addReplacement([&](LLVM::LoopAnnotationAttr loopAnnotation)
597 -> std::pair<Attribute, WalkResult> {
598 FusedLoc newStartLoc = updateLoc(loopAnnotation.getStartLoc());
599 FusedLoc newEndLoc = updateLoc(loopAnnotation.getEndLoc());
600 if (!newStartLoc && !newEndLoc)
602 auto newLoopAnnotation = LLVM::LoopAnnotationAttr::get(
603 loopAnnotation.getContext(), loopAnnotation.getId(),
604 loopAnnotation.getDisableNonforced(), loopAnnotation.getVectorize(),
605 loopAnnotation.getInterleave(), loopAnnotation.getUnroll(),
606 loopAnnotation.getUnrollAndJam(), loopAnnotation.getLicm(),
607 loopAnnotation.getDistribute(), loopAnnotation.getPipeline(),
608 loopAnnotation.getPeeled(), loopAnnotation.getUnswitch(),
609 loopAnnotation.getMustProgress(), loopAnnotation.getIsVectorized(),
610 loopAnnotation.getAlign(), newStartLoc, newEndLoc,
611 loopAnnotation.getParallelAccesses());
616 for (
Block &block : inlinedBlocks)
625 uint64_t requestedAlignment,
627 uint64_t allocaAlignment = alloca.getAlignment().value_or(1);
628 if (requestedAlignment <= allocaAlignment)
630 return allocaAlignment;
634 if (naturalStackAlignmentBits == 0 ||
637 8 * requestedAlignment <= naturalStackAlignmentBits ||
640 8 * allocaAlignment > naturalStackAlignmentBits) {
641 alloca.setAlignment(requestedAlignment);
642 allocaAlignment = requestedAlignment;
644 return allocaAlignment;
656 if (
auto alloca = dyn_cast<LLVM::AllocaOp>(definingOp))
659 if (
auto addressOf = dyn_cast<LLVM::AddressOfOp>(definingOp))
661 definingOp, addressOf.getGlobalNameAttr()))
662 return global.getAlignment().value_or(1);
669 if (
auto func = dyn_cast<LLVM::LLVMFuncOp>(parentOp)) {
672 auto blockArg = llvm::cast<BlockArgument>(value);
674 blockArg.getArgNumber(), LLVM::LLVMDialect::getAlignAttrName()))
675 return cast<IntegerAttr>(alignAttr).getValue().getLimitedValue();
685 uint64_t elementTypeSize,
686 uint64_t targetAlignment) {
701 Value one = LLVM::ConstantOp::create(builder, loc, builder.
getI64Type(),
703 allocaOp = LLVM::AllocaOp::create(builder, loc, argument.
getType(),
704 elementType, one, targetAlignment);
708 LLVM::ConstantOp::create(builder, loc, builder.
getI64Type(),
713 builder.
getNamedAttr(LLVM::LLVMDialect::getAlignAttrName(),
717 LLVM::MemcpyOp::create(builder, loc, allocaOp, argument, copySize,
721 nullptr,
nullptr, argAttrs,
733 uint64_t requestedAlignment) {
734 auto func = cast<LLVM::LLVMFuncOp>(callable);
735 LLVM::MemoryEffectsAttr memoryEffects =
func.getMemoryEffectsAttr();
738 bool isReadOnly = memoryEffects &&
739 memoryEffects.getArgMem() != LLVM::ModRefInfo::ModRef &&
740 memoryEffects.getArgMem() != LLVM::ModRefInfo::Mod;
745 if (requestedAlignment <= minimumAlignment)
747 uint64_t currentAlignment =
749 if (currentAlignment >= requestedAlignment)
752 uint64_t targetAlignment = std::max(requestedAlignment, minimumAlignment);
754 builder, argument.
getLoc(), argument, elementType,
755 dataLayout.
getTypeSize(elementType), targetAlignment);
759struct LLVMInlinerInterface :
public DialectInlinerInterface {
760 using DialectInlinerInterface::DialectInlinerInterface;
762 LLVMInlinerInterface(Dialect *dialect)
763 : DialectInlinerInterface(dialect),
765 disallowedFunctionAttrs({
766 StringAttr::get(dialect->
getContext(),
"noduplicate"),
767 StringAttr::get(dialect->
getContext(),
"presplitcoroutine"),
768 StringAttr::get(dialect->
getContext(),
"returns_twice"),
769 StringAttr::get(dialect->
getContext(),
"strictfp"),
773 bool wouldBeCloned)
const final {
774 auto callOp = dyn_cast<LLVM::CallOp>(call);
776 LDBG() <<
"Cannot inline: call is not an '"
777 << LLVM::CallOp::getOperationName() <<
"' op";
780 if (callOp.getNoInline()) {
781 LDBG() <<
"Cannot inline: call is marked no_inline";
784 auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(callable);
786 LDBG() <<
"Cannot inline: callable is not an '"
787 << LLVM::LLVMFuncOp::getOperationName() <<
"' op";
790 if (funcOp.isNoInline()) {
791 LDBG() <<
"Cannot inline: function is marked no_inline";
794 if (funcOp.isVarArg()) {
795 LDBG() <<
"Cannot inline: callable is variadic";
799 if (
auto attrs = funcOp.getArgAttrs()) {
800 for (DictionaryAttr attrDict : attrs->getAsRange<DictionaryAttr>()) {
801 if (attrDict.contains(LLVM::LLVMDialect::getInAllocaAttrName())) {
802 LDBG() <<
"Cannot inline " << funcOp.getSymName()
803 <<
": inalloca arguments not supported";
809 if (funcOp.getPersonality()) {
810 LDBG() <<
"Cannot inline " << funcOp.getSymName()
811 <<
": unhandled function personality";
814 if (funcOp.getPassthrough()) {
816 if (llvm::any_of(*funcOp.getPassthrough(), [&](Attribute attr) {
817 auto stringAttr = dyn_cast<StringAttr>(attr);
820 if (disallowedFunctionAttrs.contains(stringAttr)) {
821 LDBG() <<
"Cannot inline " << funcOp.getSymName()
822 <<
": found disallowed function attribute " << stringAttr;
836 for (
Block &block : funcOp.getBody()) {
837 if (!block.empty() && !block.back().hasTrait<OpTrait::IsTerminator>()) {
838 LDBG() <<
"Cannot inline " << funcOp.getSymName()
839 <<
": block ends with non-terminator op";
854 return !(isa<LLVM::VaStartOp>(op) || isa<LLVM::BlockTagOp>(op));
859 void handleTerminator(
Operation *op,
Block *newDest)
const final {
861 auto returnOp = dyn_cast<LLVM::ReturnOp>(op);
867 LLVM::BrOp::create(builder, op->getLoc(), returnOp.getOperands(), newDest);
871 bool allowSingleBlockOptimization(
873 return !(!inlinedBlocks.empty() &&
874 isa<LLVM::UnreachableOp>(inlinedBlocks.begin()->getTerminator()));
882 auto returnOp = cast<LLVM::ReturnOp>(op);
885 assert(returnOp.getNumOperands() == valuesToRepl.size());
886 for (
auto [dst, src] : llvm::zip(valuesToRepl, returnOp.getOperands()))
887 dst.replaceAllUsesWith(src);
892 DictionaryAttr argumentAttrs)
const final {
893 if (std::optional<NamedAttribute> attr =
894 argumentAttrs.getNamed(LLVM::LLVMDialect::getByValAttrName())) {
895 Type elementType = cast<TypeAttr>(attr->getValue()).getValue();
896 uint64_t requestedAlignment = 1;
897 if (std::optional<NamedAttribute> alignAttr =
898 argumentAttrs.getNamed(LLVM::LLVMDialect::getAlignAttrName())) {
899 requestedAlignment = cast<IntegerAttr>(alignAttr->getValue())
919 auto copyOp = LLVM::SSACopyOp::create(builder, call->getLoc(), argument);
920 if (argumentAttrs.contains(LLVM::LLVMDialect::getNoAliasAttrName()))
921 copyOp->setDiscardableAttr(
922 builder.getStringAttr(LLVM::LLVMDialect::getNoAliasAttrName()),
923 builder.getUnitAttr());
927 void processInlinedCallBlocks(
947 dialect->addInterfaces<LLVMInlinerInterface>();
static bool hasLifetimeMarkers(LLVM::AllocaOp allocaOp)
Check whether the given alloca is an input to a lifetime intrinsic, optionally passing through one or...
static void handleMemProfMetadata(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Updates MemProf metadata on calls inlined into call, matching LLVM's propagateMemProfMetadata.
static void appendCallOpAliasScopes(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Appends any alias scopes of the call operation to any inlined memory operation.
static void handleLoopAnnotations(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Updates locations inside loop annotations to reflect that they were inlined.
static ArrayAttr concatArrayAttr(ArrayAttr lhs, ArrayAttr rhs)
Creates a new ArrayAttr by concatenating lhs with rhs.
static void createNewAliasScopesFromNoAliasParameter(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Creates a new AliasScopeAttr for every noalias parameter and attaches it to the appropriate inlined m...
static FailureOr< SmallVector< Value > > getUnderlyingObjectSet(Value pointerValue)
Attempts to return the set of all underlying pointer values that pointerValue is based on.
static void handleAccessGroups(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Appends any access groups of the call operation to any inlined memory operation.
static Value handleByValArgument(OpBuilder &builder, Operation *callable, Value argument, Type elementType, uint64_t requestedAlignment)
Handles a function argument marked with the byval attribute by introducing a memcpy or realigning the...
static void handleAliasScopes(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Handles all interactions with alias scopes during inlining.
static uint64_t tryToEnforceAllocaAlignment(LLVM::AllocaOp alloca, uint64_t requestedAlignment, DataLayout const &dataLayout)
If requestedAlignment is higher than the alignment specified on alloca, realigns alloca if this does ...
static bool haveCommonPrefix(ArrayRef< int64_t > mibStack, ArrayRef< int64_t > callsiteStack)
Whether the two call stacks agree up to the shorter length, matching LLVM's haveCommonPrefix: a MemPr...
static uint64_t tryToEnforceAlignment(Value value, uint64_t requestedAlignment, DataLayout const &dataLayout)
Tries to find and return the alignment of the pointer value by looking for an alignment attribute on ...
static void deepCloneAliasScopes(iterator_range< Region::iterator > inlinedBlocks)
Maps all alias scopes in the inlined operations to deep clones of the scopes and domain.
static Value handleByValArgumentInit(OpBuilder &builder, Location loc, Value argument, Type elementType, uint64_t elementTypeSize, uint64_t targetAlignment)
Introduces a new alloca and copies the memory pointed to by argument to the address of the new alloca...
static void handleInlinedAllocas(Operation *call, iterator_range< Region::iterator > inlinedBlocks)
Handles alloca operations in the inlined blocks:
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
This is an attribute/type replacer that is naively cached.
void addWalk(WalkFn< Attribute > &&fn)
Register a walk function for a given attribute or type.
WalkResult walk(T element)
Walk the given attribute/type, and recursively walk any sub elements.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
auto getOps()
Return an iterator range over the operations within this block that are of 'OpT'.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
IntegerAttr getI64IntegerAttr(int64_t value)
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
NamedAttribute getNamedAttr(StringRef name, Attribute val)
The main mechanism for performing data layout queries.
static DataLayout closest(Operation *op)
Returns the layout of the closest parent operation carrying layout info.
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
uint64_t getStackAlignment() const
Returns the natural alignment of the stack in bits.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
MLIRContext * getContext() const
This is a utility class for mapping one set of IR entities to another.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
RAII guard to reset the insertion point of the builder when destroyed.
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.
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
A trait of region holding operations that define a new scope for automatic allocations,...
This class provides the API for ops that are known to be isolated from above.
Operation is the basic unit of execution within MLIR.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Attribute removeDiscardableAttr(StringAttr name)
Remove the discardable attribute with the specified name if it exists.
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
user_range getUsers()
Returns a range of all users.
Region * getParentRegion()
Returns the region to which the instruction belongs.
MLIRContext * getContext()
Return the context this operation is associated with.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Block * getParentBlock()
Return the Block in which this Value is defined.
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.
A class to signal how to proceed with the walk of the backward slice:
bool wasInterrupted() const
Returns true if the walk was interrupted.
static WalkContinuation skip()
Creates a continuation that advances the walk without adding any predecessor values to the work list.
static WalkContinuation advanceTo(mlir::ValueRange nextValues)
Creates a continuation that adds the user-specified nextValues to the work list and advances the walk...
static WalkContinuation interrupt()
Creates a continuation that interrupts the walk.
static WalkResult advance()
void recursivelyReplaceElementsIn(Operation *op, bool replaceAttrs=true, bool replaceLocs=false, bool replaceTypes=false)
Replace the elements within the given operation, and all nested operations.
void addReplacement(ReplaceFn< Attribute > fn)
AttrTypeReplacerBase.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int64_t > content)
ArrayRef< T > asArrayRef() const
void registerInlinerInterface(DialectRegistry ®istry)
Register the LLVMInlinerInterface implementation of DialectInlinerInterface with the LLVM dialect.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
std::optional< SmallVector< Value > > getControlFlowPredecessors(Value value)
Computes a vector of all control predecessors of value.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
llvm::SetVector< T, Vector, Set, N > SetVector
WalkContinuation walkSlice(mlir::ValueRange rootValues, WalkCallback walkCallback)
Walks the slice starting from the rootValues using a depth-first traversal.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
This trait indicates that a terminator operation is "return-like".