AssumeBundleQueries.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. //===----------------------------------------------------------------------===//
  8. #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"
  17. #define DEBUG_TYPE "assume-queries"
  18. using namespace llvm;
  19. using namespace llvm::PatternMatch;
  20. STATISTIC(NumAssumeQueries, "Number of Queries into an assume assume bundles");
  21. STATISTIC(
  22. NumUsefullAssumeQueries,
  23. "Number of Queries into an assume assume bundles that were satisfied");
  24. DEBUG_COUNTER(AssumeQueryCounter, "assume-queries-counter",
  25. "Controls which assumes gets created");
  26. static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) {
  27. return BOI.End - BOI.Begin > Idx;
  28. }
  29. static Value *getValueFromBundleOpInfo(AssumeInst &Assume,
  30. const CallBase::BundleOpInfo &BOI,
  31. unsigned Idx) {
  32. assert(bundleHasArgument(BOI, Idx) && "index out of range");
  33. return (Assume.op_begin() + BOI.Begin + Idx)->get();
  34. }
  35. bool llvm::hasAttributeInAssume(AssumeInst &Assume, Value *IsOn,
  36. StringRef AttrName, uint64_t *ArgVal) {
  37. assert(Attribute::isExistingAttribute(AttrName) &&
  38. "this attribute doesn't exist");
  39. assert((ArgVal == nullptr || Attribute::isIntAttrKind(
  40. Attribute::getAttrKindFromName(AttrName))) &&
  41. "requested value for an attribute that has no argument");
  42. if (Assume.bundle_op_infos().empty())
  43. return false;
  44. for (auto &BOI : Assume.bundle_op_infos()) {
  45. if (BOI.Tag->getKey() != AttrName)
  46. continue;
  47. if (IsOn && (BOI.End - BOI.Begin <= ABA_WasOn ||
  48. IsOn != getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn)))
  49. continue;
  50. if (ArgVal) {
  51. assert(BOI.End - BOI.Begin > ABA_Argument);
  52. *ArgVal =
  53. cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
  54. ->getZExtValue();
  55. }
  56. return true;
  57. }
  58. return false;
  59. }
  60. void llvm::fillMapFromAssume(AssumeInst &Assume, RetainedKnowledgeMap &Result) {
  61. for (auto &Bundles : Assume.bundle_op_infos()) {
  62. std::pair<Value *, Attribute::AttrKind> Key{
  63. nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())};
  64. if (bundleHasArgument(Bundles, ABA_WasOn))
  65. Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn);
  66. if (Key.first == nullptr && Key.second == Attribute::None)
  67. continue;
  68. if (!bundleHasArgument(Bundles, ABA_Argument)) {
  69. Result[Key][&Assume] = {0, 0};
  70. continue;
  71. }
  72. auto *CI = dyn_cast<ConstantInt>(
  73. getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument));
  74. if (!CI)
  75. continue;
  76. uint64_t Val = CI->getZExtValue();
  77. auto Lookup = Result.find(Key);
  78. if (Lookup == Result.end() || !Lookup->second.count(&Assume)) {
  79. Result[Key][&Assume] = {Val, Val};
  80. continue;
  81. }
  82. Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min);
  83. Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max);
  84. }
  85. }
  86. RetainedKnowledge
  87. llvm::getKnowledgeFromBundle(AssumeInst &Assume,
  88. const CallBase::BundleOpInfo &BOI) {
  89. RetainedKnowledge Result;
  90. Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
  91. if (bundleHasArgument(BOI, ABA_WasOn))
  92. Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
  93. auto GetArgOr1 = [&](unsigned Idx) -> uint64_t {
  94. if (auto *ConstInt = dyn_cast<ConstantInt>(
  95. getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
  96. return ConstInt->getZExtValue();
  97. return 1;
  98. };
  99. if (BOI.End - BOI.Begin > ABA_Argument)
  100. Result.ArgValue = GetArgOr1(0);
  101. if (Result.AttrKind == Attribute::Alignment)
  102. if (BOI.End - BOI.Begin > ABA_Argument + 1)
  103. Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
  104. return Result;
  105. }
  106. RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(AssumeInst &Assume,
  107. unsigned Idx) {
  108. CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
  109. return getKnowledgeFromBundle(Assume, BOI);
  110. }
  111. bool llvm::isAssumeWithEmptyBundle(AssumeInst &Assume) {
  112. return none_of(Assume.bundle_op_infos(),
  113. [](const CallBase::BundleOpInfo &BOI) {
  114. return BOI.Tag->getKey() != IgnoreBundleTag;
  115. });
  116. }
  117. static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
  118. if (!match(U->getUser(),
  119. m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
  120. return nullptr;
  121. auto *Intr = cast<IntrinsicInst>(U->getUser());
  122. return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
  123. }
  124. RetainedKnowledge
  125. llvm::getKnowledgeFromUse(const Use *U,
  126. ArrayRef<Attribute::AttrKind> AttrKinds) {
  127. CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
  128. if (!Bundle)
  129. return RetainedKnowledge::none();
  130. RetainedKnowledge RK =
  131. getKnowledgeFromBundle(*cast<AssumeInst>(U->getUser()), *Bundle);
  132. if (llvm::is_contained(AttrKinds, RK.AttrKind))
  133. return RK;
  134. return RetainedKnowledge::none();
  135. }
  136. RetainedKnowledge
  137. llvm::getKnowledgeForValue(const Value *V,
  138. ArrayRef<Attribute::AttrKind> AttrKinds,
  139. AssumptionCache *AC,
  140. function_ref<bool(RetainedKnowledge, Instruction *,
  141. const CallBase::BundleOpInfo *)>
  142. Filter) {
  143. NumAssumeQueries++;
  144. if (!DebugCounter::shouldExecute(AssumeQueryCounter))
  145. return RetainedKnowledge::none();
  146. if (AC) {
  147. for (AssumptionCache::ResultElem &Elem : AC->assumptionsFor(V)) {
  148. auto *II = dyn_cast_or_null<AssumeInst>(Elem.Assume);
  149. if (!II || Elem.Index == AssumptionCache::ExprResultIdx)
  150. continue;
  151. if (RetainedKnowledge RK = getKnowledgeFromBundle(
  152. *II, II->bundle_op_info_begin()[Elem.Index])) {
  153. if (V != RK.WasOn)
  154. continue;
  155. if (is_contained(AttrKinds, RK.AttrKind) &&
  156. Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
  157. NumUsefullAssumeQueries++;
  158. return RK;
  159. }
  160. }
  161. }
  162. return RetainedKnowledge::none();
  163. }
  164. for (const auto &U : V->uses()) {
  165. CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
  166. if (!Bundle)
  167. continue;
  168. if (RetainedKnowledge RK =
  169. getKnowledgeFromBundle(*cast<AssumeInst>(U.getUser()), *Bundle))
  170. if (is_contained(AttrKinds, RK.AttrKind) &&
  171. Filter(RK, cast<Instruction>(U.getUser()), Bundle)) {
  172. NumUsefullAssumeQueries++;
  173. return RK;
  174. }
  175. }
  176. return RetainedKnowledge::none();
  177. }
  178. RetainedKnowledge llvm::getKnowledgeValidInContext(
  179. const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
  180. const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
  181. return getKnowledgeForValue(V, AttrKinds, AC,
  182. [&](auto, Instruction *I, auto) {
  183. return isValidAssumeForContext(I, CtxI, DT);
  184. });
  185. }