xref: /llvm-project/llvm/lib/Analysis/AssumeBundleQueries.cpp (revision 56f569049c9df7e4db6aa14eae6c4fe200350bf6)
1c00cb762STyker //===- AssumeBundleQueries.cpp - tool to query assume bundles ---*- C++ -*-===//
2c00cb762STyker //
3c00cb762STyker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c00cb762STyker // See https://llvm.org/LICENSE.txt for license information.
5c00cb762STyker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c00cb762STyker //
7c00cb762STyker //===----------------------------------------------------------------------===//
8c00cb762STyker 
9c00cb762STyker #include "llvm/Analysis/AssumeBundleQueries.h"
1016f777f4STyker #include "llvm/ADT/Statistic.h"
1142431da8STyker #include "llvm/Analysis/AssumptionCache.h"
1242431da8STyker #include "llvm/Analysis/ValueTracking.h"
1371c3a551Sserge-sans-paille #include "llvm/IR/Instruction.h"
1471c3a551Sserge-sans-paille #include "llvm/IR/Instructions.h"
15c00cb762STyker #include "llvm/IR/IntrinsicInst.h"
1642431da8STyker #include "llvm/IR/PatternMatch.h"
1716f777f4STyker #include "llvm/Support/DebugCounter.h"
18c00cb762STyker 
1971acce68SMindong Chen #define DEBUG_TYPE "assume-queries"
2071acce68SMindong Chen 
21c00cb762STyker using namespace llvm;
2242431da8STyker using namespace llvm::PatternMatch;
23c00cb762STyker 
2416f777f4STyker STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles");
2516f777f4STyker STATISTIC(
2616f777f4STyker     NumUsefullAssumeQueries,
2716f777f4STyker     "Number of Queries into an assume assume bundles that were satisfied");
2816f777f4STyker 
2916f777f4STyker DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter",
3016f777f4STyker               "Controls which assumes gets created");
3116f777f4STyker 
bundleHasArgument(const CallBase::BundleOpInfo & BOI,unsigned Idx)32c00cb762STyker static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {
33c00cb762STyker   return BOI.End - BOI.Begin > Idx;
34c00cb762STyker }
35c00cb762STyker 
getValueFromBundleOpInfo(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI,unsigned Idx)369ef6aa02SPhilip Reames static Value *getValueFromBundleOpInfo(AssumeInst &Assume,
37c00cb762STyker                                        const CallBase::BundleOpInfo &BOI,
38c00cb762STyker                                        unsigned Idx) {
39c00cb762STyker   assert(bundleHasArgument(BOI, Idx) && "index out of range");
40c00cb762STyker   return (Assume.op_begin() + BOI.Begin + Idx)->get();
41c00cb762STyker }
42c00cb762STyker 
hasAttributeInAssume(AssumeInst & Assume,Value * IsOn,StringRef AttrName,uint64_t * ArgVal)439ef6aa02SPhilip Reames bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
44e5f8a77cSTyker                                 StringRef AttrName, uint64_t *ArgVal) {
45c00cb762STyker   assert(Attribute::isExistingAttribute(AttrName) &&
46c00cb762STyker          "this attribute doesn't exist");
476ac32872SNikita Popov   assert((ArgVal == nullptr || Attribute::isIntAttrKind(
48c00cb762STyker                                    Attribute::getAttrKindFromName(AttrName))) &&
49c00cb762STyker          "requested value for an attribute that has no argument");
50c00cb762STyker   if (Assume.bundle_op_infos().empty())
51c00cb762STyker     return false;
52c00cb762STyker 
53e5f8a77cSTyker   for (auto &BOI : Assume.bundle_op_infos()) {
54c00cb762STyker     if (BOI.Tag->getKey() != AttrName)
55c00cb762STyker       continue;
56c00cb762STyker     if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn ||
57c00cb762STyker                  IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn)))
58c00cb762STyker       continue;
59c00cb762STyker     if (ArgVal) {
60c00cb762STyker       assert(BOI.End - BOI.Begin > ABA_Argument);
61e5f8a77cSTyker       *ArgVal =
62e5f8a77cSTyker           cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
63c00cb762STyker               ->getZExtValue();
64c00cb762STyker     }
65c00cb762STyker     return true;
66c00cb762STyker   }
67c00cb762STyker   return false;
68c00cb762STyker }
69c00cb762STyker 
fillMapFromAssume(AssumeInst & Assume,RetainedKnowledgeMap & Result)709ef6aa02SPhilip Reames void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {
71c00cb762STyker   for (auto &Bundles : Assume.bundle_op_infos()) {
72c00cb762STyker     std::pair<Value *, Attribute::AttrKind> Key{
73c00cb762STyker         nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};
74c00cb762STyker     if (bundleHasArgument(Bundles, ABA_WasOn))
75c00cb762STyker       Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);
76c00cb762STyker 
77c00cb762STyker     if (Key.first == nullptr && Key.second == Attribute::None)
78c00cb762STyker       continue;
79c00cb762STyker     if (!bundleHasArgument(Bundles, ABA_Argument)) {
80c00cb762STyker       Result[Key][&Assume] = {0, 0};
81c00cb762STyker       continue;
82c00cb762STyker     }
83d22fbccfSJohannes Doerfert     auto *CI = dyn_cast<ConstantInt>(
84d22fbccfSJohannes Doerfert         getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));
85d22fbccfSJohannes Doerfert     if (!CI)
86d22fbccfSJohannes Doerfert       continue;
873628bb74SArthur Eubanks     uint64_t Val = CI->getZExtValue();
88c00cb762STyker     auto Lookup = Result.find(Key);
89c00cb762STyker     if (Lookup == Result.end() || !Lookup->second.count(&Assume)) {
90c00cb762STyker       Result[Key][&Assume] = {Val, Val};
91c00cb762STyker       continue;
92c00cb762STyker     }
93c00cb762STyker     Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min);
94c00cb762STyker     Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max);
95c00cb762STyker   }
96c00cb762STyker }
97c00cb762STyker 
98da100de0SOCHyams RetainedKnowledge
getKnowledgeFromBundle(AssumeInst & Assume,const CallBase::BundleOpInfo & BOI)999ef6aa02SPhilip Reames llvm::getKnowledgeFromBundle(AssumeInst &Assume,
100da100de0SOCHyams                              const CallBase::BundleOpInfo &BOI) {
101c00cb762STyker   RetainedKnowledge Result;
102*56f56904SNikita Popov   if (!DebugCounter::shouldExecute(AssumeQueryCounter))
103*56f56904SNikita Popov     return Result;
104*56f56904SNikita Popov 
105c00cb762STyker   Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
106da100de0SOCHyams   if (bundleHasArgument(BOI, ABA_WasOn))
107c00cb762STyker     Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
1083628bb74SArthur Eubanks   auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {
10978de7297STyker     if (auto *ConstInt = dyn_cast<ConstantInt>(
11078de7297STyker             getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
11178de7297STyker       return ConstInt->getZExtValue();
11278de7297STyker     return 1;
11378de7297STyker   };
114c00cb762STyker   if (BOI.End - BOI.Begin > ABA_Argument)
11578de7297STyker     Result.ArgValue = GetArgOr1(0);
11678de7297STyker   if (Result.AttrKind == Attribute::Alignment)
11778de7297STyker     if (BOI.End - BOI.Begin > ABA_Argument + 1)
11878de7297STyker       Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
119c00cb762STyker   return Result;
120c00cb762STyker }
121c00cb762STyker 
getKnowledgeFromOperandInAssume(AssumeInst & Assume,unsigned Idx)1229ef6aa02SPhilip Reames RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
12342431da8STyker                                                         unsigned Idx) {
12442431da8STyker   CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
1259ef6aa02SPhilip Reames   return getKnowledgeFromBundle(Assume, BOI);
12642431da8STyker }
12742431da8STyker 
isAssumeWithEmptyBundle(const AssumeInst & Assume)12806dfc840SSerguei Katkov bool llvm::isAssumeWithEmptyBundle(const AssumeInst &Assume) {
129c00cb762STyker   return none_of(Assume.bundle_op_infos(),
130c00cb762STyker                  [](const CallBase::BundleOpInfo &BOI) {
131da100de0SOCHyams                    return BOI.Tag->getKey() != IgnoreBundleTag;
132c00cb762STyker                  });
133c00cb762STyker }
13442431da8STyker 
getBundleFromUse(const Use * U)135821a0f23STyker static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
136821a0f23STyker   if (!match(U->getUser(),
137821a0f23STyker              m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
138821a0f23STyker     return nullptr;
13976a1be05SSimon Pilgrim   auto *Intr = cast<IntrinsicInst>(U->getUser());
140821a0f23STyker   return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
141821a0f23STyker }
142821a0f23STyker 
14342431da8STyker RetainedKnowledge
getKnowledgeFromUse(const Use * U,ArrayRef<Attribute::AttrKind> AttrKinds)14442431da8STyker llvm::getKnowledgeFromUse(const Use *U,
14542431da8STyker                           ArrayRef<Attribute::AttrKind> AttrKinds) {
146821a0f23STyker   CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
147821a0f23STyker   if (!Bundle)
14842431da8STyker     return RetainedKnowledge::none();
14942431da8STyker   RetainedKnowledge RK =
1509ef6aa02SPhilip Reames       getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
151910e2d1eSKazu Hirata   if (llvm::is_contained(AttrKinds, RK.AttrKind))
15242431da8STyker     return RK;
15342431da8STyker   return RetainedKnowledge::none();
15442431da8STyker }
15542431da8STyker 
156821a0f23STyker RetainedKnowledge
getKnowledgeForValue(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,AssumptionCache * AC,function_ref<bool (RetainedKnowledge,Instruction *,const CallBase::BundleOpInfo *)> Filter)157821a0f23STyker llvm::getKnowledgeForValue(const Value *V,
158821a0f23STyker                            ArrayRef<Attribute::AttrKind> AttrKinds,
15942431da8STyker                            AssumptionCache *AC,
160821a0f23STyker                            function_ref<bool(RetainedKnowledge, Instruction *,
161821a0f23STyker                                              const CallBase::BundleOpInfo *)>
162821a0f23STyker                                Filter) {
16316f777f4STyker   NumAssumeQueries++;
16442431da8STyker   if (AC) {
16542431da8STyker     for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {
1660cbb8ec0SMax Kazantsev       auto *II = cast_or_null<AssumeInst>(Elem.Assume);
16742431da8STyker       if (!II || Elem.Index == AssumptionCache::ExprResultIdx)
16842431da8STyker         continue;
16942431da8STyker       if (RetainedKnowledge RK = getKnowledgeFromBundle(
170a79e6044STyker               *II, II->bundle_op_info_begin()[Elem.Index])) {
171a79e6044STyker         if (V != RK.WasOn)
172a79e6044STyker           continue;
173821a0f23STyker         if (is_contained(AttrKinds, RK.AttrKind) &&
17416f777f4STyker             Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
17516f777f4STyker           NumUsefullAssumeQueries++;
17642431da8STyker           return RK;
17742431da8STyker         }
17816f777f4STyker       }
179a79e6044STyker     }
18042431da8STyker     return RetainedKnowledge::none();
18142431da8STyker   }
18216f777f4STyker   for (const auto &U : V->uses()) {
183821a0f23STyker     CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
184821a0f23STyker     if (!Bundle)
185821a0f23STyker       continue;
186821a0f23STyker     if (RetainedKnowledge RK =
1879ef6aa02SPhilip Reames             getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))
188821a0f23STyker       if (is_contained(AttrKinds, RK.AttrKind) &&
18916f777f4STyker           Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {
19016f777f4STyker         NumUsefullAssumeQueries++;
19142431da8STyker         return RK;
19242431da8STyker       }
19316f777f4STyker   }
19442431da8STyker   return RetainedKnowledge::none();
19542431da8STyker }
19642431da8STyker 
getKnowledgeValidInContext(const Value * V,ArrayRef<Attribute::AttrKind> AttrKinds,const Instruction * CtxI,const DominatorTree * DT,AssumptionCache * AC)19742431da8STyker RetainedKnowledge llvm::getKnowledgeValidInContext(
19842431da8STyker     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
19942431da8STyker     const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
20042431da8STyker   return getKnowledgeForValue(V, AttrKinds, AC,
201821a0f23STyker                               [&](auto, Instruction *I, auto) {
20242431da8STyker                                 return isValidAssumeForContext(I, CtxI, DT);
20342431da8STyker                               });
20442431da8STyker }
205