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 9 #include "llvm/Analysis/AssumeBundleQueries.h" 10 #include "llvm/IR/Function.h" 11 #include "llvm/IR/InstIterator.h" 12 #include "llvm/IR/IntrinsicInst.h" 13 14 using namespace llvm; 15 16 static bool bundleHasArgument(const CallBase::BundleOpInfo &BOI, unsigned Idx) { 17 return BOI.End - BOI.Begin > Idx; 18 } 19 20 static Value *getValueFromBundleOpInfo(IntrinsicInst &Assume, 21 const CallBase::BundleOpInfo &BOI, 22 unsigned Idx) { 23 assert(bundleHasArgument(BOI, Idx) && "index out of range"); 24 return (Assume.op_begin() + BOI.Begin + Idx)->get(); 25 } 26 27 bool llvm::hasAttributeInAssume(CallInst &AssumeCI, Value *IsOn, 28 StringRef AttrName, uint64_t *ArgVal, 29 AssumeQuery AQR) { 30 assert(isa<IntrinsicInst>(AssumeCI) && 31 "this function is intended to be used on llvm.assume"); 32 IntrinsicInst &Assume = cast<IntrinsicInst>(AssumeCI); 33 assert(Assume.getIntrinsicID() == Intrinsic::assume && 34 "this function is intended to be used on llvm.assume"); 35 assert(Attribute::isExistingAttribute(AttrName) && 36 "this attribute doesn't exist"); 37 assert((ArgVal == nullptr || Attribute::doesAttrKindHaveArgument( 38 Attribute::getAttrKindFromName(AttrName))) && 39 "requested value for an attribute that has no argument"); 40 if (Assume.bundle_op_infos().empty()) 41 return false; 42 43 auto Loop = [&](auto &&Range) { 44 for (auto &BOI : Range) { 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 = cast<ConstantInt>( 53 getValueFromBundleOpInfo(Assume, BOI, ABA_Argument)) 54 ->getZExtValue(); 55 } 56 return true; 57 } 58 return false; 59 }; 60 61 if (AQR == AssumeQuery::Lowest) 62 return Loop(Assume.bundle_op_infos()); 63 return Loop(reverse(Assume.bundle_op_infos())); 64 } 65 66 void llvm::fillMapFromAssume(CallInst &AssumeCI, RetainedKnowledgeMap &Result) { 67 IntrinsicInst &Assume = cast<IntrinsicInst>(AssumeCI); 68 assert(Assume.getIntrinsicID() == Intrinsic::assume && 69 "this function is intended to be used on llvm.assume"); 70 for (auto &Bundles : Assume.bundle_op_infos()) { 71 std::pair<Value *, Attribute::AttrKind> Key{ 72 nullptr, Attribute::getAttrKindFromName(Bundles.Tag->getKey())}; 73 if (bundleHasArgument(Bundles, ABA_WasOn)) 74 Key.first = getValueFromBundleOpInfo(Assume, Bundles, ABA_WasOn); 75 76 if (Key.first == nullptr && Key.second == Attribute::None) 77 continue; 78 if (!bundleHasArgument(Bundles, ABA_Argument)) { 79 Result[Key][&Assume] = {0, 0}; 80 continue; 81 } 82 unsigned Val = cast<ConstantInt>( 83 getValueFromBundleOpInfo(Assume, Bundles, ABA_Argument)) 84 ->getZExtValue(); 85 auto Lookup = Result.find(Key); 86 if (Lookup == Result.end() || !Lookup->second.count(&Assume)) { 87 Result[Key][&Assume] = {Val, Val}; 88 continue; 89 } 90 Lookup->second[&Assume].Min = std::min(Val, Lookup->second[&Assume].Min); 91 Lookup->second[&Assume].Max = std::max(Val, Lookup->second[&Assume].Max); 92 } 93 } 94 95 RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(CallInst &AssumeCI, 96 unsigned Idx) { 97 IntrinsicInst &Assume = cast<IntrinsicInst>(AssumeCI); 98 assert(Assume.getIntrinsicID() == Intrinsic::assume && 99 "this function is intended to be used on llvm.assume"); 100 CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx); 101 RetainedKnowledge Result; 102 Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey()); 103 Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn); 104 if (BOI.End - BOI.Begin > ABA_Argument) 105 Result.ArgValue = 106 cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument)) 107 ->getZExtValue(); 108 109 return Result; 110 } 111 112 bool llvm::isAssumeWithEmptyBundle(CallInst &CI) { 113 IntrinsicInst &Assume = cast<IntrinsicInst>(CI); 114 assert(Assume.getIntrinsicID() == Intrinsic::assume && 115 "this function is intended to be used on llvm.assume"); 116 return none_of(Assume.bundle_op_infos(), 117 [](const CallBase::BundleOpInfo &BOI) { 118 return BOI.Tag->getKey() != "ignore"; 119 }); 120 } 121