15ffd83dbSDimitry Andric //===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "llvm/Analysis/AssumeBundleQueries.h" 105ffd83dbSDimitry Andric #include "llvm/ADT/Statistic.h" 115ffd83dbSDimitry Andric #include "llvm/Analysis/AssumptionCache.h" 125ffd83dbSDimitry Andric #include "llvm/Analysis/ValueTracking.h" 1381ad6265SDimitry Andric #include "llvm/IR/Instruction.h" 1481ad6265SDimitry Andric #include "llvm/IR/Instructions.h" 155ffd83dbSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 165ffd83dbSDimitry Andric #include "llvm/IR/PatternMatch.h" 175ffd83dbSDimitry Andric #include "llvm/Support/DebugCounter.h" 185ffd83dbSDimitry Andric 19fe6060f1SDimitry Andric #define DEBUG_TYPE "assume-queries" 20fe6060f1SDimitry Andric 215ffd83dbSDimitry Andric using namespace llvm; 225ffd83dbSDimitry Andric using namespace llvm::PatternMatch; 235ffd83dbSDimitry Andric 245ffd83dbSDimitry Andric STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles"); 255ffd83dbSDimitry Andric STATISTIC( 265ffd83dbSDimitry Andric NumUsefullAssumeQueries, 275ffd83dbSDimitry Andric "Number of Queries into an assume assume bundles that were satisfied"); 285ffd83dbSDimitry Andric 295ffd83dbSDimitry Andric DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter", 305ffd83dbSDimitry Andric "Controls which assumes gets created"); 315ffd83dbSDimitry Andric 325ffd83dbSDimitry Andric static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) { 335ffd83dbSDimitry Andric return BOI.End - BOI.Begin > Idx; 345ffd83dbSDimitry Andric } 355ffd83dbSDimitry Andric 36fe6060f1SDimitry Andric static Value *getValueFromBundleOpInfo(AssumeInst &Assume, 375ffd83dbSDimitry Andric const CallBase::BundleOpInfo &BOI, 385ffd83dbSDimitry Andric unsigned Idx) { 395ffd83dbSDimitry Andric assert(bundleHasArgument(BOI, Idx) && "index out of range"); 405ffd83dbSDimitry Andric return (Assume.op_begin() + BOI.Begin + Idx)->get(); 415ffd83dbSDimitry Andric } 425ffd83dbSDimitry Andric 43fe6060f1SDimitry Andric bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn, 445ffd83dbSDimitry Andric StringRef AttrName, uint64_t *ArgVal) { 455ffd83dbSDimitry Andric assert(Attribute::isExistingAttribute(AttrName) && 465ffd83dbSDimitry Andric "this attribute doesn't exist"); 47fe6060f1SDimitry Andric assert((ArgVal == nullptr || Attribute::isIntAttrKind( 485ffd83dbSDimitry Andric Attribute::getAttrKindFromName(AttrName))) && 495ffd83dbSDimitry Andric "requested value for an attribute that has no argument"); 505ffd83dbSDimitry Andric if (Assume.bundle_op_infos().empty()) 515ffd83dbSDimitry Andric return false; 525ffd83dbSDimitry Andric 535ffd83dbSDimitry Andric for (auto &BOI : Assume.bundle_op_infos()) { 545ffd83dbSDimitry Andric if (BOI.Tag->getKey() != AttrName) 555ffd83dbSDimitry Andric continue; 565ffd83dbSDimitry Andric if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn || 575ffd83dbSDimitry Andric IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn))) 585ffd83dbSDimitry Andric continue; 595ffd83dbSDimitry Andric if (ArgVal) { 605ffd83dbSDimitry Andric assert(BOI.End - BOI.Begin > ABA_Argument); 615ffd83dbSDimitry Andric *ArgVal = 625ffd83dbSDimitry Andric cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument)) 635ffd83dbSDimitry Andric ->getZExtValue(); 645ffd83dbSDimitry Andric } 655ffd83dbSDimitry Andric return true; 665ffd83dbSDimitry Andric } 675ffd83dbSDimitry Andric return false; 685ffd83dbSDimitry Andric } 695ffd83dbSDimitry Andric 70fe6060f1SDimitry Andric void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) { 715ffd83dbSDimitry Andric for (auto &Bundles : Assume.bundle_op_infos()) { 725ffd83dbSDimitry Andric std::pair<Value *, Attribute::AttrKind> Key{ 735ffd83dbSDimitry Andric nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())}; 745ffd83dbSDimitry Andric if (bundleHasArgument(Bundles, ABA_WasOn)) 755ffd83dbSDimitry Andric Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn); 765ffd83dbSDimitry Andric 775ffd83dbSDimitry Andric if (Key.first == nullptr && Key.second == Attribute::None) 785ffd83dbSDimitry Andric continue; 795ffd83dbSDimitry Andric if (!bundleHasArgument(Bundles, ABA_Argument)) { 805ffd83dbSDimitry Andric Result[Key][&Assume] = {0, 0}; 815ffd83dbSDimitry Andric continue; 825ffd83dbSDimitry Andric } 83fe6060f1SDimitry Andric auto *CI = dyn_cast<ConstantInt>( 84fe6060f1SDimitry Andric getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument)); 85fe6060f1SDimitry Andric if (!CI) 86fe6060f1SDimitry Andric continue; 87349cc55cSDimitry Andric uint64_t Val = CI->getZExtValue(); 885ffd83dbSDimitry Andric auto Lookup = Result.find(Key); 895ffd83dbSDimitry Andric if (Lookup == Result.end() || !Lookup->second.count(&Assume)) { 905ffd83dbSDimitry Andric Result[Key][&Assume] = {Val, Val}; 915ffd83dbSDimitry Andric continue; 925ffd83dbSDimitry Andric } 935ffd83dbSDimitry Andric Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min); 945ffd83dbSDimitry Andric Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max); 955ffd83dbSDimitry Andric } 965ffd83dbSDimitry Andric } 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric RetainedKnowledge 99fe6060f1SDimitry Andric llvm::getKnowledgeFromBundle(AssumeInst &Assume, 1005ffd83dbSDimitry Andric const CallBase::BundleOpInfo &BOI) { 1015ffd83dbSDimitry Andric RetainedKnowledge Result; 1025ffd83dbSDimitry Andric Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey()); 1035ffd83dbSDimitry Andric if (bundleHasArgument(BOI, ABA_WasOn)) 1045ffd83dbSDimitry Andric Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn); 105349cc55cSDimitry Andric auto GetArgOr1 = [&](unsigned Idx) -> uint64_t { 106e8d8bef9SDimitry Andric if (auto *ConstInt = dyn_cast<ConstantInt>( 107e8d8bef9SDimitry Andric getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx))) 108e8d8bef9SDimitry Andric return ConstInt->getZExtValue(); 109e8d8bef9SDimitry Andric return 1; 110e8d8bef9SDimitry Andric }; 1115ffd83dbSDimitry Andric if (BOI.End - BOI.Begin > ABA_Argument) 112e8d8bef9SDimitry Andric Result.ArgValue = GetArgOr1(0); 113e8d8bef9SDimitry Andric if (Result.AttrKind == Attribute::Alignment) 114e8d8bef9SDimitry Andric if (BOI.End - BOI.Begin > ABA_Argument + 1) 115e8d8bef9SDimitry Andric Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1)); 1165ffd83dbSDimitry Andric return Result; 1175ffd83dbSDimitry Andric } 1185ffd83dbSDimitry Andric 119fe6060f1SDimitry Andric RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume, 1205ffd83dbSDimitry Andric unsigned Idx) { 1215ffd83dbSDimitry Andric CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx); 122fe6060f1SDimitry Andric return getKnowledgeFromBundle(Assume, BOI); 1235ffd83dbSDimitry Andric } 1245ffd83dbSDimitry Andric 125fe6060f1SDimitry Andric bool llvm::isAssumeWithEmptyBundle(AssumeInst &Assume) { 1265ffd83dbSDimitry Andric return none_of(Assume.bundle_op_infos(), 1275ffd83dbSDimitry Andric [](const CallBase::BundleOpInfo &BOI) { 1285ffd83dbSDimitry Andric return BOI.Tag->getKey() != IgnoreBundleTag; 1295ffd83dbSDimitry Andric }); 1305ffd83dbSDimitry Andric } 1315ffd83dbSDimitry Andric 1325ffd83dbSDimitry Andric static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) { 1335ffd83dbSDimitry Andric if (!match(U->getUser(), 1345ffd83dbSDimitry Andric m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get()))))) 1355ffd83dbSDimitry Andric return nullptr; 136fe6060f1SDimitry Andric auto *Intr = cast<IntrinsicInst>(U->getUser()); 1375ffd83dbSDimitry Andric return &Intr->getBundleOpInfoForOperand(U->getOperandNo()); 1385ffd83dbSDimitry Andric } 1395ffd83dbSDimitry Andric 1405ffd83dbSDimitry Andric RetainedKnowledge 1415ffd83dbSDimitry Andric llvm::getKnowledgeFromUse(const Use *U, 1425ffd83dbSDimitry Andric ArrayRef<Attribute::AttrKind> AttrKinds) { 1435ffd83dbSDimitry Andric CallInst::BundleOpInfo* Bundle = getBundleFromUse(U); 1445ffd83dbSDimitry Andric if (!Bundle) 1455ffd83dbSDimitry Andric return RetainedKnowledge::none(); 1465ffd83dbSDimitry Andric RetainedKnowledge RK = 147fe6060f1SDimitry Andric getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle); 148fe6060f1SDimitry Andric if (llvm::is_contained(AttrKinds, RK.AttrKind)) 1495ffd83dbSDimitry Andric return RK; 1505ffd83dbSDimitry Andric return RetainedKnowledge::none(); 1515ffd83dbSDimitry Andric } 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric RetainedKnowledge 1545ffd83dbSDimitry Andric llvm::getKnowledgeForValue(const Value *V, 1555ffd83dbSDimitry Andric ArrayRef<Attribute::AttrKind> AttrKinds, 1565ffd83dbSDimitry Andric AssumptionCache *AC, 1575ffd83dbSDimitry Andric function_ref<bool(RetainedKnowledge, Instruction *, 1585ffd83dbSDimitry Andric const CallBase::BundleOpInfo *)> 1595ffd83dbSDimitry Andric Filter) { 1605ffd83dbSDimitry Andric NumAssumeQueries++; 1615ffd83dbSDimitry Andric if (!DebugCounter::shouldExecute(AssumeQueryCounter)) 1625ffd83dbSDimitry Andric return RetainedKnowledge::none(); 1635ffd83dbSDimitry Andric if (AC) { 1645ffd83dbSDimitry Andric for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) { 165*06c3fb27SDimitry Andric auto *II = cast_or_null<AssumeInst>(Elem.Assume); 1665ffd83dbSDimitry Andric if (!II || Elem.Index == AssumptionCache::ExprResultIdx) 1675ffd83dbSDimitry Andric continue; 1685ffd83dbSDimitry Andric if (RetainedKnowledge RK = getKnowledgeFromBundle( 169e8d8bef9SDimitry Andric *II, II->bundle_op_info_begin()[Elem.Index])) { 170e8d8bef9SDimitry Andric if (V != RK.WasOn) 171e8d8bef9SDimitry Andric continue; 1725ffd83dbSDimitry Andric if (is_contained(AttrKinds, RK.AttrKind) && 1735ffd83dbSDimitry Andric Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) { 1745ffd83dbSDimitry Andric NumUsefullAssumeQueries++; 1755ffd83dbSDimitry Andric return RK; 1765ffd83dbSDimitry Andric } 1775ffd83dbSDimitry Andric } 178e8d8bef9SDimitry Andric } 1795ffd83dbSDimitry Andric return RetainedKnowledge::none(); 1805ffd83dbSDimitry Andric } 1815ffd83dbSDimitry Andric for (const auto &U : V->uses()) { 1825ffd83dbSDimitry Andric CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U); 1835ffd83dbSDimitry Andric if (!Bundle) 1845ffd83dbSDimitry Andric continue; 1855ffd83dbSDimitry Andric if (RetainedKnowledge RK = 186fe6060f1SDimitry Andric getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle)) 1875ffd83dbSDimitry Andric if (is_contained(AttrKinds, RK.AttrKind) && 1885ffd83dbSDimitry Andric Filter(RK, cast<Instruction>(U.getUser()), Bundle)) { 1895ffd83dbSDimitry Andric NumUsefullAssumeQueries++; 1905ffd83dbSDimitry Andric return RK; 1915ffd83dbSDimitry Andric } 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric return RetainedKnowledge::none(); 1945ffd83dbSDimitry Andric } 1955ffd83dbSDimitry Andric 1965ffd83dbSDimitry Andric RetainedKnowledge llvm::getKnowledgeValidInContext( 1975ffd83dbSDimitry Andric const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds, 1985ffd83dbSDimitry Andric const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) { 1995ffd83dbSDimitry Andric return getKnowledgeForValue(V, AttrKinds, AC, 2005ffd83dbSDimitry Andric [&](auto, Instruction *I, auto) { 2015ffd83dbSDimitry Andric return isValidAssumeForContext(I, CtxI, DT); 2025ffd83dbSDimitry Andric }); 2035ffd83dbSDimitry Andric } 204