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