Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/AssumeBundleQueries.cpp
35234 views
//===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Analysis/AssumeBundleQueries.h"9#include "llvm/ADT/Statistic.h"10#include "llvm/Analysis/AssumptionCache.h"11#include "llvm/Analysis/ValueTracking.h"12#include "llvm/IR/Instruction.h"13#include "llvm/IR/Instructions.h"14#include "llvm/IR/IntrinsicInst.h"15#include "llvm/IR/PatternMatch.h"16#include "llvm/Support/DebugCounter.h"1718#define DEBUG_TYPE "assume-queries"1920using namespace llvm;21using namespace llvm::PatternMatch;2223STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles");24STATISTIC(25NumUsefullAssumeQueries,26"Number of Queries into an assume assume bundles that were satisfied");2728DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter",29"Controls which assumes gets created");3031static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {32return BOI.End - BOI.Begin > Idx;33}3435static Value *getValueFromBundleOpInfo(AssumeInst &Assume,36const CallBase::BundleOpInfo &BOI,37unsigned Idx) {38assert(bundleHasArgument(BOI, Idx) && "index out of range");39return (Assume.op_begin() + BOI.Begin + Idx)->get();40}4142bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,43StringRef AttrName, uint64_t *ArgVal) {44assert(Attribute::isExistingAttribute(AttrName) &&45"this attribute doesn't exist");46assert((ArgVal == nullptr || Attribute::isIntAttrKind(47Attribute::getAttrKindFromName(AttrName))) &&48"requested value for an attribute that has no argument");49if (Assume.bundle_op_infos().empty())50return false;5152for (auto &BOI : Assume.bundle_op_infos()) {53if (BOI.Tag->getKey() != AttrName)54continue;55if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn ||56IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn)))57continue;58if (ArgVal) {59assert(BOI.End - BOI.Begin > ABA_Argument);60*ArgVal =61cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))62->getZExtValue();63}64return true;65}66return false;67}6869void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {70for (auto &Bundles : Assume.bundle_op_infos()) {71std::pair<Value *, Attribute::AttrKind> Key{72nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};73if (bundleHasArgument(Bundles, ABA_WasOn))74Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);7576if (Key.first == nullptr && Key.second == Attribute::None)77continue;78if (!bundleHasArgument(Bundles, ABA_Argument)) {79Result[Key][&Assume] = {0, 0};80continue;81}82auto *CI = dyn_cast<ConstantInt>(83getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));84if (!CI)85continue;86uint64_t Val = CI->getZExtValue();87auto Lookup = Result.find(Key);88if (Lookup == Result.end() || !Lookup->second.count(&Assume)) {89Result[Key][&Assume] = {Val, Val};90continue;91}92Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min);93Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max);94}95}9697RetainedKnowledge98llvm::getKnowledgeFromBundle(AssumeInst &Assume,99const CallBase::BundleOpInfo &BOI) {100RetainedKnowledge Result;101if (!DebugCounter::shouldExecute(AssumeQueryCounter))102return Result;103104Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());105if (bundleHasArgument(BOI, ABA_WasOn))106Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);107auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {108if (auto *ConstInt = dyn_cast<ConstantInt>(109getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))110return ConstInt->getZExtValue();111return 1;112};113if (BOI.End - BOI.Begin > ABA_Argument)114Result.ArgValue = GetArgOr1(0);115if (Result.AttrKind == Attribute::Alignment)116if (BOI.End - BOI.Begin > ABA_Argument + 1)117Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));118return Result;119}120121RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,122unsigned Idx) {123CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);124return getKnowledgeFromBundle(Assume, BOI);125}126127bool llvm::isAssumeWithEmptyBundle(const AssumeInst &Assume) {128return none_of(Assume.bundle_op_infos(),129[](const CallBase::BundleOpInfo &BOI) {130return BOI.Tag->getKey() != IgnoreBundleTag;131});132}133134static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {135if (!match(U->getUser(),136m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))137return nullptr;138auto *Intr = cast<IntrinsicInst>(U->getUser());139return &Intr->getBundleOpInfoForOperand(U->getOperandNo());140}141142RetainedKnowledge143llvm::getKnowledgeFromUse(const Use *U,144ArrayRef<Attribute::AttrKind> AttrKinds) {145CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);146if (!Bundle)147return RetainedKnowledge::none();148RetainedKnowledge RK =149getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);150if (llvm::is_contained(AttrKinds, RK.AttrKind))151return RK;152return RetainedKnowledge::none();153}154155RetainedKnowledge156llvm::getKnowledgeForValue(const Value *V,157ArrayRef<Attribute::AttrKind> AttrKinds,158AssumptionCache *AC,159function_ref<bool(RetainedKnowledge, Instruction *,160const CallBase::BundleOpInfo *)>161Filter) {162NumAssumeQueries++;163if (AC) {164for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {165auto *II = cast_or_null<AssumeInst>(Elem.Assume);166if (!II || Elem.Index == AssumptionCache::ExprResultIdx)167continue;168if (RetainedKnowledge RK = getKnowledgeFromBundle(169*II, II->bundle_op_info_begin()[Elem.Index])) {170if (V != RK.WasOn)171continue;172if (is_contained(AttrKinds, RK.AttrKind) &&173Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {174NumUsefullAssumeQueries++;175return RK;176}177}178}179return RetainedKnowledge::none();180}181for (const auto &U : V->uses()) {182CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);183if (!Bundle)184continue;185if (RetainedKnowledge RK =186getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))187if (is_contained(AttrKinds, RK.AttrKind) &&188Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {189NumUsefullAssumeQueries++;190return RK;191}192}193return RetainedKnowledge::none();194}195196RetainedKnowledge llvm::getKnowledgeValidInContext(197const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,198const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {199return getKnowledgeForValue(V, AttrKinds, AC,200[&](auto, Instruction *I, auto) {201return isValidAssumeForContext(I, CtxI, DT);202});203}204205206