|
15 | 15 |
|
16 | 16 | using namespace llvm; |
17 | 17 |
|
18 | | -namespace { |
19 | | - |
20 | 18 | cl::opt<bool> ShouldPreserveAllAttributes( |
21 | 19 | "assume-preserve-all", cl::init(false), cl::Hidden, |
22 | 20 | cl::desc("enable preservation of all attrbitues. even those that are " |
23 | 21 | "unlikely to be usefull")); |
24 | 22 |
|
| 23 | +namespace { |
| 24 | + |
25 | 25 | struct AssumedKnowledge { |
26 | 26 | const char *Name; |
27 | 27 | Value *Argument; |
@@ -59,22 +59,33 @@ template <> struct DenseMapInfo<AssumedKnowledge> { |
59 | 59 |
|
60 | 60 | namespace { |
61 | 61 |
|
| 62 | +/// Index of elements in the operand bundle. |
| 63 | +/// If the element exist it is guaranteed to be what is specified in this enum |
| 64 | +/// but it may not exist. |
| 65 | +enum BundleOpInfoElem { |
| 66 | + BOIE_WasOn = 0, |
| 67 | + BOIE_Argument = 1, |
| 68 | +}; |
| 69 | + |
62 | 70 | /// Deterministically compare OperandBundleDef. |
63 | 71 | /// The ordering is: |
64 | | -/// - by the name of the attribute, (doesn't change) |
65 | | -/// - then by the Value of the argument, (doesn't change) |
| 72 | +/// - by the attribute's name aka operand bundle tag, (doesn't change) |
| 73 | +/// - then by the numeric Value of the argument, (doesn't change) |
66 | 74 | /// - lastly by the Name of the current Value it WasOn. (may change) |
67 | 75 | /// This order is deterministic and allows looking for the right kind of |
68 | 76 | /// attribute with binary search. However finding the right WasOn needs to be |
69 | | -/// done via linear search because values can get remplaced. |
| 77 | +/// done via linear search because values can get replaced. |
70 | 78 | bool isLowerOpBundle(const OperandBundleDef &LHS, const OperandBundleDef &RHS) { |
71 | 79 | auto getTuple = [](const OperandBundleDef &Op) { |
72 | 80 | return std::make_tuple( |
73 | 81 | Op.getTag(), |
74 | | - Op.input_size() < 2 |
| 82 | + Op.input_size() <= BOIE_Argument |
75 | 83 | ? 0 |
76 | | - : cast<ConstantInt>(*std::next(Op.input_begin()))->getZExtValue(), |
77 | | - Op.input_size() < 1 ? StringRef("") : (*Op.input_begin())->getName()); |
| 84 | + : cast<ConstantInt>(*(Op.input_begin() + BOIE_Argument)) |
| 85 | + ->getZExtValue(), |
| 86 | + Op.input_size() <= BOIE_WasOn |
| 87 | + ? StringRef("") |
| 88 | + : (*(Op.input_begin() + BOIE_WasOn))->getName()); |
78 | 89 | }; |
79 | 90 | return getTuple(LHS) < getTuple(RHS); |
80 | 91 | } |
@@ -160,6 +171,88 @@ CallInst *llvm::BuildAssumeFromInst(const Instruction *I, Module *M) { |
160 | 171 | return Builder.build(); |
161 | 172 | } |
162 | 173 |
|
| 174 | +#ifndef NDEBUG |
| 175 | + |
| 176 | +static bool isExistingAttribute(StringRef Name) { |
| 177 | + return StringSwitch<bool>(Name) |
| 178 | +#define GET_ATTR_NAMES |
| 179 | +#define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true) |
| 180 | +#include "llvm/IR/Attributes.inc" |
| 181 | + .Default(false); |
| 182 | +} |
| 183 | + |
| 184 | +#endif |
| 185 | + |
| 186 | +bool llvm::hasAttributeInAssume(CallInst &AssumeCI, Value *IsOn, |
| 187 | + StringRef AttrName, uint64_t *ArgVal, |
| 188 | + AssumeQuery AQR) { |
| 189 | + IntrinsicInst &Assume = cast<IntrinsicInst>(AssumeCI); |
| 190 | + assert(Assume.getIntrinsicID() == Intrinsic::assume && |
| 191 | + "this function is intended to be used on llvm.assume"); |
| 192 | + assert(isExistingAttribute(AttrName) && "this attribute doesn't exist"); |
| 193 | + assert((ArgVal == nullptr || Attribute::doesAttrKindHaveArgument( |
| 194 | + Attribute::getAttrKindFromName(AttrName))) && |
| 195 | + "requested value for an attribute that has no argument"); |
| 196 | + if (Assume.bundle_op_infos().empty()) |
| 197 | + return false; |
| 198 | + |
| 199 | + CallInst::bundle_op_iterator Lookup; |
| 200 | + |
| 201 | + /// The right attribute can be found by binary search. After this finding the |
| 202 | + /// right WasOn needs to be done via linear search. |
| 203 | + /// Element have been ordered by argument value so the first we find is the |
| 204 | + /// one we need. |
| 205 | + if (AQR == AssumeQuery::Lowest) |
| 206 | + Lookup = |
| 207 | + llvm::lower_bound(Assume.bundle_op_infos(), AttrName, |
| 208 | + [](const CallBase::BundleOpInfo &BOI, StringRef RHS) { |
| 209 | + assert(isExistingAttribute(BOI.Tag->getKey()) && |
| 210 | + "this attribute doesn't exist"); |
| 211 | + return BOI.Tag->getKey() < RHS; |
| 212 | + }); |
| 213 | + else |
| 214 | + Lookup = std::prev( |
| 215 | + llvm::upper_bound(Assume.bundle_op_infos(), AttrName, |
| 216 | + [](StringRef LHS, const CallBase::BundleOpInfo &BOI) { |
| 217 | + assert(isExistingAttribute(BOI.Tag->getKey()) && |
| 218 | + "this attribute doesn't exist"); |
| 219 | + return LHS < BOI.Tag->getKey(); |
| 220 | + })); |
| 221 | + |
| 222 | + auto getValueFromBundleOpInfo = [&Assume](const CallBase::BundleOpInfo &BOI, |
| 223 | + unsigned Idx) { |
| 224 | + assert(BOI.End - BOI.Begin > Idx && "index out of range"); |
| 225 | + return (Assume.op_begin() + BOI.Begin + Idx)->get(); |
| 226 | + }; |
| 227 | + |
| 228 | + if (Lookup == Assume.bundle_op_info_end() || |
| 229 | + Lookup->Tag->getKey() != AttrName) |
| 230 | + return false; |
| 231 | + if (IsOn) { |
| 232 | + if (Lookup->End - Lookup->Begin < BOIE_WasOn) |
| 233 | + return false; |
| 234 | + while (true) { |
| 235 | + if (Lookup == Assume.bundle_op_info_end() || |
| 236 | + Lookup->Tag->getKey() != AttrName) |
| 237 | + return false; |
| 238 | + if (getValueFromBundleOpInfo(*Lookup, BOIE_WasOn) == IsOn) |
| 239 | + break; |
| 240 | + if (AQR == AssumeQuery::Highest && |
| 241 | + Lookup == Assume.bundle_op_info_begin()) |
| 242 | + return false; |
| 243 | + Lookup = Lookup + (AQR == AssumeQuery::Lowest ? 1 : -1); |
| 244 | + } |
| 245 | + } |
| 246 | + |
| 247 | + if (Lookup->End - Lookup->Begin < BOIE_Argument) |
| 248 | + return true; |
| 249 | + if (ArgVal) |
| 250 | + *ArgVal = |
| 251 | + cast<ConstantInt>(getValueFromBundleOpInfo(*Lookup, BOIE_Argument)) |
| 252 | + ->getZExtValue(); |
| 253 | + return true; |
| 254 | +} |
| 255 | + |
163 | 256 | PreservedAnalyses AssumeBuilderPass::run(Function &F, |
164 | 257 | FunctionAnalysisManager &AM) { |
165 | 258 | for (Instruction &I : instructions(F)) |
|
0 commit comments