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