31 cl::desc(
"enable preservation of all attrbitues. even those that are "
32 "unlikely to be usefull"));
37 "enable preservation of attributes throughout code transformation"));
40#define DEBUG_TYPE "assume-builder"
42STATISTIC(NumAssumeBuilt,
"Number of assume built by the assume builder");
43STATISTIC(NumBundlesInAssumes,
"Total number of Bundles in the assume built");
45 "Number of assume merged by the assume simplify pass");
47 "Number of assume removed by the assume simplify pass");
50 "Controls which assumes gets created");
56 case Attribute::NonNull:
57 case Attribute::NoUndef:
58 case Attribute::Alignment:
59 case Attribute::Dereferenceable:
60 case Attribute::DereferenceableOrNull:
75 case Attribute::NonNull:
78 case Attribute::Alignment: {
80 if (
auto *
GEP = dyn_cast<GEPOperator>(Strip))
87 case Attribute::Dereferenceable:
88 case Attribute::DereferenceableOrNull: {
103struct AssumeBuilderState {
106 using MapKey = std::pair<Value *, Attribute::AttrKind>;
114 :
M(
M), InstBeingModified(
I), AC(AC), DT(DT) {}
117 if (!InstBeingModified || !RK.
WasOn)
119 bool HasBeenPreserved =
false;
120 Use* ToUpdate =
nullptr;
122 RK.
WasOn, {RK.AttrKind}, AC,
125 if (!isValidAssumeForContext(Assume, InstBeingModified, DT))
127 if (RKOther.ArgValue >= RK.ArgValue) {
128 HasBeenPreserved = true;
131 HasBeenPreserved =
true;
141 return HasBeenPreserved;
151 if (isa<AllocaInst>(UnderlyingPtr) || isa<GlobalValue>(UnderlyingPtr))
154 if (
auto *Arg = dyn_cast<Argument>(RK.
WasOn)) {
155 if (Arg->hasAttribute(RK.
AttrKind) &&
161 if (
auto *Inst = dyn_cast<Instruction>(RK.
WasOn))
166 if (SingleUse && SingleUse->getUser() == InstBeingModified)
173 RK = canonicalizedKnowledge(RK,
M->getDataLayout());
175 if (!isKnowledgeWorthPreserving(RK))
178 if (tryToPreserveWithoutAddingAssume(RK))
182 if (
Lookup == AssumedKnowledgeMap.
end()) {
188 "inconsistent argument value");
206 void addCall(
const CallBase *Call) {
207 auto addAttrList = [&](
AttributeList AttrList,
unsigned NumArgs) {
208 for (
unsigned Idx = 0;
Idx < NumArgs;
Idx++)
210 bool IsPoisonAttr = Attr.
hasAttribute(Attribute::NonNull) ||
212 if (!IsPoisonAttr ||
Call->isPassingUndefUB(
Idx))
213 addAttribute(Attr,
Call->getArgOperand(
Idx));
216 addAttribute(Attr,
nullptr);
218 addAttrList(
Call->getAttributes(),
Call->arg_size());
220 addAttrList(Fn->getAttributes(), Fn->arg_size());
224 if (AssumedKnowledgeMap.
empty())
231 for (
auto &MapElem : AssumedKnowledgeMap) {
233 if (MapElem.first.first)
234 Args.push_back(MapElem.first.first);
244 NumBundlesInAssumes++;
253 unsigned DerefSize = MemInst->
getModule()
257 if (DerefSize != 0) {
258 addKnowledge({Attribute::Dereferenceable, DerefSize,
Pointer});
260 Pointer->getType()->getPointerAddressSpace()))
261 addKnowledge({Attribute::NonNull, 0
u,
Pointer});
264 addKnowledge({Attribute::Alignment, MA.
valueOrOne().
value(), Pointer});
268 if (
auto *Call = dyn_cast<CallBase>(
I))
269 return addCall(Call);
270 if (
auto *Load = dyn_cast<LoadInst>(
I))
271 return addAccessedPtr(
I,
Load->getPointerOperand(),
Load->getType(),
273 if (
auto *Store = dyn_cast<StoreInst>(
I))
274 return addAccessedPtr(
I,
Store->getPointerOperand(),
275 Store->getValueOperand()->getType(),
287 AssumeBuilderState Builder(
I->getModule());
288 Builder.addInstruction(
I);
289 return Builder.build();
296 bool Changed =
false;
297 AssumeBuilderState Builder(
I->getModule(),
I, AC, DT);
298 Builder.addInstruction(
I);
299 if (
auto *
Intr = Builder.build()) {
300 Intr->insertBefore(
I);
312 AssumeBuilderState Builder(CtxI->
getModule(), CtxI, AC, DT);
314 Builder.addKnowledge(RK);
315 return Builder.build();
322 AssumeBuilderState Builder(Assume->
getModule(), Assume, AC, DT);
325 if (!Builder.isKnowledgeWorthPreserving(RK))
328 if (Builder.tryToPreserveWithoutAddingAssume(RK))
335struct AssumeSimplify {
343 bool MadeChange =
false;
347 :
F(
F), AC(AC), DT(DT), C(C),
350 void buildMapping(
bool FilterBooleanArgument) {
356 if (FilterBooleanArgument) {
357 auto *Arg = dyn_cast<ConstantInt>(Assume->
getOperand(0));
358 if (!Arg || Arg->isZero())
361 BBToAssume[Assume->
getParent()].push_back(Assume);
364 for (
auto &Elem : BBToAssume) {
367 return LHS->comesBefore(RHS);
374 void RunCleanup(
bool ForceCleanup) {
376 auto *Arg = dyn_cast<ConstantInt>(Assume->
getOperand(0));
377 if (!Arg || Arg->isZero() ||
394 void dropRedundantKnowledge() {
405 for (
Value *V : BBToAssume[BB]) {
410 auto RemoveFromAssume = [&]() {
411 CleanupToDo.insert(Assume);
412 if (BOI.Begin != BOI.End) {
418 if (BOI.Tag == IgnoreTag) {
419 CleanupToDo.insert(Assume);
424 if (
auto *Arg = dyn_cast_or_null<Argument>(RK.
WasOn)) {
425 bool HasSameKindAttr = Arg->hasAttribute(RK.
AttrKind);
428 Arg->getAttribute(RK.
AttrKind).getValueAsInt() >=
434 Assume, &*
F.getEntryBlock().getFirstInsertionPt()) ||
435 Assume == &*
F.getEntryBlock().getFirstInsertionPt()) {
452 Elem.Assume->op_begin()[Elem.BOI->Begin +
ABA_Argument].set(
468 void mergeRange(
BasicBlock *BB, MergeIterator Begin, MergeIterator
End) {
469 if (Begin ==
End || std::next(Begin) ==
End)
473 AssumeBuilderState Builder(
F.getParent());
477 if (isa<LandingPadInst>(InsertPt))
480 CleanupToDo.insert(
I);
486 Builder.addKnowledge(RK);
487 if (
auto *
I = dyn_cast_or_null<Instruction>(RK.
WasOn))
488 if (
I->getParent() == InsertPt->
getParent() &&
490 InsertPt =
I->getNextNode();
497 for (
auto It = (*Begin)->getIterator(), E = InsertPt->
getIterator();
503 auto *MergedAssume = Builder.build();
507 MergedAssume->insertBefore(InsertPt);
513 void mergeAssumes() {
517 for (
auto &Elem : BBToAssume) {
519 if (AssumesInBB.
size() < 2)
526 MergeIterator LastSplit = AssumesInBB.
begin();
527 for (; It != E; ++It)
529 for (; (*LastSplit)->comesBefore(&*It); ++LastSplit)
531 if (SplitPoints.
back() != LastSplit)
535 for (
auto SplitIt = SplitPoints.
begin();
536 SplitIt != std::prev(SplitPoints.
end()); SplitIt++) {
537 mergeRange(Elem.first, *SplitIt, *(SplitIt + 1));
545 AssumeSimplify AS(
F, *AC, DT,
F.getContext());
549 AS.dropRedundantKnowledge();
552 AS.RunCleanup(
false);
559 return AS.MadeChange;
580 bool Changed =
false;
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Given that RA is a live value
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
This file implements a map that provides insertion order iteration.
Module.h This file contains the declarations for the Module class.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
This represents the llvm.assume intrinsic.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
void registerAssumption(AssumeInst *CI)
Add an @llvm.assume intrinsic to this function's cache.
MutableArrayRef< ResultElem > assumptions()
Access the list of assumption handles currently tracked for this function.
AttributeSet getFnAttrs() const
The function attributes are returned.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
bool isStringAttribute() const
Return true if the attribute is a string (target-dependent) attribute.
bool isIntAttribute() const
Return true if the attribute is an integer attribute.
uint64_t getValueAsInt() const
Return the attribute's value as an integer.
static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
static StringRef getNameFromAttrKind(Attribute::AttrKind AttrKind)
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
bool isTypeAttribute() const
Return true if the attribute is a type attribute.
static bool isIntAttrKind(AttrKind Kind)
bool hasAttribute(AttrKind Val) const
Return true if the attribute is present.
LLVM Basic Block Representation.
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
InstListType::iterator iterator
Instruction iterators...
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
iterator_range< bundle_op_iterator > bundle_op_infos()
Return the range [bundle_op_info_begin, bundle_op_info_end).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static ConstantInt * getTrue(LLVMContext &Context)
A parsed version of the target data layout string in and methods for querying it.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
static bool shouldExecute(unsigned CounterName)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
const Function * getFunction() const
Return the function this instruction belongs to.
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
iterator find(const KeyT &Key)
A Module instance is used to store all the information related to an LLVM module.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
A container for an operand bundle being viewed as a set of values rather than a set of uses.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
Implements a dense probed hash-table based set with some number of buckets stored inline.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMapEntry - This is used to represent one value that is inserted into a StringMap.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
static IntegerType * getInt64Ty(LLVMContext &C)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const Value * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
Use * getSingleUndroppableUse()
Return true if there is exactly one use of this value that cannot be dropped.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ C
The default llvm calling convention, compatible with C.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
initializer< Ty > init(const Ty &Val)
Error build(ArrayRef< Module * > Mods, SmallVector< char, 0 > &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc)
Fills in Symtab and StrtabBuilder with a valid symbol and string table for Mods.
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< bool > EnableKnowledgeRetention
bool isValidAssumeForContext(const Instruction *I, const Instruction *CxtI, const DominatorTree *DT=nullptr, bool AllowEphemerals=false)
Return true if it is valid to use the assumptions provided by an assume intrinsic,...
RetainedKnowledge simplifyRetainedKnowledge(AssumeInst *Assume, RetainedKnowledge RK, AssumptionCache *AC, DominatorTree *DT)
canonicalize the RetainedKnowledge RK.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
constexpr StringRef IgnoreBundleTag
Tag in operand bundle indicating that this bundle should be ignored.
cl::opt< bool > ShouldPreserveAllAttributes("assume-preserve-all", cl::init(false), cl::Hidden, cl::desc("enable preservation of all attrbitues. even those that are " "unlikely to be usefull"))
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isAssumeWithEmptyBundle(const AssumeInst &Assume)
Return true iff the operand bundles of the provided llvm.assume doesn't contain any valuable informat...
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
RetainedKnowledge getKnowledgeForValue(const Value *V, ArrayRef< Attribute::AttrKind > AttrKinds, AssumptionCache *AC=nullptr, function_ref< bool(RetainedKnowledge, Instruction *, const CallBase::BundleOpInfo *)> Filter=[](auto...) { return true;})
Return a valid Knowledge associated to the Value V if its Attribute kind is in AttrKinds and it match...
RetainedKnowledge getKnowledgeFromBundle(AssumeInst &Assume, const CallBase::BundleOpInfo &BOI)
This extracts the Knowledge from an element of an operand bundle.
void sort(IteratorTy Start, IteratorTy End)
bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
bool wouldInstructionBeTriviallyDead(const Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction would have no side effects if it was not used.
AssumeInst * buildAssumeFromKnowledge(ArrayRef< RetainedKnowledge > Knowledge, Instruction *CtxI, AssumptionCache *AC=nullptr, DominatorTree *DT=nullptr)
Build and return a new assume created from the provided knowledge if the knowledge in the assume is f...
Value * MapValue(const Value *V, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr)
Look up or compute a value in the value map.
bool salvageKnowledge(Instruction *I, AssumptionCache *AC=nullptr, DominatorTree *DT=nullptr)
Calls BuildAssumeFromInst and if the resulting llvm.assume is valid insert if before I.
bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
iterator_range< df_iterator< T > > depth_first(const T &G)
AssumeInst * buildAssumeFromInst(Instruction *I)
Build a call to llvm.assume to preserve informations that can be derived from the given instruction.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Used to keep track of an operand bundle.
uint32_t Begin
The index in the Use& vector where operands for this operand bundle starts.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Represent one information held inside an operand bundle of an llvm.assume.
Attribute::AttrKind AttrKind
static RetainedKnowledge none()
A MapVector that performs no allocations if smaller than a certain size.