File indexing completed on 2026-05-10 08:44:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 #ifndef LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H
0098 #define LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H
0099
0100 #include "llvm/ADT/DenseSet.h"
0101 #include "llvm/ADT/GraphTraits.h"
0102 #include "llvm/ADT/MapVector.h"
0103 #include "llvm/ADT/STLExtras.h"
0104 #include "llvm/ADT/SetOperations.h"
0105 #include "llvm/ADT/SetVector.h"
0106 #include "llvm/ADT/SmallSet.h"
0107 #include "llvm/ADT/iterator.h"
0108 #include "llvm/Analysis/AssumeBundleQueries.h"
0109 #include "llvm/Analysis/CFG.h"
0110 #include "llvm/Analysis/CGSCCPassManager.h"
0111 #include "llvm/Analysis/LazyCallGraph.h"
0112 #include "llvm/Analysis/LoopInfo.h"
0113 #include "llvm/Analysis/MemoryLocation.h"
0114 #include "llvm/Analysis/MustExecute.h"
0115 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
0116 #include "llvm/Analysis/PostDominators.h"
0117 #include "llvm/Analysis/TargetLibraryInfo.h"
0118 #include "llvm/IR/AbstractCallSite.h"
0119 #include "llvm/IR/Attributes.h"
0120 #include "llvm/IR/ConstantRange.h"
0121 #include "llvm/IR/Constants.h"
0122 #include "llvm/IR/GlobalValue.h"
0123 #include "llvm/IR/InstIterator.h"
0124 #include "llvm/IR/Instruction.h"
0125 #include "llvm/IR/Instructions.h"
0126 #include "llvm/IR/Module.h"
0127 #include "llvm/IR/PassManager.h"
0128 #include "llvm/IR/Value.h"
0129 #include "llvm/Support/Alignment.h"
0130 #include "llvm/Support/Allocator.h"
0131 #include "llvm/Support/Casting.h"
0132 #include "llvm/Support/DOTGraphTraits.h"
0133 #include "llvm/Support/DebugCounter.h"
0134 #include "llvm/Support/ErrorHandling.h"
0135 #include "llvm/Support/ModRef.h"
0136 #include "llvm/Support/TimeProfiler.h"
0137 #include "llvm/Support/TypeSize.h"
0138 #include "llvm/TargetParser/Triple.h"
0139 #include "llvm/Transforms/Utils/CallGraphUpdater.h"
0140
0141 #include <limits>
0142 #include <map>
0143 #include <optional>
0144
0145 namespace llvm {
0146
0147 class DataLayout;
0148 class LLVMContext;
0149 class Pass;
0150 template <typename Fn> class function_ref;
0151 struct AADepGraphNode;
0152 struct AADepGraph;
0153 struct Attributor;
0154 struct AbstractAttribute;
0155 struct InformationCache;
0156 struct AAIsDead;
0157 struct AttributorCallGraph;
0158 struct IRPosition;
0159
0160 class Function;
0161
0162
0163 namespace AA {
0164 using InstExclusionSetTy = SmallPtrSet<Instruction *, 4>;
0165
0166 enum class GPUAddressSpace : unsigned {
0167 Generic = 0,
0168 Global = 1,
0169 Shared = 3,
0170 Constant = 4,
0171 Local = 5,
0172 };
0173
0174
0175 bool isGPU(const Module &M);
0176
0177
0178
0179
0180 enum ValueScope : uint8_t {
0181 Intraprocedural = 1,
0182 Interprocedural = 2,
0183 AnyScope = Intraprocedural | Interprocedural,
0184 };
0185
0186 struct ValueAndContext : public std::pair<Value *, const Instruction *> {
0187 using Base = std::pair<Value *, const Instruction *>;
0188 ValueAndContext(const Base &B) : Base(B) {}
0189 ValueAndContext(Value &V, const Instruction *CtxI) : Base(&V, CtxI) {}
0190 ValueAndContext(Value &V, const Instruction &CtxI) : Base(&V, &CtxI) {}
0191
0192 Value *getValue() const { return this->first; }
0193 const Instruction *getCtxI() const { return this->second; }
0194 };
0195
0196
0197
0198 bool isNoSyncInst(Attributor &A, const Instruction &I,
0199 const AbstractAttribute &QueryingAA);
0200
0201
0202
0203
0204
0205
0206 bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA,
0207 const Value &V, bool ForAnalysisOnly = true);
0208
0209
0210
0211 bool isValidInScope(const Value &V, const Function *Scope);
0212
0213
0214
0215
0216 bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache);
0217
0218
0219
0220
0221 Value *getWithType(Value &V, Type &Ty);
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231 std::optional<Value *>
0232 combineOptionalValuesInAAValueLatice(const std::optional<Value *> &A,
0233 const std::optional<Value *> &B, Type *Ty);
0234
0235
0236
0237 struct RangeTy {
0238 int64_t Offset = Unassigned;
0239 int64_t Size = Unassigned;
0240
0241 RangeTy(int64_t Offset, int64_t Size) : Offset(Offset), Size(Size) {}
0242 RangeTy() = default;
0243 static RangeTy getUnknown() { return RangeTy{Unknown, Unknown}; }
0244
0245
0246 bool offsetOrSizeAreUnknown() const {
0247 return Offset == RangeTy::Unknown || Size == RangeTy::Unknown;
0248 }
0249
0250
0251
0252 bool offsetAndSizeAreUnknown() const {
0253 return Offset == RangeTy::Unknown && Size == RangeTy::Unknown;
0254 }
0255
0256
0257 bool isUnassigned() const {
0258 assert((Offset == RangeTy::Unassigned) == (Size == RangeTy::Unassigned) &&
0259 "Inconsistent state!");
0260 return Offset == RangeTy::Unassigned;
0261 }
0262
0263
0264
0265 bool mayOverlap(const RangeTy &Range) const {
0266
0267 if (offsetOrSizeAreUnknown() || Range.offsetOrSizeAreUnknown())
0268 return true;
0269
0270
0271
0272 return Range.Offset + Range.Size > Offset && Range.Offset < Offset + Size;
0273 }
0274
0275 RangeTy &operator&=(const RangeTy &R) {
0276 if (R.isUnassigned())
0277 return *this;
0278 if (isUnassigned())
0279 return *this = R;
0280 if (Offset == Unknown || R.Offset == Unknown)
0281 Offset = Unknown;
0282 if (Size == Unknown || R.Size == Unknown)
0283 Size = Unknown;
0284 if (offsetAndSizeAreUnknown())
0285 return *this;
0286 if (Offset == Unknown) {
0287 Size = std::max(Size, R.Size);
0288 } else if (Size == Unknown) {
0289 Offset = std::min(Offset, R.Offset);
0290 } else {
0291 Offset = std::min(Offset, R.Offset);
0292 Size = std::max(Offset + Size, R.Offset + R.Size) - Offset;
0293 }
0294 return *this;
0295 }
0296
0297
0298
0299
0300
0301 inline static bool LessThan(const RangeTy &L, const RangeTy &R) {
0302 if (L.Offset < R.Offset)
0303 return true;
0304 if (L.Offset == R.Offset)
0305 return L.Size < R.Size;
0306 return false;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315 static constexpr int64_t Unassigned = std::numeric_limits<int32_t>::min();
0316 static constexpr int64_t Unknown = std::numeric_limits<int32_t>::max();
0317 };
0318
0319 inline raw_ostream &operator<<(raw_ostream &OS, const RangeTy &R) {
0320 OS << "[" << R.Offset << ", " << R.Size << "]";
0321 return OS;
0322 }
0323
0324 inline bool operator==(const RangeTy &A, const RangeTy &B) {
0325 return A.Offset == B.Offset && A.Size == B.Size;
0326 }
0327
0328 inline bool operator!=(const RangeTy &A, const RangeTy &B) { return !(A == B); }
0329
0330
0331 Constant *getInitialValueForObj(Attributor &A,
0332 const AbstractAttribute &QueryingAA, Value &Obj,
0333 Type &Ty, const TargetLibraryInfo *TLI,
0334 const DataLayout &DL,
0335 RangeTy *RangePtr = nullptr);
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348 bool getPotentiallyLoadedValues(
0349 Attributor &A, LoadInst &LI, SmallSetVector<Value *, 4> &PotentialValues,
0350 SmallSetVector<Instruction *, 4> &PotentialValueOrigins,
0351 const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
0352 bool OnlyExact = false);
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363 bool getPotentialCopiesOfStoredValue(
0364 Attributor &A, StoreInst &SI, SmallSetVector<Value *, 4> &PotentialCopies,
0365 const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
0366 bool OnlyExact = false);
0367
0368
0369
0370 bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP,
0371 const AbstractAttribute &QueryingAA, bool &IsKnown);
0372
0373
0374
0375 bool isAssumedReadNone(Attributor &A, const IRPosition &IRP,
0376 const AbstractAttribute &QueryingAA, bool &IsKnown);
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386 bool isPotentiallyReachable(
0387 Attributor &A, const Instruction &FromI, const Instruction &ToI,
0388 const AbstractAttribute &QueryingAA,
0389 const AA::InstExclusionSetTy *ExclusionSet = nullptr,
0390 std::function<bool(const Function &F)> GoBackwardsCB = nullptr);
0391
0392
0393 bool isPotentiallyReachable(
0394 Attributor &A, const Instruction &FromI, const Function &ToFn,
0395 const AbstractAttribute &QueryingAA,
0396 const AA::InstExclusionSetTy *ExclusionSet = nullptr,
0397 std::function<bool(const Function &F)> GoBackwardsCB = nullptr);
0398
0399
0400 bool isAssumedThreadLocalObject(Attributor &A, Value &Obj,
0401 const AbstractAttribute &QueryingAA);
0402
0403
0404 bool isPotentiallyAffectedByBarrier(Attributor &A, const Instruction &I,
0405 const AbstractAttribute &QueryingAA);
0406 bool isPotentiallyAffectedByBarrier(Attributor &A, ArrayRef<const Value *> Ptrs,
0407 const AbstractAttribute &QueryingAA,
0408 const Instruction *CtxI);
0409 }
0410
0411 template <>
0412 struct DenseMapInfo<AA::ValueAndContext>
0413 : public DenseMapInfo<AA::ValueAndContext::Base> {
0414 using Base = DenseMapInfo<AA::ValueAndContext::Base>;
0415 static inline AA::ValueAndContext getEmptyKey() {
0416 return Base::getEmptyKey();
0417 }
0418 static inline AA::ValueAndContext getTombstoneKey() {
0419 return Base::getTombstoneKey();
0420 }
0421 static unsigned getHashValue(const AA::ValueAndContext &VAC) {
0422 return Base::getHashValue(VAC);
0423 }
0424
0425 static bool isEqual(const AA::ValueAndContext &LHS,
0426 const AA::ValueAndContext &RHS) {
0427 return Base::isEqual(LHS, RHS);
0428 }
0429 };
0430
0431 template <>
0432 struct DenseMapInfo<AA::ValueScope> : public DenseMapInfo<unsigned char> {
0433 using Base = DenseMapInfo<unsigned char>;
0434 static inline AA::ValueScope getEmptyKey() {
0435 return AA::ValueScope(Base::getEmptyKey());
0436 }
0437 static inline AA::ValueScope getTombstoneKey() {
0438 return AA::ValueScope(Base::getTombstoneKey());
0439 }
0440 static unsigned getHashValue(const AA::ValueScope &S) {
0441 return Base::getHashValue(S);
0442 }
0443
0444 static bool isEqual(const AA::ValueScope &LHS, const AA::ValueScope &RHS) {
0445 return Base::isEqual(LHS, RHS);
0446 }
0447 };
0448
0449 template <>
0450 struct DenseMapInfo<const AA::InstExclusionSetTy *>
0451 : public DenseMapInfo<void *> {
0452 using super = DenseMapInfo<void *>;
0453 static inline const AA::InstExclusionSetTy *getEmptyKey() {
0454 return static_cast<const AA::InstExclusionSetTy *>(super::getEmptyKey());
0455 }
0456 static inline const AA::InstExclusionSetTy *getTombstoneKey() {
0457 return static_cast<const AA::InstExclusionSetTy *>(
0458 super::getTombstoneKey());
0459 }
0460 static unsigned getHashValue(const AA::InstExclusionSetTy *BES) {
0461 unsigned H = 0;
0462 if (BES)
0463 for (const auto *II : *BES)
0464 H += DenseMapInfo<const Instruction *>::getHashValue(II);
0465 return H;
0466 }
0467 static bool isEqual(const AA::InstExclusionSetTy *LHS,
0468 const AA::InstExclusionSetTy *RHS) {
0469 if (LHS == RHS)
0470 return true;
0471 if (LHS == getEmptyKey() || RHS == getEmptyKey() ||
0472 LHS == getTombstoneKey() || RHS == getTombstoneKey())
0473 return false;
0474 auto SizeLHS = LHS ? LHS->size() : 0;
0475 auto SizeRHS = RHS ? RHS->size() : 0;
0476 if (SizeLHS != SizeRHS)
0477 return false;
0478 if (SizeRHS == 0)
0479 return true;
0480 return llvm::set_is_subset(*LHS, *RHS);
0481 }
0482 };
0483
0484
0485
0486 extern unsigned MaxInitializationChainLength;
0487
0488
0489 enum class ChangeStatus {
0490 CHANGED,
0491 UNCHANGED,
0492 };
0493
0494 ChangeStatus operator|(ChangeStatus l, ChangeStatus r);
0495 ChangeStatus &operator|=(ChangeStatus &l, ChangeStatus r);
0496 ChangeStatus operator&(ChangeStatus l, ChangeStatus r);
0497 ChangeStatus &operator&=(ChangeStatus &l, ChangeStatus r);
0498
0499 enum class DepClassTy {
0500 REQUIRED,
0501 OPTIONAL,
0502 NONE,
0503 };
0504
0505
0506
0507 struct AADepGraphNode {
0508 public:
0509 virtual ~AADepGraphNode() = default;
0510 using DepTy = PointerIntPair<AADepGraphNode *, 1>;
0511 using DepSetTy = SmallSetVector<DepTy, 2>;
0512
0513 protected:
0514
0515
0516 DepSetTy Deps;
0517
0518 static AADepGraphNode *DepGetVal(const DepTy &DT) { return DT.getPointer(); }
0519 static AbstractAttribute *DepGetValAA(const DepTy &DT) {
0520 return cast<AbstractAttribute>(DT.getPointer());
0521 }
0522
0523 operator AbstractAttribute *() { return cast<AbstractAttribute>(this); }
0524
0525 public:
0526 using iterator = mapped_iterator<DepSetTy::iterator, decltype(&DepGetVal)>;
0527 using aaiterator =
0528 mapped_iterator<DepSetTy::iterator, decltype(&DepGetValAA)>;
0529
0530 aaiterator begin() { return aaiterator(Deps.begin(), &DepGetValAA); }
0531 aaiterator end() { return aaiterator(Deps.end(), &DepGetValAA); }
0532 iterator child_begin() { return iterator(Deps.begin(), &DepGetVal); }
0533 iterator child_end() { return iterator(Deps.end(), &DepGetVal); }
0534
0535 void print(raw_ostream &OS) const { print(nullptr, OS); }
0536 virtual void print(Attributor *, raw_ostream &OS) const {
0537 OS << "AADepNode Impl\n";
0538 }
0539 DepSetTy &getDeps() { return Deps; }
0540
0541 friend struct Attributor;
0542 friend struct AADepGraph;
0543 };
0544
0545
0546
0547
0548
0549
0550 struct AADepGraph {
0551 AADepGraph() = default;
0552 ~AADepGraph() = default;
0553
0554 using DepTy = AADepGraphNode::DepTy;
0555 static AADepGraphNode *DepGetVal(const DepTy &DT) { return DT.getPointer(); }
0556 using iterator =
0557 mapped_iterator<AADepGraphNode::DepSetTy::iterator, decltype(&DepGetVal)>;
0558
0559
0560
0561
0562 AADepGraphNode SyntheticRoot;
0563 AADepGraphNode *GetEntryNode() { return &SyntheticRoot; }
0564
0565 iterator begin() { return SyntheticRoot.child_begin(); }
0566 iterator end() { return SyntheticRoot.child_end(); }
0567
0568 void viewGraph();
0569
0570
0571 void dumpGraph();
0572
0573
0574 void print();
0575 };
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586 struct IRPosition {
0587
0588
0589 using CallBaseContext = CallBase;
0590
0591
0592 enum Kind : char {
0593 IRP_INVALID,
0594 IRP_FLOAT,
0595
0596 IRP_RETURNED,
0597 IRP_CALL_SITE_RETURNED,
0598 IRP_FUNCTION,
0599 IRP_CALL_SITE,
0600 IRP_ARGUMENT,
0601 IRP_CALL_SITE_ARGUMENT,
0602 };
0603
0604
0605
0606
0607 IRPosition() : Enc(nullptr, ENC_VALUE) { verify(); }
0608
0609
0610 static const IRPosition value(const Value &V,
0611 const CallBaseContext *CBContext = nullptr) {
0612 if (auto *Arg = dyn_cast<Argument>(&V))
0613 return IRPosition::argument(*Arg, CBContext);
0614 if (auto *CB = dyn_cast<CallBase>(&V))
0615 return IRPosition::callsite_returned(*CB);
0616 return IRPosition(const_cast<Value &>(V), IRP_FLOAT, CBContext);
0617 }
0618
0619
0620
0621
0622 static const IRPosition inst(const Instruction &I,
0623 const CallBaseContext *CBContext = nullptr) {
0624 return IRPosition(const_cast<Instruction &>(I), IRP_FLOAT, CBContext);
0625 }
0626
0627
0628
0629 static const IRPosition function(const Function &F,
0630 const CallBaseContext *CBContext = nullptr) {
0631 return IRPosition(const_cast<Function &>(F), IRP_FUNCTION, CBContext);
0632 }
0633
0634
0635
0636 static const IRPosition returned(const Function &F,
0637 const CallBaseContext *CBContext = nullptr) {
0638 return IRPosition(const_cast<Function &>(F), IRP_RETURNED, CBContext);
0639 }
0640
0641
0642
0643 static const IRPosition argument(const Argument &Arg,
0644 const CallBaseContext *CBContext = nullptr) {
0645 return IRPosition(const_cast<Argument &>(Arg), IRP_ARGUMENT, CBContext);
0646 }
0647
0648
0649 static const IRPosition callsite_function(const CallBase &CB) {
0650 return IRPosition(const_cast<CallBase &>(CB), IRP_CALL_SITE);
0651 }
0652
0653
0654 static const IRPosition callsite_returned(const CallBase &CB) {
0655 return IRPosition(const_cast<CallBase &>(CB), IRP_CALL_SITE_RETURNED);
0656 }
0657
0658
0659 static const IRPosition callsite_argument(const CallBase &CB,
0660 unsigned ArgNo) {
0661 return IRPosition(const_cast<Use &>(CB.getArgOperandUse(ArgNo)),
0662 IRP_CALL_SITE_ARGUMENT);
0663 }
0664
0665
0666 static const IRPosition callsite_argument(AbstractCallSite ACS,
0667 unsigned ArgNo) {
0668 if (ACS.getNumArgOperands() <= ArgNo)
0669 return IRPosition();
0670 int CSArgNo = ACS.getCallArgOperandNo(ArgNo);
0671 if (CSArgNo >= 0)
0672 return IRPosition::callsite_argument(
0673 cast<CallBase>(*ACS.getInstruction()), CSArgNo);
0674 return IRPosition();
0675 }
0676
0677
0678
0679
0680
0681 static const IRPosition
0682 function_scope(const IRPosition &IRP,
0683 const CallBaseContext *CBContext = nullptr) {
0684 if (IRP.isAnyCallSitePosition()) {
0685 return IRPosition::callsite_function(
0686 cast<CallBase>(IRP.getAnchorValue()));
0687 }
0688 assert(IRP.getAssociatedFunction());
0689 return IRPosition::function(*IRP.getAssociatedFunction(), CBContext);
0690 }
0691
0692 bool operator==(const IRPosition &RHS) const {
0693 return Enc == RHS.Enc && RHS.CBContext == CBContext;
0694 }
0695 bool operator!=(const IRPosition &RHS) const { return !(*this == RHS); }
0696
0697
0698
0699
0700
0701
0702
0703 Value &getAnchorValue() const {
0704 switch (getEncodingBits()) {
0705 case ENC_VALUE:
0706 case ENC_RETURNED_VALUE:
0707 case ENC_FLOATING_FUNCTION:
0708 return *getAsValuePtr();
0709 case ENC_CALL_SITE_ARGUMENT_USE:
0710 return *(getAsUsePtr()->getUser());
0711 default:
0712 llvm_unreachable("Unkown encoding!");
0713 };
0714 }
0715
0716
0717 Function *getAssociatedFunction() const {
0718 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue())) {
0719
0720
0721
0722 if (Argument *Arg = getAssociatedArgument())
0723 return Arg->getParent();
0724 return dyn_cast_if_present<Function>(
0725 CB->getCalledOperand()->stripPointerCasts());
0726 }
0727 return getAnchorScope();
0728 }
0729
0730
0731 Argument *getAssociatedArgument() const;
0732
0733
0734
0735 bool isFnInterfaceKind() const {
0736 switch (getPositionKind()) {
0737 case IRPosition::IRP_FUNCTION:
0738 case IRPosition::IRP_RETURNED:
0739 case IRPosition::IRP_ARGUMENT:
0740 return true;
0741 default:
0742 return false;
0743 }
0744 }
0745
0746
0747 bool isFunctionScope() const {
0748 switch (getPositionKind()) {
0749 case IRPosition::IRP_CALL_SITE:
0750 case IRPosition::IRP_FUNCTION:
0751 return true;
0752 default:
0753 return false;
0754 };
0755 }
0756
0757
0758 Function *getAnchorScope() const {
0759 Value &V = getAnchorValue();
0760 if (isa<Function>(V))
0761 return &cast<Function>(V);
0762 if (isa<Argument>(V))
0763 return cast<Argument>(V).getParent();
0764 if (isa<Instruction>(V))
0765 return cast<Instruction>(V).getFunction();
0766 return nullptr;
0767 }
0768
0769
0770 Instruction *getCtxI() const {
0771 Value &V = getAnchorValue();
0772 if (auto *I = dyn_cast<Instruction>(&V))
0773 return I;
0774 if (auto *Arg = dyn_cast<Argument>(&V))
0775 if (!Arg->getParent()->isDeclaration())
0776 return &Arg->getParent()->getEntryBlock().front();
0777 if (auto *F = dyn_cast<Function>(&V))
0778 if (!F->isDeclaration())
0779 return &(F->getEntryBlock().front());
0780 return nullptr;
0781 }
0782
0783
0784 Value &getAssociatedValue() const {
0785 if (getCallSiteArgNo() < 0 || isa<Argument>(&getAnchorValue()))
0786 return getAnchorValue();
0787 assert(isa<CallBase>(&getAnchorValue()) && "Expected a call base!");
0788 return *cast<CallBase>(&getAnchorValue())
0789 ->getArgOperand(getCallSiteArgNo());
0790 }
0791
0792
0793 Type *getAssociatedType() const {
0794 if (getPositionKind() == IRPosition::IRP_RETURNED)
0795 return getAssociatedFunction()->getReturnType();
0796 return getAssociatedValue().getType();
0797 }
0798
0799
0800
0801
0802
0803
0804 int getCalleeArgNo() const {
0805 return getArgNo( true);
0806 }
0807
0808
0809
0810
0811
0812
0813 int getCallSiteArgNo() const {
0814 return getArgNo( false);
0815 }
0816
0817
0818 unsigned getAttrIdx() const {
0819 switch (getPositionKind()) {
0820 case IRPosition::IRP_INVALID:
0821 case IRPosition::IRP_FLOAT:
0822 break;
0823 case IRPosition::IRP_FUNCTION:
0824 case IRPosition::IRP_CALL_SITE:
0825 return AttributeList::FunctionIndex;
0826 case IRPosition::IRP_RETURNED:
0827 case IRPosition::IRP_CALL_SITE_RETURNED:
0828 return AttributeList::ReturnIndex;
0829 case IRPosition::IRP_ARGUMENT:
0830 return getCalleeArgNo() + AttributeList::FirstArgIndex;
0831 case IRPosition::IRP_CALL_SITE_ARGUMENT:
0832 return getCallSiteArgNo() + AttributeList::FirstArgIndex;
0833 }
0834 llvm_unreachable(
0835 "There is no attribute index for a floating or invalid position!");
0836 }
0837
0838
0839 Value *getAttrListAnchor() const {
0840 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue()))
0841 return CB;
0842 return getAssociatedFunction();
0843 }
0844
0845
0846 AttributeList getAttrList() const {
0847 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue()))
0848 return CB->getAttributes();
0849 return getAssociatedFunction()->getAttributes();
0850 }
0851
0852
0853 void setAttrList(const AttributeList &AttrList) const {
0854 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue()))
0855 return CB->setAttributes(AttrList);
0856 return getAssociatedFunction()->setAttributes(AttrList);
0857 }
0858
0859
0860
0861 unsigned getNumArgs() const {
0862 assert((getPositionKind() == IRP_CALL_SITE ||
0863 getPositionKind() == IRP_FUNCTION) &&
0864 "Only valid for function/call site positions!");
0865 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue()))
0866 return CB->arg_size();
0867 return getAssociatedFunction()->arg_size();
0868 }
0869
0870
0871
0872 Value *getArg(unsigned ArgNo) const {
0873 assert((getPositionKind() == IRP_CALL_SITE ||
0874 getPositionKind() == IRP_FUNCTION) &&
0875 "Only valid for function/call site positions!");
0876 if (auto *CB = dyn_cast<CallBase>(&getAnchorValue()))
0877 return CB->getArgOperand(ArgNo);
0878 return getAssociatedFunction()->getArg(ArgNo);
0879 }
0880
0881
0882 Kind getPositionKind() const {
0883 char EncodingBits = getEncodingBits();
0884 if (EncodingBits == ENC_CALL_SITE_ARGUMENT_USE)
0885 return IRP_CALL_SITE_ARGUMENT;
0886 if (EncodingBits == ENC_FLOATING_FUNCTION)
0887 return IRP_FLOAT;
0888
0889 Value *V = getAsValuePtr();
0890 if (!V)
0891 return IRP_INVALID;
0892 if (isa<Argument>(V))
0893 return IRP_ARGUMENT;
0894 if (isa<Function>(V))
0895 return isReturnPosition(EncodingBits) ? IRP_RETURNED : IRP_FUNCTION;
0896 if (isa<CallBase>(V))
0897 return isReturnPosition(EncodingBits) ? IRP_CALL_SITE_RETURNED
0898 : IRP_CALL_SITE;
0899 return IRP_FLOAT;
0900 }
0901
0902 bool isAnyCallSitePosition() const {
0903 switch (getPositionKind()) {
0904 case IRPosition::IRP_CALL_SITE:
0905 case IRPosition::IRP_CALL_SITE_RETURNED:
0906 case IRPosition::IRP_CALL_SITE_ARGUMENT:
0907 return true;
0908 default:
0909 return false;
0910 }
0911 }
0912
0913
0914 bool isArgumentPosition() const {
0915 switch (getPositionKind()) {
0916 case IRPosition::IRP_ARGUMENT:
0917 case IRPosition::IRP_CALL_SITE_ARGUMENT:
0918 return true;
0919 default:
0920 return false;
0921 }
0922 }
0923
0924
0925 IRPosition stripCallBaseContext() const {
0926 IRPosition Result = *this;
0927 Result.CBContext = nullptr;
0928 return Result;
0929 }
0930
0931
0932 const CallBaseContext *getCallBaseContext() const { return CBContext; }
0933
0934
0935 bool hasCallBaseContext() const { return CBContext != nullptr; }
0936
0937
0938
0939
0940 static const IRPosition EmptyKey;
0941 static const IRPosition TombstoneKey;
0942
0943
0944
0945 operator void *() const { return Enc.getOpaqueValue(); }
0946
0947 private:
0948
0949 explicit IRPosition(void *Ptr, const CallBaseContext *CBContext = nullptr)
0950 : CBContext(CBContext) {
0951 Enc.setFromOpaqueValue(Ptr);
0952 }
0953
0954
0955 explicit IRPosition(Value &AnchorVal, Kind PK,
0956 const CallBaseContext *CBContext = nullptr)
0957 : CBContext(CBContext) {
0958 switch (PK) {
0959 case IRPosition::IRP_INVALID:
0960 llvm_unreachable("Cannot create invalid IRP with an anchor value!");
0961 break;
0962 case IRPosition::IRP_FLOAT:
0963
0964 if (isa<Function>(AnchorVal) || isa<CallBase>(AnchorVal))
0965 Enc = {&AnchorVal, ENC_FLOATING_FUNCTION};
0966 else
0967 Enc = {&AnchorVal, ENC_VALUE};
0968 break;
0969 case IRPosition::IRP_FUNCTION:
0970 case IRPosition::IRP_CALL_SITE:
0971 Enc = {&AnchorVal, ENC_VALUE};
0972 break;
0973 case IRPosition::IRP_RETURNED:
0974 case IRPosition::IRP_CALL_SITE_RETURNED:
0975 Enc = {&AnchorVal, ENC_RETURNED_VALUE};
0976 break;
0977 case IRPosition::IRP_ARGUMENT:
0978 Enc = {&AnchorVal, ENC_VALUE};
0979 break;
0980 case IRPosition::IRP_CALL_SITE_ARGUMENT:
0981 llvm_unreachable(
0982 "Cannot create call site argument IRP with an anchor value!");
0983 break;
0984 }
0985 verify();
0986 }
0987
0988
0989
0990
0991 int getArgNo(bool CallbackCalleeArgIfApplicable) const {
0992 if (CallbackCalleeArgIfApplicable)
0993 if (Argument *Arg = getAssociatedArgument())
0994 return Arg->getArgNo();
0995 switch (getPositionKind()) {
0996 case IRPosition::IRP_ARGUMENT:
0997 return cast<Argument>(getAsValuePtr())->getArgNo();
0998 case IRPosition::IRP_CALL_SITE_ARGUMENT: {
0999 Use &U = *getAsUsePtr();
1000 return cast<CallBase>(U.getUser())->getArgOperandNo(&U);
1001 }
1002 default:
1003 return -1;
1004 }
1005 }
1006
1007
1008
1009
1010 explicit IRPosition(Use &U, Kind PK) {
1011 assert(PK == IRP_CALL_SITE_ARGUMENT &&
1012 "Use constructor is for call site arguments only!");
1013 Enc = {&U, ENC_CALL_SITE_ARGUMENT_USE};
1014 verify();
1015 }
1016
1017
1018 void verify();
1019
1020
1021
1022 Value *getAsValuePtr() const {
1023 assert(getEncodingBits() != ENC_CALL_SITE_ARGUMENT_USE &&
1024 "Not a value pointer!");
1025 return reinterpret_cast<Value *>(Enc.getPointer());
1026 }
1027
1028
1029
1030 Use *getAsUsePtr() const {
1031 assert(getEncodingBits() == ENC_CALL_SITE_ARGUMENT_USE &&
1032 "Not a value pointer!");
1033 return reinterpret_cast<Use *>(Enc.getPointer());
1034 }
1035
1036
1037
1038 static bool isReturnPosition(char EncodingBits) {
1039 return EncodingBits == ENC_RETURNED_VALUE;
1040 }
1041
1042
1043
1044 bool isReturnPosition() const { return isReturnPosition(getEncodingBits()); }
1045
1046
1047
1048
1049
1050
1051
1052 enum {
1053 ENC_VALUE = 0b00,
1054 ENC_RETURNED_VALUE = 0b01,
1055 ENC_FLOATING_FUNCTION = 0b10,
1056 ENC_CALL_SITE_ARGUMENT_USE = 0b11,
1057 };
1058
1059
1060
1061 static constexpr int NumEncodingBits =
1062 PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1063 static_assert(NumEncodingBits >= 2, "At least two bits are required!");
1064
1065
1066 PointerIntPair<void *, NumEncodingBits, char> Enc;
1067
1068
1069
1070 const CallBaseContext *CBContext = nullptr;
1071
1072
1073 char getEncodingBits() const { return Enc.getInt(); }
1074 };
1075
1076
1077 template <> struct DenseMapInfo<IRPosition> {
1078 static inline IRPosition getEmptyKey() { return IRPosition::EmptyKey; }
1079 static inline IRPosition getTombstoneKey() {
1080 return IRPosition::TombstoneKey;
1081 }
1082 static unsigned getHashValue(const IRPosition &IRP) {
1083 return (DenseMapInfo<void *>::getHashValue(IRP) << 4) ^
1084 (DenseMapInfo<Value *>::getHashValue(IRP.getCallBaseContext()));
1085 }
1086
1087 static bool isEqual(const IRPosition &a, const IRPosition &b) {
1088 return a == b;
1089 }
1090 };
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 class SubsumingPositionIterator {
1117 SmallVector<IRPosition, 4> IRPositions;
1118 using iterator = decltype(IRPositions)::iterator;
1119
1120 public:
1121 SubsumingPositionIterator(const IRPosition &IRP);
1122 iterator begin() { return IRPositions.begin(); }
1123 iterator end() { return IRPositions.end(); }
1124 };
1125
1126
1127 struct AnalysisGetter {
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139 template <typename, typename = void>
1140 static constexpr bool HasLegacyWrapper = false;
1141
1142 template <typename Analysis>
1143 typename Analysis::Result *getAnalysis(const Function &F,
1144 bool RequestCachedOnly = false) {
1145 if (!LegacyPass && !FAM)
1146 return nullptr;
1147 if (FAM) {
1148 if (CachedOnly || RequestCachedOnly)
1149 return FAM->getCachedResult<Analysis>(const_cast<Function &>(F));
1150 return &FAM->getResult<Analysis>(const_cast<Function &>(F));
1151 }
1152 if constexpr (HasLegacyWrapper<Analysis>) {
1153 if (!CachedOnly && !RequestCachedOnly)
1154 return &LegacyPass
1155 ->getAnalysis<typename Analysis::LegacyWrapper>(
1156 const_cast<Function &>(F))
1157 .getResult();
1158 if (auto *P =
1159 LegacyPass
1160 ->getAnalysisIfAvailable<typename Analysis::LegacyWrapper>())
1161 return &P->getResult();
1162 }
1163 return nullptr;
1164 }
1165
1166
1167 void invalidateAnalyses() {
1168 assert(FAM && "Can only be used from the new PM!");
1169 FAM->clear();
1170 }
1171
1172 AnalysisGetter(FunctionAnalysisManager &FAM, bool CachedOnly = false)
1173 : FAM(&FAM), CachedOnly(CachedOnly) {}
1174 AnalysisGetter(Pass *P, bool CachedOnly = false)
1175 : LegacyPass(P), CachedOnly(CachedOnly) {}
1176 AnalysisGetter() = default;
1177
1178 private:
1179 FunctionAnalysisManager *FAM = nullptr;
1180 Pass *LegacyPass = nullptr;
1181
1182
1183
1184 bool CachedOnly = false;
1185 };
1186
1187 template <typename Analysis>
1188 constexpr bool AnalysisGetter::HasLegacyWrapper<
1189 Analysis, std::void_t<typename Analysis::LegacyWrapper>> = true;
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203 struct InformationCache {
1204 InformationCache(const Module &M, AnalysisGetter &AG,
1205 BumpPtrAllocator &Allocator, SetVector<Function *> *CGSCC,
1206 bool UseExplorer = true)
1207 : CGSCC(CGSCC), DL(M.getDataLayout()), Allocator(Allocator), AG(AG),
1208 TargetTriple(M.getTargetTriple()) {
1209 if (UseExplorer)
1210 Explorer = new (Allocator) MustBeExecutedContextExplorer(
1211 true, true,
1212 true,
1213
1214 [&](const Function &F) { return AG.getAnalysis<LoopAnalysis>(F); },
1215
1216 [&](const Function &F) {
1217 return AG.getAnalysis<DominatorTreeAnalysis>(F);
1218 },
1219
1220 [&](const Function &F) {
1221 return AG.getAnalysis<PostDominatorTreeAnalysis>(F);
1222 });
1223 }
1224
1225 ~InformationCache() {
1226
1227
1228 for (auto &It : FuncInfoMap)
1229 It.getSecond()->~FunctionInfo();
1230
1231 using AA::InstExclusionSetTy;
1232 for (auto *BES : BESets)
1233 BES->~InstExclusionSetTy();
1234 if (Explorer)
1235 Explorer->~MustBeExecutedContextExplorer();
1236 }
1237
1238
1239
1240
1241 template <typename CBTy>
1242 static void foreachUse(Function &F, CBTy CB,
1243 bool LookThroughConstantExprUses = true) {
1244 SmallVector<Use *, 8> Worklist(make_pointer_range(F.uses()));
1245
1246 for (unsigned Idx = 0; Idx < Worklist.size(); ++Idx) {
1247 Use &U = *Worklist[Idx];
1248
1249
1250 if (LookThroughConstantExprUses && isa<ConstantExpr>(U.getUser())) {
1251 for (Use &CEU : cast<ConstantExpr>(U.getUser())->uses())
1252 Worklist.push_back(&CEU);
1253 continue;
1254 }
1255
1256 CB(U);
1257 }
1258 }
1259
1260
1261 const SetVector<Function *> *const CGSCC = nullptr;
1262
1263
1264 using InstructionVectorTy = SmallVector<Instruction *, 8>;
1265
1266
1267 using OpcodeInstMapTy = DenseMap<unsigned, InstructionVectorTy *>;
1268
1269
1270
1271 OpcodeInstMapTy &getOpcodeInstMapForFunction(const Function &F) {
1272 return getFunctionInfo(F).OpcodeInstMap;
1273 }
1274
1275
1276 InstructionVectorTy &getReadOrWriteInstsForFunction(const Function &F) {
1277 return getFunctionInfo(F).RWInsts;
1278 }
1279
1280
1281 MustBeExecutedContextExplorer *getMustBeExecutedContextExplorer() {
1282 return Explorer;
1283 }
1284
1285
1286 TargetLibraryInfo *getTargetLibraryInfoForFunction(const Function &F) {
1287 return AG.getAnalysis<TargetLibraryAnalysis>(F);
1288 }
1289
1290
1291 bool isKernel(const Function &F) {
1292 FunctionInfo &FI = getFunctionInfo(F);
1293 return FI.IsKernel;
1294 }
1295
1296
1297
1298 bool isInvolvedInMustTailCall(const Argument &Arg) {
1299 FunctionInfo &FI = getFunctionInfo(*Arg.getParent());
1300 return FI.CalledViaMustTail || FI.ContainsMustTailCall;
1301 }
1302
1303 bool isOnlyUsedByAssume(const Instruction &I) const {
1304 return AssumeOnlyValues.contains(&I);
1305 }
1306
1307
1308
1309 void invalidateAnalyses() { AG.invalidateAnalyses(); }
1310
1311
1312 template <typename AP>
1313 typename AP::Result *getAnalysisResultForFunction(const Function &F,
1314 bool CachedOnly = false) {
1315 return AG.getAnalysis<AP>(F, CachedOnly);
1316 }
1317
1318
1319 const DataLayout &getDL() { return DL; }
1320
1321
1322 const RetainedKnowledgeMap &getKnowledgeMap() const { return KnowledgeMap; }
1323
1324
1325 const AA::InstExclusionSetTy *
1326 getOrCreateUniqueBlockExecutionSet(const AA::InstExclusionSetTy *BES) {
1327 auto It = BESets.find(BES);
1328 if (It != BESets.end())
1329 return *It;
1330 auto *UniqueBES = new (Allocator) AA::InstExclusionSetTy(*BES);
1331 bool Success = BESets.insert(UniqueBES).second;
1332 (void)Success;
1333 assert(Success && "Expected only new entries to be added");
1334 return UniqueBES;
1335 }
1336
1337
1338 bool stackIsAccessibleByOtherThreads() { return !targetIsGPU(); }
1339
1340
1341 bool targetIsGPU() {
1342 return TargetTriple.isAMDGPU() || TargetTriple.isNVPTX();
1343 }
1344
1345
1346
1347 const ArrayRef<Function *>
1348 getIndirectlyCallableFunctions(Attributor &A) const;
1349
1350
1351 std::optional<unsigned> getFlatAddressSpace() const;
1352
1353 private:
1354 struct FunctionInfo {
1355 ~FunctionInfo();
1356
1357
1358
1359 OpcodeInstMapTy OpcodeInstMap;
1360
1361
1362
1363 InstructionVectorTy RWInsts;
1364
1365
1366 bool CalledViaMustTail;
1367
1368
1369 bool ContainsMustTailCall;
1370
1371
1372 bool IsKernel;
1373 };
1374
1375
1376 DenseMap<const Function *, FunctionInfo *> FuncInfoMap;
1377
1378
1379 FunctionInfo &getFunctionInfo(const Function &F) {
1380 FunctionInfo *&FI = FuncInfoMap[&F];
1381 if (!FI) {
1382 FI = new (Allocator) FunctionInfo();
1383 initializeInformationCache(F, *FI);
1384 }
1385 return *FI;
1386 }
1387
1388
1389
1390 SmallVector<Function *> IndirectlyCallableFunctions;
1391
1392
1393
1394
1395
1396 void initializeInformationCache(const Function &F, FunctionInfo &FI);
1397
1398
1399 const DataLayout &DL;
1400
1401
1402 BumpPtrAllocator &Allocator;
1403
1404
1405 MustBeExecutedContextExplorer *Explorer = nullptr;
1406
1407
1408 RetainedKnowledgeMap KnowledgeMap;
1409
1410
1411 SetVector<const Instruction *> AssumeOnlyValues;
1412
1413
1414 DenseSet<const AA::InstExclusionSetTy *> BESets;
1415
1416
1417 AnalysisGetter &AG;
1418
1419
1420 SmallPtrSet<const Function *, 8> InlineableFunctions;
1421
1422
1423 Triple TargetTriple;
1424
1425
1426
1427 friend struct Attributor;
1428 };
1429
1430
1431 struct AttributorConfig {
1432
1433 AttributorConfig(CallGraphUpdater &CGUpdater) : CGUpdater(CGUpdater) {}
1434
1435
1436
1437
1438
1439
1440
1441
1442 bool IsModulePass = true;
1443
1444
1445 bool DeleteFns = true;
1446
1447
1448 bool RewriteSignatures = true;
1449
1450
1451
1452 bool DefaultInitializeLiveInternals = true;
1453
1454
1455 bool UseLiveness = true;
1456
1457
1458
1459 bool IsClosedWorldModule = false;
1460
1461
1462 std::function<void(Attributor &A, const Function &F)> InitializationCallback =
1463 nullptr;
1464
1465
1466
1467 std::function<bool(Attributor &A, const AbstractAttribute &AA, CallBase &CB,
1468 Function &AssumedCallee, unsigned NumAssumedCallees)>
1469 IndirectCalleeSpecializationCallback = nullptr;
1470
1471
1472 CallGraphUpdater &CGUpdater;
1473
1474
1475 DenseSet<const char *> *Allowed = nullptr;
1476
1477
1478 std::optional<unsigned> MaxFixpointIterations;
1479
1480
1481
1482 using OptimizationRemarkGetter =
1483 function_ref<OptimizationRemarkEmitter &(Function *)>;
1484 OptimizationRemarkGetter OREGetter = nullptr;
1485
1486
1487
1488 const char *PassName = nullptr;
1489
1490 using IPOAmendableCBTy = std::function<bool(const Function &F)>;
1491 IPOAmendableCBTy IPOAmendableCB;
1492 };
1493
1494
1495 DEBUG_COUNTER(NumAbstractAttributes, "num-abstract-attributes",
1496 "How many AAs should be initialized");
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525 struct Attributor {
1526
1527
1528
1529
1530
1531
1532
1533
1534 Attributor(SetVector<Function *> &Functions, InformationCache &InfoCache,
1535 AttributorConfig Configuration);
1536
1537 ~Attributor();
1538
1539
1540
1541
1542
1543
1544
1545 ChangeStatus run();
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567 template <typename AAType>
1568 const AAType *getAAFor(const AbstractAttribute &QueryingAA,
1569 const IRPosition &IRP, DepClassTy DepClass) {
1570 return getOrCreateAAFor<AAType>(IRP, &QueryingAA, DepClass,
1571 false);
1572 }
1573
1574
1575
1576
1577
1578
1579 template <typename AAType>
1580 const AAType *getOrCreateAAFor(IRPosition IRP,
1581 const AbstractAttribute *QueryingAA,
1582 DepClassTy DepClass, bool ForceUpdate = false,
1583 bool UpdateAfterInit = true) {
1584 if (!shouldPropagateCallBaseContext(IRP))
1585 IRP = IRP.stripCallBaseContext();
1586
1587 if (AAType *AAPtr = lookupAAFor<AAType>(IRP, QueryingAA, DepClass,
1588 true)) {
1589 if (ForceUpdate && Phase == AttributorPhase::UPDATE)
1590 updateAA(*AAPtr);
1591 return AAPtr;
1592 }
1593
1594 bool ShouldUpdateAA;
1595 if (!shouldInitialize<AAType>(IRP, ShouldUpdateAA))
1596 return nullptr;
1597
1598 if (!DebugCounter::shouldExecute(NumAbstractAttributes))
1599 return nullptr;
1600
1601
1602
1603 auto &AA = AAType::createForPosition(IRP, *this);
1604
1605
1606
1607 registerAA(AA);
1608
1609
1610 if (Phase == AttributorPhase::SEEDING && !shouldSeedAttribute(AA)) {
1611 AA.getState().indicatePessimisticFixpoint();
1612 return &AA;
1613 }
1614
1615
1616
1617 {
1618 TimeTraceScope TimeScope("initialize", [&]() {
1619 return AA.getName() +
1620 std::to_string(AA.getIRPosition().getPositionKind());
1621 });
1622 ++InitializationChainLength;
1623 AA.initialize(*this);
1624 --InitializationChainLength;
1625 }
1626
1627 if (!ShouldUpdateAA) {
1628 AA.getState().indicatePessimisticFixpoint();
1629 return &AA;
1630 }
1631
1632
1633
1634 if (UpdateAfterInit) {
1635 AttributorPhase OldPhase = Phase;
1636 Phase = AttributorPhase::UPDATE;
1637
1638 updateAA(AA);
1639
1640 Phase = OldPhase;
1641 }
1642
1643 if (QueryingAA && AA.getState().isValidState())
1644 recordDependence(AA, const_cast<AbstractAttribute &>(*QueryingAA),
1645 DepClass);
1646 return &AA;
1647 }
1648
1649 template <typename AAType>
1650 const AAType *getOrCreateAAFor(const IRPosition &IRP) {
1651 return getOrCreateAAFor<AAType>(IRP, nullptr,
1652 DepClassTy::NONE);
1653 }
1654
1655
1656
1657 template <typename AAType>
1658 AAType *lookupAAFor(const IRPosition &IRP,
1659 const AbstractAttribute *QueryingAA = nullptr,
1660 DepClassTy DepClass = DepClassTy::OPTIONAL,
1661 bool AllowInvalidState = false) {
1662 static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
1663 "Cannot query an attribute with a type not derived from "
1664 "'AbstractAttribute'!");
1665
1666
1667 AbstractAttribute *AAPtr = AAMap.lookup({&AAType::ID, IRP});
1668 if (!AAPtr)
1669 return nullptr;
1670
1671 AAType *AA = static_cast<AAType *>(AAPtr);
1672
1673
1674 if (DepClass != DepClassTy::NONE && QueryingAA &&
1675 AA->getState().isValidState())
1676 recordDependence(*AA, const_cast<AbstractAttribute &>(*QueryingAA),
1677 DepClass);
1678
1679
1680 if (!AllowInvalidState && !AA->getState().isValidState())
1681 return nullptr;
1682 return AA;
1683 }
1684
1685
1686 void registerForUpdate(AbstractAttribute &AA);
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699 void recordDependence(const AbstractAttribute &FromAA,
1700 const AbstractAttribute &ToAA, DepClassTy DepClass);
1701
1702
1703
1704
1705
1706
1707
1708
1709 template <typename AAType> AAType ®isterAA(AAType &AA) {
1710 static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
1711 "Cannot register an attribute with a type not derived from "
1712 "'AbstractAttribute'!");
1713
1714
1715 const IRPosition &IRP = AA.getIRPosition();
1716 AbstractAttribute *&AAPtr = AAMap[{&AAType::ID, IRP}];
1717
1718 assert(!AAPtr && "Attribute already in map!");
1719 AAPtr = &AA;
1720
1721
1722 if (Phase == AttributorPhase::SEEDING || Phase == AttributorPhase::UPDATE)
1723 DG.SyntheticRoot.Deps.insert(
1724 AADepGraphNode::DepTy(&AA, unsigned(DepClassTy::REQUIRED)));
1725
1726 return AA;
1727 }
1728
1729
1730 InformationCache &getInfoCache() { return InfoCache; }
1731
1732
1733 bool isModulePass() const { return Configuration.IsModulePass; }
1734
1735
1736
1737 bool shouldSpecializeCallSiteForCallee(const AbstractAttribute &AA,
1738 CallBase &CB, Function &Callee,
1739 unsigned NumAssumedCallees) {
1740 return Configuration.IndirectCalleeSpecializationCallback
1741 ? Configuration.IndirectCalleeSpecializationCallback(
1742 *this, AA, CB, Callee, NumAssumedCallees)
1743 : true;
1744 }
1745
1746
1747
1748 bool isClosedWorldModule() const;
1749
1750
1751 bool isRunOn(Function &Fn) const { return isRunOn(&Fn); }
1752 bool isRunOn(Function *Fn) const {
1753 return Functions.empty() || Functions.count(Fn);
1754 }
1755
1756 template <typename AAType> bool shouldUpdateAA(const IRPosition &IRP) {
1757
1758
1759 if (Phase == AttributorPhase::MANIFEST || Phase == AttributorPhase::CLEANUP)
1760 return false;
1761
1762 Function *AssociatedFn = IRP.getAssociatedFunction();
1763
1764 if (IRP.isAnyCallSitePosition()) {
1765
1766 if (!AssociatedFn && AAType::requiresCalleeForCallBase())
1767 return false;
1768
1769
1770 if (AAType::requiresNonAsmForCallBase() &&
1771 cast<CallBase>(IRP.getAnchorValue()).isInlineAsm())
1772 return false;
1773 }
1774
1775
1776 if (AAType::requiresCallersForArgOrFunction())
1777 if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION ||
1778 IRP.getPositionKind() == IRPosition::IRP_ARGUMENT)
1779 if (!AssociatedFn->hasLocalLinkage())
1780 return false;
1781
1782 if (!AAType::isValidIRPositionForUpdate(*this, IRP))
1783 return false;
1784
1785
1786
1787 return (!AssociatedFn || isModulePass() || isRunOn(AssociatedFn) ||
1788 isRunOn(IRP.getAnchorScope()));
1789 }
1790
1791 template <typename AAType>
1792 bool shouldInitialize(const IRPosition &IRP, bool &ShouldUpdateAA) {
1793 if (!AAType::isValidIRPositionForInit(*this, IRP))
1794 return false;
1795
1796 if (Configuration.Allowed && !Configuration.Allowed->count(&AAType::ID))
1797 return false;
1798
1799
1800 const Function *AnchorFn = IRP.getAnchorScope();
1801 if (AnchorFn && (AnchorFn->hasFnAttribute(Attribute::Naked) ||
1802 AnchorFn->hasFnAttribute(Attribute::OptimizeNone)))
1803 return false;
1804
1805
1806 if (InitializationChainLength > MaxInitializationChainLength)
1807 return false;
1808
1809 ShouldUpdateAA = shouldUpdateAA<AAType>(IRP);
1810
1811 return !AAType::hasTrivialInitializer() || ShouldUpdateAA;
1812 }
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824 void identifyDefaultAbstractAttributes(Function &F);
1825
1826
1827
1828
1829
1830 bool isFunctionIPOAmendable(const Function &F) {
1831 return F.hasExactDefinition() || InfoCache.InlineableFunctions.count(&F) ||
1832 (Configuration.IPOAmendableCB && Configuration.IPOAmendableCB(F));
1833 }
1834
1835
1836
1837
1838
1839 void markLiveInternalFunction(const Function &F) {
1840 assert(F.hasLocalLinkage() &&
1841 "Only local linkage is assumed dead initially.");
1842
1843 if (Configuration.DefaultInitializeLiveInternals)
1844 identifyDefaultAbstractAttributes(const_cast<Function &>(F));
1845 if (Configuration.InitializationCallback)
1846 Configuration.InitializationCallback(*this, F);
1847 }
1848
1849
1850
1851 bool changeUseAfterManifest(Use &U, Value &NV) {
1852 Value *&V = ToBeChangedUses[&U];
1853 if (V && (V->stripPointerCasts() == NV.stripPointerCasts() ||
1854 isa_and_nonnull<UndefValue>(V)))
1855 return false;
1856 assert((!V || V == &NV || isa<UndefValue>(NV)) &&
1857 "Use was registered twice for replacement with different values!");
1858 V = &NV;
1859 return true;
1860 }
1861
1862
1863
1864
1865 bool changeAfterManifest(const IRPosition IRP, Value &NV,
1866 bool ChangeDroppable = true) {
1867 if (IRP.getPositionKind() == IRPosition::IRP_CALL_SITE_ARGUMENT) {
1868 auto *CB = cast<CallBase>(IRP.getCtxI());
1869 return changeUseAfterManifest(
1870 CB->getArgOperandUse(IRP.getCallSiteArgNo()), NV);
1871 }
1872 Value &V = IRP.getAssociatedValue();
1873 auto &Entry = ToBeChangedValues[&V];
1874 Value *CurNV = get<0>(Entry);
1875 if (CurNV && (CurNV->stripPointerCasts() == NV.stripPointerCasts() ||
1876 isa<UndefValue>(CurNV)))
1877 return false;
1878 assert((!CurNV || CurNV == &NV || isa<UndefValue>(NV)) &&
1879 "Value replacement was registered twice with different values!");
1880 Entry = {&NV, ChangeDroppable};
1881 return true;
1882 }
1883
1884
1885
1886 void changeToUnreachableAfterManifest(Instruction *I) {
1887 ToBeChangedToUnreachableInsts.insert(I);
1888 }
1889
1890
1891
1892
1893 void registerInvokeWithDeadSuccessor(InvokeInst &II) {
1894 InvokeWithDeadSuccessor.insert(&II);
1895 }
1896
1897
1898
1899 void deleteAfterManifest(Instruction &I) { ToBeDeletedInsts.insert(&I); }
1900
1901
1902
1903 void deleteAfterManifest(BasicBlock &BB) { ToBeDeletedBlocks.insert(&BB); }
1904
1905
1906
1907 void registerManifestAddedBasicBlock(BasicBlock &BB) {
1908 ManifestAddedBlocks.insert(&BB);
1909 }
1910
1911
1912 void deleteAfterManifest(Function &F) {
1913 if (Configuration.DeleteFns)
1914 ToBeDeletedFunctions.insert(&F);
1915 }
1916
1917
1918
1919 bool getAttrsFromAssumes(const IRPosition &IRP, Attribute::AttrKind AK,
1920 SmallVectorImpl<Attribute> &Attrs);
1921
1922
1923
1924
1925
1926
1927 bool hasAttr(const IRPosition &IRP, ArrayRef<Attribute::AttrKind> AKs,
1928 bool IgnoreSubsumingPositions = false,
1929 Attribute::AttrKind ImpliedAttributeKind = Attribute::None);
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939 void getAttrs(const IRPosition &IRP, ArrayRef<Attribute::AttrKind> AKs,
1940 SmallVectorImpl<Attribute> &Attrs,
1941 bool IgnoreSubsumingPositions = false);
1942
1943
1944 ChangeStatus removeAttrs(const IRPosition &IRP,
1945 ArrayRef<Attribute::AttrKind> AttrKinds);
1946 ChangeStatus removeAttrs(const IRPosition &IRP, ArrayRef<StringRef> Attrs);
1947
1948
1949
1950 ChangeStatus manifestAttrs(const IRPosition &IRP,
1951 ArrayRef<Attribute> DeducedAttrs,
1952 bool ForceReplace = false);
1953
1954 private:
1955
1956
1957 template <Attribute::AttrKind AK, typename AAType>
1958 void checkAndQueryIRAttr(const IRPosition &IRP, AttributeSet Attrs);
1959
1960
1961 template <typename DescTy>
1962 ChangeStatus updateAttrMap(const IRPosition &IRP, ArrayRef<DescTy> AttrDescs,
1963 function_ref<bool(const DescTy &, AttributeSet,
1964 AttributeMask &, AttrBuilder &)>
1965 CB);
1966
1967
1968 DenseMap<Value *, AttributeList> AttrsMap;
1969
1970 public:
1971
1972
1973 std::optional<Constant *> getAssumedConstant(const IRPosition &IRP,
1974 const AbstractAttribute &AA,
1975 bool &UsedAssumedInformation);
1976 std::optional<Constant *> getAssumedConstant(const Value &V,
1977 const AbstractAttribute &AA,
1978 bool &UsedAssumedInformation) {
1979 return getAssumedConstant(IRPosition::value(V), AA, UsedAssumedInformation);
1980 }
1981
1982
1983
1984 std::optional<Value *> getAssumedSimplified(const IRPosition &IRP,
1985 const AbstractAttribute &AA,
1986 bool &UsedAssumedInformation,
1987 AA::ValueScope S) {
1988 return getAssumedSimplified(IRP, &AA, UsedAssumedInformation, S);
1989 }
1990 std::optional<Value *> getAssumedSimplified(const Value &V,
1991 const AbstractAttribute &AA,
1992 bool &UsedAssumedInformation,
1993 AA::ValueScope S) {
1994 return getAssumedSimplified(IRPosition::value(V), AA,
1995 UsedAssumedInformation, S);
1996 }
1997
1998
1999
2000
2001
2002 std::optional<Value *> getAssumedSimplified(const IRPosition &V,
2003 const AbstractAttribute *AA,
2004 bool &UsedAssumedInformation,
2005 AA::ValueScope S);
2006
2007
2008
2009
2010
2011
2012
2013 bool getAssumedSimplifiedValues(const IRPosition &IRP,
2014 const AbstractAttribute *AA,
2015 SmallVectorImpl<AA::ValueAndContext> &Values,
2016 AA::ValueScope S,
2017 bool &UsedAssumedInformation,
2018 bool RecurseForSelectAndPHI = true);
2019
2020
2021
2022
2023
2024
2025 using SimplifictionCallbackTy = std::function<std::optional<Value *>(
2026 const IRPosition &, const AbstractAttribute *, bool &)>;
2027 void registerSimplificationCallback(const IRPosition &IRP,
2028 const SimplifictionCallbackTy &CB) {
2029 SimplificationCallbacks[IRP].emplace_back(CB);
2030 }
2031
2032
2033 bool hasSimplificationCallback(const IRPosition &IRP) {
2034 return SimplificationCallbacks.count(IRP);
2035 }
2036
2037
2038
2039
2040 using GlobalVariableSimplifictionCallbackTy =
2041 std::function<std::optional<Constant *>(
2042 const GlobalVariable &, const AbstractAttribute *, bool &)>;
2043 void registerGlobalVariableSimplificationCallback(
2044 const GlobalVariable &GV,
2045 const GlobalVariableSimplifictionCallbackTy &CB) {
2046 GlobalVariableSimplificationCallbacks[&GV].emplace_back(CB);
2047 }
2048
2049
2050 bool hasGlobalVariableSimplificationCallback(const GlobalVariable &GV) {
2051 return GlobalVariableSimplificationCallbacks.count(&GV);
2052 }
2053
2054
2055
2056
2057 std::optional<Constant *>
2058 getAssumedInitializerFromCallBack(const GlobalVariable &GV,
2059 const AbstractAttribute *AA,
2060 bool &UsedAssumedInformation) {
2061 assert(GlobalVariableSimplificationCallbacks.contains(&GV));
2062 for (auto &CB : GlobalVariableSimplificationCallbacks.lookup(&GV)) {
2063 auto SimplifiedGV = CB(GV, AA, UsedAssumedInformation);
2064
2065 assert(SimplifiedGV.has_value() && "SimplifiedGV has not value");
2066 return *SimplifiedGV;
2067 }
2068 llvm_unreachable("there must be a callback registered");
2069 }
2070
2071 using VirtualUseCallbackTy =
2072 std::function<bool(Attributor &, const AbstractAttribute *)>;
2073 void registerVirtualUseCallback(const Value &V,
2074 const VirtualUseCallbackTy &CB) {
2075 VirtualUseCallbacks[&V].emplace_back(CB);
2076 }
2077
2078 private:
2079
2080 DenseMap<IRPosition, SmallVector<SimplifictionCallbackTy, 1>>
2081 SimplificationCallbacks;
2082
2083
2084
2085 DenseMap<const GlobalVariable *,
2086 SmallVector<GlobalVariableSimplifictionCallbackTy, 1>>
2087 GlobalVariableSimplificationCallbacks;
2088
2089 DenseMap<const Value *, SmallVector<VirtualUseCallbackTy, 1>>
2090 VirtualUseCallbacks;
2091
2092 public:
2093
2094 std::optional<Value *>
2095 translateArgumentToCallSiteContent(std::optional<Value *> V, CallBase &CB,
2096 const AbstractAttribute &AA,
2097 bool &UsedAssumedInformation);
2098
2099
2100
2101
2102 bool isAssumedDead(const AbstractAttribute &AA, const AAIsDead *LivenessAA,
2103 bool &UsedAssumedInformation,
2104 bool CheckBBLivenessOnly = false,
2105 DepClassTy DepClass = DepClassTy::OPTIONAL);
2106
2107
2108
2109
2110 bool isAssumedDead(const Instruction &I, const AbstractAttribute *QueryingAA,
2111 const AAIsDead *LivenessAA, bool &UsedAssumedInformation,
2112 bool CheckBBLivenessOnly = false,
2113 DepClassTy DepClass = DepClassTy::OPTIONAL,
2114 bool CheckForDeadStore = false);
2115
2116
2117
2118
2119 bool isAssumedDead(const Use &U, const AbstractAttribute *QueryingAA,
2120 const AAIsDead *FnLivenessAA, bool &UsedAssumedInformation,
2121 bool CheckBBLivenessOnly = false,
2122 DepClassTy DepClass = DepClassTy::OPTIONAL);
2123
2124
2125
2126
2127 bool isAssumedDead(const IRPosition &IRP, const AbstractAttribute *QueryingAA,
2128 const AAIsDead *FnLivenessAA, bool &UsedAssumedInformation,
2129 bool CheckBBLivenessOnly = false,
2130 DepClassTy DepClass = DepClassTy::OPTIONAL);
2131
2132
2133
2134
2135 bool isAssumedDead(const BasicBlock &BB, const AbstractAttribute *QueryingAA,
2136 const AAIsDead *FnLivenessAA,
2137 DepClassTy DepClass = DepClassTy::OPTIONAL);
2138
2139
2140
2141
2142
2143
2144 bool checkForAllCallees(
2145 function_ref<bool(ArrayRef<const Function *> Callees)> Pred,
2146 const AbstractAttribute &QueryingAA, const CallBase &CB);
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157 bool checkForAllUses(function_ref<bool(const Use &, bool &)> Pred,
2158 const AbstractAttribute &QueryingAA, const Value &V,
2159 bool CheckBBLivenessOnly = false,
2160 DepClassTy LivenessDepClass = DepClassTy::OPTIONAL,
2161 bool IgnoreDroppableUses = true,
2162 function_ref<bool(const Use &OldU, const Use &NewU)>
2163 EquivalentUseCB = nullptr);
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176 template <typename RemarkKind, typename RemarkCallBack>
2177 void emitRemark(Instruction *I, StringRef RemarkName,
2178 RemarkCallBack &&RemarkCB) const {
2179 if (!Configuration.OREGetter)
2180 return;
2181
2182 Function *F = I->getFunction();
2183 auto &ORE = Configuration.OREGetter(F);
2184
2185 if (RemarkName.starts_with("OMP"))
2186 ORE.emit([&]() {
2187 return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, I))
2188 << " [" << RemarkName << "]";
2189 });
2190 else
2191 ORE.emit([&]() {
2192 return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, I));
2193 });
2194 }
2195
2196
2197 template <typename RemarkKind, typename RemarkCallBack>
2198 void emitRemark(Function *F, StringRef RemarkName,
2199 RemarkCallBack &&RemarkCB) const {
2200 if (!Configuration.OREGetter)
2201 return;
2202
2203 auto &ORE = Configuration.OREGetter(F);
2204
2205 if (RemarkName.starts_with("OMP"))
2206 ORE.emit([&]() {
2207 return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, F))
2208 << " [" << RemarkName << "]";
2209 });
2210 else
2211 ORE.emit([&]() {
2212 return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, F));
2213 });
2214 }
2215
2216
2217
2218
2219
2220
2221 struct ArgumentReplacementInfo {
2222
2223
2224
2225
2226
2227
2228
2229 using CalleeRepairCBTy = std::function<void(
2230 const ArgumentReplacementInfo &, Function &, Function::arg_iterator)>;
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242 using ACSRepairCBTy =
2243 std::function<void(const ArgumentReplacementInfo &, AbstractCallSite,
2244 SmallVectorImpl<Value *> &)>;
2245
2246
2247
2248
2249 Attributor &getAttributor() const { return A; }
2250 const Function &getReplacedFn() const { return ReplacedFn; }
2251 const Argument &getReplacedArg() const { return ReplacedArg; }
2252 unsigned getNumReplacementArgs() const { return ReplacementTypes.size(); }
2253 const SmallVectorImpl<Type *> &getReplacementTypes() const {
2254 return ReplacementTypes;
2255 }
2256
2257
2258
2259 private:
2260
2261
2262
2263 ArgumentReplacementInfo(Attributor &A, Argument &Arg,
2264 ArrayRef<Type *> ReplacementTypes,
2265 CalleeRepairCBTy &&CalleeRepairCB,
2266 ACSRepairCBTy &&ACSRepairCB)
2267 : A(A), ReplacedFn(*Arg.getParent()), ReplacedArg(Arg),
2268 ReplacementTypes(ReplacementTypes),
2269 CalleeRepairCB(std::move(CalleeRepairCB)),
2270 ACSRepairCB(std::move(ACSRepairCB)) {}
2271
2272
2273 Attributor &A;
2274
2275
2276 const Function &ReplacedFn;
2277
2278
2279 const Argument &ReplacedArg;
2280
2281
2282 const SmallVector<Type *, 8> ReplacementTypes;
2283
2284
2285 const CalleeRepairCBTy CalleeRepairCB;
2286
2287
2288 const ACSRepairCBTy ACSRepairCB;
2289
2290
2291 friend struct Attributor;
2292 };
2293
2294
2295
2296
2297
2298
2299
2300
2301 bool isValidFunctionSignatureRewrite(Argument &Arg,
2302 ArrayRef<Type *> ReplacementTypes);
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312 bool registerFunctionSignatureRewrite(
2313 Argument &Arg, ArrayRef<Type *> ReplacementTypes,
2314 ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB,
2315 ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB);
2316
2317
2318
2319
2320
2321
2322
2323
2324 bool checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
2325 const AbstractAttribute &QueryingAA,
2326 bool RequireAllCallSites,
2327 bool &UsedAssumedInformation);
2328
2329
2330
2331
2332
2333
2334
2335
2336 bool checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
2337 const Function &Fn, bool RequireAllCallSites,
2338 const AbstractAttribute *QueryingAA,
2339 bool &UsedAssumedInformation,
2340 bool CheckPotentiallyDead = false);
2341
2342
2343
2344
2345
2346 bool
2347 checkForAllReturnedValues(function_ref<bool(Value &)> Pred,
2348 const AbstractAttribute &QueryingAA,
2349 AA::ValueScope S = AA::ValueScope::Intraprocedural,
2350 bool RecurseForSelectAndPHI = true);
2351
2352
2353
2354
2355
2356
2357 bool checkForAllInstructions(function_ref<bool(Instruction &)> Pred,
2358 const Function *Fn,
2359 const AbstractAttribute *QueryingAA,
2360 ArrayRef<unsigned> Opcodes,
2361 bool &UsedAssumedInformation,
2362 bool CheckBBLivenessOnly = false,
2363 bool CheckPotentiallyDead = false);
2364
2365
2366
2367
2368
2369 bool checkForAllInstructions(function_ref<bool(Instruction &)> Pred,
2370 const AbstractAttribute &QueryingAA,
2371 ArrayRef<unsigned> Opcodes,
2372 bool &UsedAssumedInformation,
2373 bool CheckBBLivenessOnly = false,
2374 bool CheckPotentiallyDead = false);
2375
2376
2377
2378
2379 bool checkForAllCallLikeInstructions(function_ref<bool(Instruction &)> Pred,
2380 const AbstractAttribute &QueryingAA,
2381 bool &UsedAssumedInformation,
2382 bool CheckBBLivenessOnly = false,
2383 bool CheckPotentiallyDead = false) {
2384 return checkForAllInstructions(
2385 Pred, QueryingAA,
2386 {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
2387 (unsigned)Instruction::Call},
2388 UsedAssumedInformation, CheckBBLivenessOnly, CheckPotentiallyDead);
2389 }
2390
2391
2392
2393
2394
2395
2396 bool checkForAllReadWriteInstructions(function_ref<bool(Instruction &)> Pred,
2397 AbstractAttribute &QueryingAA,
2398 bool &UsedAssumedInformation);
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414 static void createShallowWrapper(Function &F);
2415
2416
2417
2418 static bool isInternalizable(Function &F);
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433 static Function *internalizeFunction(Function &F, bool Force = false);
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448 static bool internalizeFunctions(SmallPtrSetImpl<Function *> &FnSet,
2449 DenseMap<Function *, Function *> &FnMap);
2450
2451
2452 const DataLayout &getDataLayout() const { return InfoCache.DL; }
2453
2454
2455 BumpPtrAllocator &Allocator;
2456
2457 const SmallSetVector<Function *, 8> &getModifiedFunctions() {
2458 return CGModifiedFunctions;
2459 }
2460
2461 private:
2462
2463
2464
2465
2466
2467
2468 void runTillFixpoint();
2469
2470
2471 ChangeStatus manifestAttributes();
2472
2473
2474
2475
2476 ChangeStatus cleanupIR();
2477
2478
2479
2480 void identifyDeadInternalFunctions();
2481
2482
2483
2484 ChangeStatus updateAA(AbstractAttribute &AA);
2485
2486
2487
2488 void rememberDependences();
2489
2490
2491 bool shouldPropagateCallBaseContext(const IRPosition &IRP);
2492
2493
2494
2495
2496 ChangeStatus
2497 rewriteFunctionSignatures(SmallSetVector<Function *, 8> &ModifiedFns);
2498
2499
2500
2501 bool shouldSeedAttribute(AbstractAttribute &AA);
2502
2503
2504
2505
2506
2507 using AAMapKeyTy = std::pair<const char *, IRPosition>;
2508 DenseMap<AAMapKeyTy, AbstractAttribute *> AAMap;
2509
2510
2511
2512 DenseMap<Function *, SmallVector<std::unique_ptr<ArgumentReplacementInfo>, 8>>
2513 ArgumentReplacementMap;
2514
2515
2516 SetVector<Function *> &Functions;
2517
2518
2519 InformationCache &InfoCache;
2520
2521
2522 AADepGraph DG;
2523
2524
2525
2526 SmallSetVector<Function *, 8> CGModifiedFunctions;
2527
2528
2529
2530 struct DepInfo {
2531 const AbstractAttribute *FromAA;
2532 const AbstractAttribute *ToAA;
2533 DepClassTy DepClass;
2534 };
2535
2536
2537
2538
2539
2540
2541
2542
2543 using DependenceVector = SmallVector<DepInfo, 8>;
2544 SmallVector<DependenceVector *, 16> DependenceStack;
2545
2546
2547 DenseSet<const Function *> VisitedFunctions;
2548
2549
2550
2551 SmallMapVector<Use *, Value *, 32> ToBeChangedUses;
2552
2553
2554
2555 SmallMapVector<Value *, PointerIntPair<Value *, 1, bool>, 32>
2556 ToBeChangedValues;
2557
2558
2559 SmallSetVector<WeakVH, 16> ToBeChangedToUnreachableInsts;
2560
2561
2562 SmallSetVector<WeakVH, 16> InvokeWithDeadSuccessor;
2563
2564
2565
2566 enum class AttributorPhase {
2567 SEEDING,
2568 UPDATE,
2569 MANIFEST,
2570 CLEANUP,
2571 } Phase = AttributorPhase::SEEDING;
2572
2573
2574 unsigned InitializationChainLength = 0;
2575
2576
2577
2578
2579 SmallPtrSet<BasicBlock *, 8> ManifestAddedBlocks;
2580 SmallSetVector<Function *, 8> ToBeDeletedFunctions;
2581 SmallSetVector<BasicBlock *, 8> ToBeDeletedBlocks;
2582 SmallSetVector<WeakVH, 8> ToBeDeletedInsts;
2583
2584
2585
2586
2587 SmallSetVector<AbstractAttribute *, 16> QueryAAsAwaitingUpdate;
2588
2589
2590 const AttributorConfig Configuration;
2591
2592 friend AADepGraph;
2593 friend AttributorCallGraph;
2594 };
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613 struct AbstractState {
2614 virtual ~AbstractState() = default;
2615
2616
2617
2618 virtual bool isValidState() const = 0;
2619
2620
2621
2622 virtual bool isAtFixpoint() const = 0;
2623
2624
2625
2626
2627
2628
2629
2630 virtual ChangeStatus indicateOptimisticFixpoint() = 0;
2631
2632
2633
2634
2635
2636
2637
2638 virtual ChangeStatus indicatePessimisticFixpoint() = 0;
2639 };
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651 template <typename base_ty, base_ty BestState, base_ty WorstState>
2652 struct IntegerStateBase : public AbstractState {
2653 using base_t = base_ty;
2654
2655 IntegerStateBase() = default;
2656 IntegerStateBase(base_t Assumed) : Assumed(Assumed) {}
2657
2658
2659 static constexpr base_t getBestState() { return BestState; }
2660 static constexpr base_t getBestState(const IntegerStateBase &) {
2661 return getBestState();
2662 }
2663
2664
2665 static constexpr base_t getWorstState() { return WorstState; }
2666 static constexpr base_t getWorstState(const IntegerStateBase &) {
2667 return getWorstState();
2668 }
2669
2670
2671
2672 bool isValidState() const override { return Assumed != getWorstState(); }
2673
2674
2675 bool isAtFixpoint() const override { return Assumed == Known; }
2676
2677
2678 ChangeStatus indicateOptimisticFixpoint() override {
2679 Known = Assumed;
2680 return ChangeStatus::UNCHANGED;
2681 }
2682
2683
2684 ChangeStatus indicatePessimisticFixpoint() override {
2685 Assumed = Known;
2686 return ChangeStatus::CHANGED;
2687 }
2688
2689
2690 base_t getKnown() const { return Known; }
2691
2692
2693 base_t getAssumed() const { return Assumed; }
2694
2695
2696 bool
2697 operator==(const IntegerStateBase<base_t, BestState, WorstState> &R) const {
2698 return this->getAssumed() == R.getAssumed() &&
2699 this->getKnown() == R.getKnown();
2700 }
2701
2702
2703 bool
2704 operator!=(const IntegerStateBase<base_t, BestState, WorstState> &R) const {
2705 return !(*this == R);
2706 }
2707
2708
2709
2710
2711 void operator^=(const IntegerStateBase<base_t, BestState, WorstState> &R) {
2712 handleNewAssumedValue(R.getAssumed());
2713 }
2714
2715
2716
2717
2718 void operator+=(const IntegerStateBase<base_t, BestState, WorstState> &R) {
2719 handleNewKnownValue(R.getKnown());
2720 }
2721
2722 void operator|=(const IntegerStateBase<base_t, BestState, WorstState> &R) {
2723 joinOR(R.getAssumed(), R.getKnown());
2724 }
2725
2726 void operator&=(const IntegerStateBase<base_t, BestState, WorstState> &R) {
2727 joinAND(R.getAssumed(), R.getKnown());
2728 }
2729
2730 protected:
2731
2732 virtual void handleNewAssumedValue(base_t Value) = 0;
2733
2734
2735 virtual void handleNewKnownValue(base_t Value) = 0;
2736
2737
2738 virtual void joinOR(base_t AssumedValue, base_t KnownValue) = 0;
2739
2740
2741 virtual void joinAND(base_t AssumedValue, base_t KnownValue) = 0;
2742
2743
2744 base_t Known = getWorstState();
2745
2746
2747 base_t Assumed = getBestState();
2748 };
2749
2750
2751 template <typename base_ty = uint32_t, base_ty BestState = ~base_ty(0),
2752 base_ty WorstState = 0>
2753 struct BitIntegerState
2754 : public IntegerStateBase<base_ty, BestState, WorstState> {
2755 using super = IntegerStateBase<base_ty, BestState, WorstState>;
2756 using base_t = base_ty;
2757 BitIntegerState() = default;
2758 BitIntegerState(base_t Assumed) : super(Assumed) {}
2759
2760
2761 bool isKnown(base_t BitsEncoding = BestState) const {
2762 return (this->Known & BitsEncoding) == BitsEncoding;
2763 }
2764
2765
2766 bool isAssumed(base_t BitsEncoding = BestState) const {
2767 return (this->Assumed & BitsEncoding) == BitsEncoding;
2768 }
2769
2770
2771 BitIntegerState &addKnownBits(base_t Bits) {
2772
2773 this->Assumed |= Bits;
2774 this->Known |= Bits;
2775 return *this;
2776 }
2777
2778
2779 BitIntegerState &removeAssumedBits(base_t BitsEncoding) {
2780 return intersectAssumedBits(~BitsEncoding);
2781 }
2782
2783
2784 BitIntegerState &removeKnownBits(base_t BitsEncoding) {
2785 this->Known = (this->Known & ~BitsEncoding);
2786 return *this;
2787 }
2788
2789
2790 BitIntegerState &intersectAssumedBits(base_t BitsEncoding) {
2791
2792 this->Assumed = (this->Assumed & BitsEncoding) | this->Known;
2793 return *this;
2794 }
2795
2796 private:
2797 void handleNewAssumedValue(base_t Value) override {
2798 intersectAssumedBits(Value);
2799 }
2800 void handleNewKnownValue(base_t Value) override { addKnownBits(Value); }
2801 void joinOR(base_t AssumedValue, base_t KnownValue) override {
2802 this->Known |= KnownValue;
2803 this->Assumed |= AssumedValue;
2804 }
2805 void joinAND(base_t AssumedValue, base_t KnownValue) override {
2806 this->Known &= KnownValue;
2807 this->Assumed &= AssumedValue;
2808 }
2809 };
2810
2811
2812
2813 template <typename base_ty = uint32_t, base_ty BestState = ~base_ty(0),
2814 base_ty WorstState = 0>
2815 struct IncIntegerState
2816 : public IntegerStateBase<base_ty, BestState, WorstState> {
2817 using super = IntegerStateBase<base_ty, BestState, WorstState>;
2818 using base_t = base_ty;
2819
2820 IncIntegerState() : super() {}
2821 IncIntegerState(base_t Assumed) : super(Assumed) {}
2822
2823
2824 static constexpr base_t getBestState() { return BestState; }
2825 static constexpr base_t
2826 getBestState(const IncIntegerState<base_ty, BestState, WorstState> &) {
2827 return getBestState();
2828 }
2829
2830
2831 IncIntegerState &takeAssumedMinimum(base_t Value) {
2832
2833 this->Assumed = std::max(std::min(this->Assumed, Value), this->Known);
2834 return *this;
2835 }
2836
2837
2838 IncIntegerState &takeKnownMaximum(base_t Value) {
2839
2840 this->Assumed = std::max(Value, this->Assumed);
2841 this->Known = std::max(Value, this->Known);
2842 return *this;
2843 }
2844
2845 private:
2846 void handleNewAssumedValue(base_t Value) override {
2847 takeAssumedMinimum(Value);
2848 }
2849 void handleNewKnownValue(base_t Value) override { takeKnownMaximum(Value); }
2850 void joinOR(base_t AssumedValue, base_t KnownValue) override {
2851 this->Known = std::max(this->Known, KnownValue);
2852 this->Assumed = std::max(this->Assumed, AssumedValue);
2853 }
2854 void joinAND(base_t AssumedValue, base_t KnownValue) override {
2855 this->Known = std::min(this->Known, KnownValue);
2856 this->Assumed = std::min(this->Assumed, AssumedValue);
2857 }
2858 };
2859
2860
2861
2862 template <typename base_ty = uint32_t>
2863 struct DecIntegerState : public IntegerStateBase<base_ty, 0, ~base_ty(0)> {
2864 using base_t = base_ty;
2865
2866
2867 DecIntegerState &takeAssumedMaximum(base_t Value) {
2868
2869 this->Assumed = std::min(std::max(this->Assumed, Value), this->Known);
2870 return *this;
2871 }
2872
2873
2874 DecIntegerState &takeKnownMinimum(base_t Value) {
2875
2876 this->Assumed = std::min(Value, this->Assumed);
2877 this->Known = std::min(Value, this->Known);
2878 return *this;
2879 }
2880
2881 private:
2882 void handleNewAssumedValue(base_t Value) override {
2883 takeAssumedMaximum(Value);
2884 }
2885 void handleNewKnownValue(base_t Value) override { takeKnownMinimum(Value); }
2886 void joinOR(base_t AssumedValue, base_t KnownValue) override {
2887 this->Assumed = std::min(this->Assumed, KnownValue);
2888 this->Assumed = std::min(this->Assumed, AssumedValue);
2889 }
2890 void joinAND(base_t AssumedValue, base_t KnownValue) override {
2891 this->Assumed = std::max(this->Assumed, KnownValue);
2892 this->Assumed = std::max(this->Assumed, AssumedValue);
2893 }
2894 };
2895
2896
2897 struct BooleanState : public IntegerStateBase<bool, true, false> {
2898 using super = IntegerStateBase<bool, true, false>;
2899 using base_t = IntegerStateBase::base_t;
2900
2901 BooleanState() = default;
2902 BooleanState(base_t Assumed) : super(Assumed) {}
2903
2904
2905 void setAssumed(bool Value) { Assumed &= (Known | Value); }
2906
2907
2908 void setKnown(bool Value) {
2909 Known |= Value;
2910 Assumed |= Value;
2911 }
2912
2913
2914 bool isAssumed() const { return getAssumed(); }
2915
2916
2917 bool isKnown() const { return getKnown(); }
2918
2919 private:
2920 void handleNewAssumedValue(base_t Value) override {
2921 if (!Value)
2922 Assumed = Known;
2923 }
2924 void handleNewKnownValue(base_t Value) override {
2925 if (Value)
2926 Known = (Assumed = Value);
2927 }
2928 void joinOR(base_t AssumedValue, base_t KnownValue) override {
2929 Known |= KnownValue;
2930 Assumed |= AssumedValue;
2931 }
2932 void joinAND(base_t AssumedValue, base_t KnownValue) override {
2933 Known &= KnownValue;
2934 Assumed &= AssumedValue;
2935 }
2936 };
2937
2938
2939 struct IntegerRangeState : public AbstractState {
2940
2941
2942 uint32_t BitWidth;
2943
2944
2945 ConstantRange Assumed;
2946
2947
2948 ConstantRange Known;
2949
2950 IntegerRangeState(uint32_t BitWidth)
2951 : BitWidth(BitWidth), Assumed(ConstantRange::getEmpty(BitWidth)),
2952 Known(ConstantRange::getFull(BitWidth)) {}
2953
2954 IntegerRangeState(const ConstantRange &CR)
2955 : BitWidth(CR.getBitWidth()), Assumed(CR),
2956 Known(getWorstState(CR.getBitWidth())) {}
2957
2958
2959 static ConstantRange getWorstState(uint32_t BitWidth) {
2960 return ConstantRange::getFull(BitWidth);
2961 }
2962
2963
2964 static ConstantRange getBestState(uint32_t BitWidth) {
2965 return ConstantRange::getEmpty(BitWidth);
2966 }
2967 static ConstantRange getBestState(const IntegerRangeState &IRS) {
2968 return getBestState(IRS.getBitWidth());
2969 }
2970
2971
2972 uint32_t getBitWidth() const { return BitWidth; }
2973
2974
2975 bool isValidState() const override {
2976 return BitWidth > 0 && !Assumed.isFullSet();
2977 }
2978
2979
2980 bool isAtFixpoint() const override { return Assumed == Known; }
2981
2982
2983 ChangeStatus indicateOptimisticFixpoint() override {
2984 Known = Assumed;
2985 return ChangeStatus::CHANGED;
2986 }
2987
2988
2989 ChangeStatus indicatePessimisticFixpoint() override {
2990 Assumed = Known;
2991 return ChangeStatus::CHANGED;
2992 }
2993
2994
2995 ConstantRange getKnown() const { return Known; }
2996
2997
2998 ConstantRange getAssumed() const { return Assumed; }
2999
3000
3001 void unionAssumed(const ConstantRange &R) {
3002
3003 Assumed = Assumed.unionWith(R).intersectWith(Known);
3004 }
3005
3006
3007 void unionAssumed(const IntegerRangeState &R) {
3008 unionAssumed(R.getAssumed());
3009 }
3010
3011
3012 void intersectKnown(const ConstantRange &R) {
3013 Assumed = Assumed.intersectWith(R);
3014 Known = Known.intersectWith(R);
3015 }
3016
3017
3018 void intersectKnown(const IntegerRangeState &R) {
3019 intersectKnown(R.getKnown());
3020 }
3021
3022
3023 bool operator==(const IntegerRangeState &R) const {
3024 return getAssumed() == R.getAssumed() && getKnown() == R.getKnown();
3025 }
3026
3027
3028
3029
3030 IntegerRangeState operator^=(const IntegerRangeState &R) {
3031
3032
3033 unionAssumed(R);
3034 return *this;
3035 }
3036
3037 IntegerRangeState operator&=(const IntegerRangeState &R) {
3038
3039
3040 Known = Known.unionWith(R.getKnown());
3041 Assumed = Assumed.unionWith(R.getAssumed());
3042 return *this;
3043 }
3044 };
3045
3046
3047
3048
3049
3050
3051 template <typename BaseTy> struct SetState : public AbstractState {
3052
3053
3054 struct SetContents {
3055
3056 SetContents(bool Universal) : Universal(Universal) {}
3057
3058
3059 SetContents(const DenseSet<BaseTy> &Assumptions)
3060 : Universal(false), Set(Assumptions) {}
3061
3062 SetContents(bool Universal, const DenseSet<BaseTy> &Assumptions)
3063 : Universal(Universal), Set(Assumptions) {}
3064
3065 const DenseSet<BaseTy> &getSet() const { return Set; }
3066
3067 bool isUniversal() const { return Universal; }
3068
3069 bool empty() const { return Set.empty() && !Universal; }
3070
3071
3072
3073 bool getIntersection(const SetContents &RHS) {
3074 bool IsUniversal = Universal;
3075 unsigned Size = Set.size();
3076
3077
3078 if (RHS.isUniversal())
3079 return false;
3080
3081
3082 if (Universal)
3083 Set = RHS.getSet();
3084 else
3085 set_intersect(Set, RHS.getSet());
3086
3087 Universal &= RHS.isUniversal();
3088 return IsUniversal != Universal || Size != Set.size();
3089 }
3090
3091
3092
3093 bool getUnion(const SetContents &RHS) {
3094 bool IsUniversal = Universal;
3095 unsigned Size = Set.size();
3096
3097
3098 if (!RHS.isUniversal() && !Universal)
3099 set_union(Set, RHS.getSet());
3100
3101 Universal |= RHS.isUniversal();
3102 return IsUniversal != Universal || Size != Set.size();
3103 }
3104
3105 private:
3106
3107 bool Universal;
3108
3109
3110 DenseSet<BaseTy> Set;
3111 };
3112
3113 SetState() : Known(false), Assumed(true), IsAtFixedpoint(false) {}
3114
3115
3116
3117 SetState(const DenseSet<BaseTy> &Known)
3118 : Known(Known), Assumed(true), IsAtFixedpoint(false) {}
3119
3120
3121 bool isValidState() const override { return !Assumed.empty(); }
3122
3123
3124 bool isAtFixpoint() const override { return IsAtFixedpoint; }
3125
3126
3127 ChangeStatus indicateOptimisticFixpoint() override {
3128 IsAtFixedpoint = true;
3129 Known = Assumed;
3130 return ChangeStatus::UNCHANGED;
3131 }
3132
3133
3134 ChangeStatus indicatePessimisticFixpoint() override {
3135 IsAtFixedpoint = true;
3136 Assumed = Known;
3137 return ChangeStatus::CHANGED;
3138 }
3139
3140
3141 const SetContents &getKnown() const { return Known; }
3142
3143
3144 const SetContents &getAssumed() const { return Assumed; }
3145
3146
3147 bool setContains(const BaseTy &Elem) const {
3148 return Assumed.getSet().contains(Elem) || Known.getSet().contains(Elem);
3149 }
3150
3151
3152
3153 bool getIntersection(const SetContents &RHS) {
3154 bool IsUniversal = Assumed.isUniversal();
3155 unsigned SizeBefore = Assumed.getSet().size();
3156
3157
3158
3159 Assumed.getIntersection(RHS);
3160 Assumed.getUnion(Known);
3161
3162 return SizeBefore != Assumed.getSet().size() ||
3163 IsUniversal != Assumed.isUniversal();
3164 }
3165
3166
3167
3168 bool getUnion(const SetContents &RHS) { return Assumed.getUnion(RHS); }
3169
3170 private:
3171
3172 SetContents Known;
3173
3174
3175 SetContents Assumed;
3176
3177 bool IsAtFixedpoint;
3178 };
3179
3180
3181 template <typename StateTy, typename BaseType, class... Ts>
3182 struct StateWrapper : public BaseType, public StateTy {
3183
3184 using StateType = StateTy;
3185
3186 StateWrapper(const IRPosition &IRP, Ts... Args)
3187 : BaseType(IRP), StateTy(Args...) {}
3188
3189
3190 StateType &getState() override { return *this; }
3191
3192
3193 const StateType &getState() const override { return *this; }
3194 };
3195
3196
3197 template <Attribute::AttrKind AK, typename BaseType, typename AAType>
3198 struct IRAttribute : public BaseType {
3199 IRAttribute(const IRPosition &IRP) : BaseType(IRP) {}
3200
3201
3202
3203
3204 static bool hasTrivialInitializer() { return Attribute::isEnumAttrKind(AK); }
3205
3206
3207 static constexpr Attribute::AttrKind IRAttributeKind = AK;
3208
3209
3210
3211 static bool isImpliedByUndef() { return true; }
3212
3213
3214
3215 static bool isImpliedByPoison() { return true; }
3216
3217 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3218 Attribute::AttrKind ImpliedAttributeKind = AK,
3219 bool IgnoreSubsumingPositions = false) {
3220 if (AAType::isImpliedByUndef() && isa<UndefValue>(IRP.getAssociatedValue()))
3221 return true;
3222 if (AAType::isImpliedByPoison() &&
3223 isa<PoisonValue>(IRP.getAssociatedValue()))
3224 return true;
3225 return A.hasAttr(IRP, {ImpliedAttributeKind}, IgnoreSubsumingPositions,
3226 ImpliedAttributeKind);
3227 }
3228
3229
3230 ChangeStatus manifest(Attributor &A) override {
3231 if (isa<UndefValue>(this->getIRPosition().getAssociatedValue()))
3232 return ChangeStatus::UNCHANGED;
3233 SmallVector<Attribute, 4> DeducedAttrs;
3234 getDeducedAttributes(A, this->getAnchorValue().getContext(), DeducedAttrs);
3235 if (DeducedAttrs.empty())
3236 return ChangeStatus::UNCHANGED;
3237 return A.manifestAttrs(this->getIRPosition(), DeducedAttrs);
3238 }
3239
3240
3241 Attribute::AttrKind getAttrKind() const { return AK; }
3242
3243
3244 virtual void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,
3245 SmallVectorImpl<Attribute> &Attrs) const {
3246 Attrs.emplace_back(Attribute::get(Ctx, getAttrKind()));
3247 }
3248 };
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293 struct AbstractAttribute : public IRPosition, public AADepGraphNode {
3294 using StateType = AbstractState;
3295
3296 AbstractAttribute(const IRPosition &IRP) : IRPosition(IRP) {}
3297
3298
3299 virtual ~AbstractAttribute() = default;
3300
3301
3302 static constexpr Attribute::AttrKind IRAttributeKind = Attribute::None;
3303
3304
3305
3306
3307
3308
3309
3310 static bool classof(const AADepGraphNode *DGN) { return true; }
3311
3312
3313
3314 static bool hasTrivialInitializer() { return false; }
3315
3316
3317
3318 static bool requiresCalleeForCallBase() { return false; }
3319
3320
3321 static bool requiresNonAsmForCallBase() { return true; }
3322
3323
3324
3325 static bool requiresCallersForArgOrFunction() { return false; }
3326
3327
3328 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3329 return true;
3330 }
3331
3332
3333 static bool isValidIRPositionForUpdate(Attributor &A, const IRPosition &IRP) {
3334 Function *AssociatedFn = IRP.getAssociatedFunction();
3335 bool IsFnInterface = IRP.isFnInterfaceKind();
3336 assert((!IsFnInterface || AssociatedFn) &&
3337 "Function interface without a function?");
3338
3339
3340
3341
3342
3343
3344
3345
3346 return !IsFnInterface || A.isFunctionIPOAmendable(*AssociatedFn);
3347 }
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357 virtual void initialize(Attributor &A) {}
3358
3359
3360
3361
3362
3363
3364
3365 virtual bool isQueryAA() const { return false; }
3366
3367
3368 virtual StateType &getState() = 0;
3369 virtual const StateType &getState() const = 0;
3370
3371
3372 const IRPosition &getIRPosition() const { return *this; };
3373 IRPosition &getIRPosition() { return *this; };
3374
3375
3376
3377 void print(raw_ostream &OS) const { print(nullptr, OS); }
3378 void print(Attributor *, raw_ostream &OS) const override;
3379 virtual void printWithDeps(raw_ostream &OS) const;
3380 void dump() const { this->print(dbgs()); }
3381
3382
3383 virtual const std::string getAsStr(Attributor *A) const = 0;
3384
3385
3386 virtual const std::string getName() const = 0;
3387
3388
3389 virtual const char *getIdAddr() const = 0;
3390
3391
3392
3393 friend struct Attributor;
3394
3395 protected:
3396
3397
3398
3399
3400
3401
3402 ChangeStatus update(Attributor &A);
3403
3404
3405
3406
3407
3408 virtual ChangeStatus manifest(Attributor &A) {
3409 return ChangeStatus::UNCHANGED;
3410 }
3411
3412
3413
3414
3415
3416
3417 virtual void trackStatistics() const = 0;
3418
3419
3420
3421
3422
3423
3424
3425
3426 virtual ChangeStatus updateImpl(Attributor &A) = 0;
3427 };
3428
3429
3430
3431
3432 raw_ostream &operator<<(raw_ostream &OS, const AbstractAttribute &AA);
3433 raw_ostream &operator<<(raw_ostream &OS, ChangeStatus S);
3434 raw_ostream &operator<<(raw_ostream &OS, IRPosition::Kind);
3435 raw_ostream &operator<<(raw_ostream &OS, const IRPosition &);
3436 raw_ostream &operator<<(raw_ostream &OS, const AbstractState &State);
3437 template <typename base_ty, base_ty BestState, base_ty WorstState>
3438 raw_ostream &
3439 operator<<(raw_ostream &OS,
3440 const IntegerStateBase<base_ty, BestState, WorstState> &S) {
3441 return OS << "(" << S.getKnown() << "-" << S.getAssumed() << ")"
3442 << static_cast<const AbstractState &>(S);
3443 }
3444 raw_ostream &operator<<(raw_ostream &OS, const IntegerRangeState &State);
3445
3446
3447 struct AttributorPass : public PassInfoMixin<AttributorPass> {
3448 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
3449 };
3450 struct AttributorCGSCCPass : public PassInfoMixin<AttributorCGSCCPass> {
3451 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
3452 LazyCallGraph &CG, CGSCCUpdateResult &UR);
3453 };
3454
3455
3456
3457 struct AttributorLightPass : public PassInfoMixin<AttributorLightPass> {
3458 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
3459 };
3460
3461
3462
3463 struct AttributorLightCGSCCPass
3464 : public PassInfoMixin<AttributorLightCGSCCPass> {
3465 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
3466 LazyCallGraph &CG, CGSCCUpdateResult &UR);
3467 };
3468
3469
3470
3471
3472 template <typename StateType>
3473 ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R) {
3474 auto Assumed = S.getAssumed();
3475 S ^= R;
3476 return Assumed == S.getAssumed() ? ChangeStatus::UNCHANGED
3477 : ChangeStatus::CHANGED;
3478 }
3479
3480
3481
3482
3483
3484 struct AANoUnwind
3485 : public IRAttribute<Attribute::NoUnwind,
3486 StateWrapper<BooleanState, AbstractAttribute>,
3487 AANoUnwind> {
3488 AANoUnwind(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3489
3490
3491 bool isAssumedNoUnwind() const { return getAssumed(); }
3492
3493
3494 bool isKnownNoUnwind() const { return getKnown(); }
3495
3496
3497 static AANoUnwind &createForPosition(const IRPosition &IRP, Attributor &A);
3498
3499
3500 const std::string getName() const override { return "AANoUnwind"; }
3501
3502
3503 const char *getIdAddr() const override { return &ID; }
3504
3505
3506 static bool classof(const AbstractAttribute *AA) {
3507 return (AA->getIdAddr() == &ID);
3508 }
3509
3510
3511 static const char ID;
3512 };
3513
3514 struct AANoSync
3515 : public IRAttribute<Attribute::NoSync,
3516 StateWrapper<BooleanState, AbstractAttribute>,
3517 AANoSync> {
3518 AANoSync(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3519
3520 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3521 Attribute::AttrKind ImpliedAttributeKind,
3522 bool IgnoreSubsumingPositions = false) {
3523
3524 assert(ImpliedAttributeKind == Attribute::NoSync);
3525 if (A.hasAttr(IRP, {Attribute::NoSync}, IgnoreSubsumingPositions,
3526 Attribute::NoSync))
3527 return true;
3528
3529
3530
3531
3532 Function *F = IRP.getAssociatedFunction();
3533 if (!F || F->isConvergent())
3534 return false;
3535
3536 SmallVector<Attribute, 2> Attrs;
3537 A.getAttrs(IRP, {Attribute::Memory}, Attrs, IgnoreSubsumingPositions);
3538
3539 MemoryEffects ME = MemoryEffects::unknown();
3540 for (const Attribute &Attr : Attrs)
3541 ME &= Attr.getMemoryEffects();
3542
3543 if (!ME.onlyReadsMemory())
3544 return false;
3545
3546 A.manifestAttrs(IRP, Attribute::get(F->getContext(), Attribute::NoSync));
3547 return true;
3548 }
3549
3550
3551 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3552 if (!IRP.isFunctionScope() &&
3553 !IRP.getAssociatedType()->isPtrOrPtrVectorTy())
3554 return false;
3555 return IRAttribute::isValidIRPositionForInit(A, IRP);
3556 }
3557
3558
3559 bool isAssumedNoSync() const { return getAssumed(); }
3560
3561
3562 bool isKnownNoSync() const { return getKnown(); }
3563
3564
3565
3566
3567 static bool isNonRelaxedAtomic(const Instruction *I);
3568
3569
3570 static bool isNoSyncIntrinsic(const Instruction *I);
3571
3572
3573
3574
3575
3576
3577 static bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned);
3578
3579
3580 static AANoSync &createForPosition(const IRPosition &IRP, Attributor &A);
3581
3582
3583 const std::string getName() const override { return "AANoSync"; }
3584
3585
3586 const char *getIdAddr() const override { return &ID; }
3587
3588
3589 static bool classof(const AbstractAttribute *AA) {
3590 return (AA->getIdAddr() == &ID);
3591 }
3592
3593
3594 static const char ID;
3595 };
3596
3597
3598 struct AAMustProgress
3599 : public IRAttribute<Attribute::MustProgress,
3600 StateWrapper<BooleanState, AbstractAttribute>,
3601 AAMustProgress> {
3602 AAMustProgress(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3603
3604 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3605 Attribute::AttrKind ImpliedAttributeKind,
3606 bool IgnoreSubsumingPositions = false) {
3607
3608 assert(ImpliedAttributeKind == Attribute::MustProgress);
3609 return A.hasAttr(IRP, {Attribute::MustProgress, Attribute::WillReturn},
3610 IgnoreSubsumingPositions, Attribute::MustProgress);
3611 }
3612
3613
3614 bool isAssumedMustProgress() const { return getAssumed(); }
3615
3616
3617 bool isKnownMustProgress() const { return getKnown(); }
3618
3619
3620 static AAMustProgress &createForPosition(const IRPosition &IRP,
3621 Attributor &A);
3622
3623
3624 const std::string getName() const override { return "AAMustProgress"; }
3625
3626
3627 const char *getIdAddr() const override { return &ID; }
3628
3629
3630
3631 static bool classof(const AbstractAttribute *AA) {
3632 return (AA->getIdAddr() == &ID);
3633 }
3634
3635
3636 static const char ID;
3637 };
3638
3639
3640 struct AANonNull
3641 : public IRAttribute<Attribute::NonNull,
3642 StateWrapper<BooleanState, AbstractAttribute>,
3643 AANonNull> {
3644 AANonNull(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3645
3646
3647 static bool hasTrivialInitializer() { return false; }
3648
3649
3650
3651
3652 static bool isImpliedByUndef() { return false; }
3653
3654
3655 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3656 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
3657 return false;
3658 return IRAttribute::isValidIRPositionForInit(A, IRP);
3659 }
3660
3661
3662 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3663 Attribute::AttrKind ImpliedAttributeKind,
3664 bool IgnoreSubsumingPositions = false);
3665
3666
3667 bool isAssumedNonNull() const { return getAssumed(); }
3668
3669
3670 bool isKnownNonNull() const { return getKnown(); }
3671
3672
3673 static AANonNull &createForPosition(const IRPosition &IRP, Attributor &A);
3674
3675
3676 const std::string getName() const override { return "AANonNull"; }
3677
3678
3679 const char *getIdAddr() const override { return &ID; }
3680
3681
3682 static bool classof(const AbstractAttribute *AA) {
3683 return (AA->getIdAddr() == &ID);
3684 }
3685
3686
3687 static const char ID;
3688 };
3689
3690
3691 struct AANoRecurse
3692 : public IRAttribute<Attribute::NoRecurse,
3693 StateWrapper<BooleanState, AbstractAttribute>,
3694 AANoRecurse> {
3695 AANoRecurse(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3696
3697
3698 bool isAssumedNoRecurse() const { return getAssumed(); }
3699
3700
3701 bool isKnownNoRecurse() const { return getKnown(); }
3702
3703
3704 static AANoRecurse &createForPosition(const IRPosition &IRP, Attributor &A);
3705
3706
3707 const std::string getName() const override { return "AANoRecurse"; }
3708
3709
3710 const char *getIdAddr() const override { return &ID; }
3711
3712
3713 static bool classof(const AbstractAttribute *AA) {
3714 return (AA->getIdAddr() == &ID);
3715 }
3716
3717
3718 static const char ID;
3719 };
3720
3721
3722 struct AAWillReturn
3723 : public IRAttribute<Attribute::WillReturn,
3724 StateWrapper<BooleanState, AbstractAttribute>,
3725 AAWillReturn> {
3726 AAWillReturn(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3727
3728 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3729 Attribute::AttrKind ImpliedAttributeKind,
3730 bool IgnoreSubsumingPositions = false) {
3731
3732 assert(ImpliedAttributeKind == Attribute::WillReturn);
3733 if (IRAttribute::isImpliedByIR(A, IRP, ImpliedAttributeKind,
3734 IgnoreSubsumingPositions))
3735 return true;
3736 if (!isImpliedByMustprogressAndReadonly(A, IRP))
3737 return false;
3738 A.manifestAttrs(IRP, Attribute::get(IRP.getAnchorValue().getContext(),
3739 Attribute::WillReturn));
3740 return true;
3741 }
3742
3743
3744 static bool isImpliedByMustprogressAndReadonly(Attributor &A,
3745 const IRPosition &IRP) {
3746
3747
3748 if (!A.hasAttr(IRP, {Attribute::MustProgress}))
3749 return false;
3750
3751 SmallVector<Attribute, 2> Attrs;
3752 A.getAttrs(IRP, {Attribute::Memory}, Attrs,
3753 false);
3754
3755 MemoryEffects ME = MemoryEffects::unknown();
3756 for (const Attribute &Attr : Attrs)
3757 ME &= Attr.getMemoryEffects();
3758 return ME.onlyReadsMemory();
3759 }
3760
3761
3762 bool isAssumedWillReturn() const { return getAssumed(); }
3763
3764
3765 bool isKnownWillReturn() const { return getKnown(); }
3766
3767
3768 static AAWillReturn &createForPosition(const IRPosition &IRP, Attributor &A);
3769
3770
3771 const std::string getName() const override { return "AAWillReturn"; }
3772
3773
3774 const char *getIdAddr() const override { return &ID; }
3775
3776
3777 static bool classof(const AbstractAttribute *AA) {
3778 return (AA->getIdAddr() == &ID);
3779 }
3780
3781
3782 static const char ID;
3783 };
3784
3785
3786 struct AAUndefinedBehavior
3787 : public StateWrapper<BooleanState, AbstractAttribute> {
3788 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3789 AAUndefinedBehavior(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3790
3791
3792 bool isAssumedToCauseUB() const { return getAssumed(); }
3793
3794
3795 virtual bool isAssumedToCauseUB(Instruction *I) const = 0;
3796
3797
3798 bool isKnownToCauseUB() const { return getKnown(); }
3799
3800
3801 virtual bool isKnownToCauseUB(Instruction *I) const = 0;
3802
3803
3804 static AAUndefinedBehavior &createForPosition(const IRPosition &IRP,
3805 Attributor &A);
3806
3807
3808 const std::string getName() const override { return "AAUndefinedBehavior"; }
3809
3810
3811 const char *getIdAddr() const override { return &ID; }
3812
3813
3814
3815 static bool classof(const AbstractAttribute *AA) {
3816 return (AA->getIdAddr() == &ID);
3817 }
3818
3819
3820 static const char ID;
3821 };
3822
3823
3824 struct AAIntraFnReachability
3825 : public StateWrapper<BooleanState, AbstractAttribute> {
3826 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3827 AAIntraFnReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3828
3829
3830
3831
3832 virtual bool isAssumedReachable(
3833 Attributor &A, const Instruction &From, const Instruction &To,
3834 const AA::InstExclusionSetTy *ExclusionSet = nullptr) const = 0;
3835
3836
3837 static AAIntraFnReachability &createForPosition(const IRPosition &IRP,
3838 Attributor &A);
3839
3840
3841 const std::string getName() const override { return "AAIntraFnReachability"; }
3842
3843
3844 const char *getIdAddr() const override { return &ID; }
3845
3846
3847
3848 static bool classof(const AbstractAttribute *AA) {
3849 return (AA->getIdAddr() == &ID);
3850 }
3851
3852
3853 static const char ID;
3854 };
3855
3856
3857 struct AANoAlias
3858 : public IRAttribute<Attribute::NoAlias,
3859 StateWrapper<BooleanState, AbstractAttribute>,
3860 AANoAlias> {
3861 AANoAlias(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3862
3863
3864 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3865 if (!IRP.getAssociatedType()->isPointerTy())
3866 return false;
3867 return IRAttribute::isValidIRPositionForInit(A, IRP);
3868 }
3869
3870
3871 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3872 Attribute::AttrKind ImpliedAttributeKind,
3873 bool IgnoreSubsumingPositions = false);
3874
3875
3876 static bool requiresCallersForArgOrFunction() { return true; }
3877
3878
3879 bool isAssumedNoAlias() const { return getAssumed(); }
3880
3881
3882 bool isKnownNoAlias() const { return getKnown(); }
3883
3884
3885 static AANoAlias &createForPosition(const IRPosition &IRP, Attributor &A);
3886
3887
3888 const std::string getName() const override { return "AANoAlias"; }
3889
3890
3891 const char *getIdAddr() const override { return &ID; }
3892
3893
3894 static bool classof(const AbstractAttribute *AA) {
3895 return (AA->getIdAddr() == &ID);
3896 }
3897
3898
3899 static const char ID;
3900 };
3901
3902
3903 struct AANoFree
3904 : public IRAttribute<Attribute::NoFree,
3905 StateWrapper<BooleanState, AbstractAttribute>,
3906 AANoFree> {
3907 AANoFree(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3908
3909
3910 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
3911 Attribute::AttrKind ImpliedAttributeKind,
3912 bool IgnoreSubsumingPositions = false) {
3913
3914 assert(ImpliedAttributeKind == Attribute::NoFree);
3915 return A.hasAttr(
3916 IRP, {Attribute::ReadNone, Attribute::ReadOnly, Attribute::NoFree},
3917 IgnoreSubsumingPositions, Attribute::NoFree);
3918 }
3919
3920
3921 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3922 if (!IRP.isFunctionScope() &&
3923 !IRP.getAssociatedType()->isPtrOrPtrVectorTy())
3924 return false;
3925 return IRAttribute::isValidIRPositionForInit(A, IRP);
3926 }
3927
3928
3929 bool isAssumedNoFree() const { return getAssumed(); }
3930
3931
3932 bool isKnownNoFree() const { return getKnown(); }
3933
3934
3935 static AANoFree &createForPosition(const IRPosition &IRP, Attributor &A);
3936
3937
3938 const std::string getName() const override { return "AANoFree"; }
3939
3940
3941 const char *getIdAddr() const override { return &ID; }
3942
3943
3944 static bool classof(const AbstractAttribute *AA) {
3945 return (AA->getIdAddr() == &ID);
3946 }
3947
3948
3949 static const char ID;
3950 };
3951
3952
3953 struct AANoReturn
3954 : public IRAttribute<Attribute::NoReturn,
3955 StateWrapper<BooleanState, AbstractAttribute>,
3956 AANoReturn> {
3957 AANoReturn(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
3958
3959
3960 bool isAssumedNoReturn() const { return getAssumed(); }
3961
3962
3963 bool isKnownNoReturn() const { return getKnown(); }
3964
3965
3966 static AANoReturn &createForPosition(const IRPosition &IRP, Attributor &A);
3967
3968
3969 const std::string getName() const override { return "AANoReturn"; }
3970
3971
3972 const char *getIdAddr() const override { return &ID; }
3973
3974
3975 static bool classof(const AbstractAttribute *AA) {
3976 return (AA->getIdAddr() == &ID);
3977 }
3978
3979
3980 static const char ID;
3981 };
3982
3983
3984 struct AAIsDead
3985 : public StateWrapper<BitIntegerState<uint8_t, 3, 0>, AbstractAttribute> {
3986 using Base = StateWrapper<BitIntegerState<uint8_t, 3, 0>, AbstractAttribute>;
3987 AAIsDead(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3988
3989
3990 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3991 if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION)
3992 return isa<Function>(IRP.getAnchorValue()) &&
3993 !cast<Function>(IRP.getAnchorValue()).isDeclaration();
3994 return true;
3995 }
3996
3997
3998 enum {
3999 HAS_NO_EFFECT = 1 << 0,
4000 IS_REMOVABLE = 1 << 1,
4001
4002 IS_DEAD = HAS_NO_EFFECT | IS_REMOVABLE,
4003 };
4004 static_assert(IS_DEAD == getBestState(), "Unexpected BEST_STATE value");
4005
4006 protected:
4007
4008
4009
4010
4011 virtual bool isAssumedDead() const = 0;
4012
4013
4014 virtual bool isKnownDead() const = 0;
4015
4016
4017 virtual bool isKnownDead(const BasicBlock *BB) const = 0;
4018
4019
4020 virtual bool isAssumedDead(const Instruction *I) const = 0;
4021
4022
4023 virtual bool isKnownDead(const Instruction *I) const = 0;
4024
4025
4026
4027
4028
4029 virtual bool isRemovableStore() const { return false; }
4030
4031
4032
4033 template <typename T> bool isLiveInstSet(T begin, T end) const {
4034 for (const auto &I : llvm::make_range(begin, end)) {
4035 assert(I->getFunction() == getIRPosition().getAssociatedFunction() &&
4036 "Instruction must be in the same anchor scope function.");
4037
4038 if (!isAssumedDead(I))
4039 return true;
4040 }
4041
4042 return false;
4043 }
4044
4045 public:
4046
4047 static AAIsDead &createForPosition(const IRPosition &IRP, Attributor &A);
4048
4049
4050 static bool mayCatchAsynchronousExceptions(const Function &F) {
4051 return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F);
4052 }
4053
4054
4055 virtual bool isAssumedDead(const BasicBlock *BB) const = 0;
4056
4057
4058
4059 virtual bool isEdgeDead(const BasicBlock *From, const BasicBlock *To) const {
4060 return false;
4061 }
4062
4063
4064 const std::string getName() const override { return "AAIsDead"; }
4065
4066
4067 const char *getIdAddr() const override { return &ID; }
4068
4069
4070 static bool classof(const AbstractAttribute *AA) {
4071 return (AA->getIdAddr() == &ID);
4072 }
4073
4074
4075 static const char ID;
4076
4077 friend struct Attributor;
4078 };
4079
4080
4081 struct DerefState : AbstractState {
4082
4083 static DerefState getBestState() { return DerefState(); }
4084 static DerefState getBestState(const DerefState &) { return getBestState(); }
4085
4086
4087 static DerefState getWorstState() {
4088 DerefState DS;
4089 DS.indicatePessimisticFixpoint();
4090 return DS;
4091 }
4092 static DerefState getWorstState(const DerefState &) {
4093 return getWorstState();
4094 }
4095
4096
4097 IncIntegerState<> DerefBytesState;
4098
4099
4100
4101
4102
4103
4104
4105 std::map<int64_t, uint64_t> AccessedBytesMap;
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126 void computeKnownDerefBytesFromAccessedMap() {
4127 int64_t KnownBytes = DerefBytesState.getKnown();
4128 for (auto &Access : AccessedBytesMap) {
4129 if (KnownBytes < Access.first)
4130 break;
4131 KnownBytes = std::max(KnownBytes, Access.first + (int64_t)Access.second);
4132 }
4133
4134 DerefBytesState.takeKnownMaximum(KnownBytes);
4135 }
4136
4137
4138 BooleanState GlobalState;
4139
4140
4141 bool isValidState() const override { return DerefBytesState.isValidState(); }
4142
4143
4144 bool isAtFixpoint() const override {
4145 return !isValidState() ||
4146 (DerefBytesState.isAtFixpoint() && GlobalState.isAtFixpoint());
4147 }
4148
4149
4150 ChangeStatus indicateOptimisticFixpoint() override {
4151 DerefBytesState.indicateOptimisticFixpoint();
4152 GlobalState.indicateOptimisticFixpoint();
4153 return ChangeStatus::UNCHANGED;
4154 }
4155
4156
4157 ChangeStatus indicatePessimisticFixpoint() override {
4158 DerefBytesState.indicatePessimisticFixpoint();
4159 GlobalState.indicatePessimisticFixpoint();
4160 return ChangeStatus::CHANGED;
4161 }
4162
4163
4164 void takeKnownDerefBytesMaximum(uint64_t Bytes) {
4165 DerefBytesState.takeKnownMaximum(Bytes);
4166
4167
4168 computeKnownDerefBytesFromAccessedMap();
4169 }
4170
4171
4172 void takeAssumedDerefBytesMinimum(uint64_t Bytes) {
4173 DerefBytesState.takeAssumedMinimum(Bytes);
4174 }
4175
4176
4177 void addAccessedBytes(int64_t Offset, uint64_t Size) {
4178 uint64_t &AccessedBytes = AccessedBytesMap[Offset];
4179 AccessedBytes = std::max(AccessedBytes, Size);
4180
4181
4182 computeKnownDerefBytesFromAccessedMap();
4183 }
4184
4185
4186 bool operator==(const DerefState &R) const {
4187 return this->DerefBytesState == R.DerefBytesState &&
4188 this->GlobalState == R.GlobalState;
4189 }
4190
4191
4192 bool operator!=(const DerefState &R) const { return !(*this == R); }
4193
4194
4195 DerefState operator^=(const DerefState &R) {
4196 DerefBytesState ^= R.DerefBytesState;
4197 GlobalState ^= R.GlobalState;
4198 return *this;
4199 }
4200
4201
4202 DerefState operator+=(const DerefState &R) {
4203 DerefBytesState += R.DerefBytesState;
4204 GlobalState += R.GlobalState;
4205 return *this;
4206 }
4207
4208
4209 DerefState operator&=(const DerefState &R) {
4210 DerefBytesState &= R.DerefBytesState;
4211 GlobalState &= R.GlobalState;
4212 return *this;
4213 }
4214
4215
4216 DerefState operator|=(const DerefState &R) {
4217 DerefBytesState |= R.DerefBytesState;
4218 GlobalState |= R.GlobalState;
4219 return *this;
4220 }
4221 };
4222
4223
4224 struct AADereferenceable
4225 : public IRAttribute<Attribute::Dereferenceable,
4226 StateWrapper<DerefState, AbstractAttribute>,
4227 AADereferenceable> {
4228 AADereferenceable(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
4229
4230
4231 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4232 if (!IRP.getAssociatedType()->isPointerTy())
4233 return false;
4234 return IRAttribute::isValidIRPositionForInit(A, IRP);
4235 }
4236
4237
4238
4239 bool isAssumedGlobal() const { return GlobalState.getAssumed(); }
4240
4241
4242
4243 bool isKnownGlobal() const { return GlobalState.getKnown(); }
4244
4245
4246 uint32_t getAssumedDereferenceableBytes() const {
4247 return DerefBytesState.getAssumed();
4248 }
4249
4250
4251 uint32_t getKnownDereferenceableBytes() const {
4252 return DerefBytesState.getKnown();
4253 }
4254
4255
4256 static AADereferenceable &createForPosition(const IRPosition &IRP,
4257 Attributor &A);
4258
4259
4260 const std::string getName() const override { return "AADereferenceable"; }
4261
4262
4263 const char *getIdAddr() const override { return &ID; }
4264
4265
4266
4267 static bool classof(const AbstractAttribute *AA) {
4268 return (AA->getIdAddr() == &ID);
4269 }
4270
4271
4272 static const char ID;
4273 };
4274
4275 using AAAlignmentStateType =
4276 IncIntegerState<uint64_t, Value::MaximumAlignment, 1>;
4277
4278 struct AAAlign
4279 : public IRAttribute<Attribute::Alignment,
4280 StateWrapper<AAAlignmentStateType, AbstractAttribute>,
4281 AAAlign> {
4282 AAAlign(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
4283
4284
4285 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4286 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
4287 return false;
4288 return IRAttribute::isValidIRPositionForInit(A, IRP);
4289 }
4290
4291
4292 Align getAssumedAlign() const { return Align(getAssumed()); }
4293
4294
4295 Align getKnownAlign() const { return Align(getKnown()); }
4296
4297
4298 const std::string getName() const override { return "AAAlign"; }
4299
4300
4301 const char *getIdAddr() const override { return &ID; }
4302
4303
4304 static bool classof(const AbstractAttribute *AA) {
4305 return (AA->getIdAddr() == &ID);
4306 }
4307
4308
4309 static AAAlign &createForPosition(const IRPosition &IRP, Attributor &A);
4310
4311
4312 static const char ID;
4313 };
4314
4315
4316
4317
4318
4319 struct AAInstanceInfo : public StateWrapper<BooleanState, AbstractAttribute> {
4320 AAInstanceInfo(const IRPosition &IRP, Attributor &A)
4321 : StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
4322
4323
4324
4325
4326
4327 bool isKnownUniqueForAnalysis() const { return isKnown(); }
4328
4329
4330
4331
4332
4333 bool isAssumedUniqueForAnalysis() const { return isAssumed(); }
4334
4335
4336 static AAInstanceInfo &createForPosition(const IRPosition &IRP,
4337 Attributor &A);
4338
4339
4340 const std::string getName() const override { return "AAInstanceInfo"; }
4341
4342
4343 const char *getIdAddr() const override { return &ID; }
4344
4345
4346
4347 static bool classof(const AbstractAttribute *AA) {
4348 return (AA->getIdAddr() == &ID);
4349 }
4350
4351
4352 static const char ID;
4353 };
4354
4355
4356 struct AANoCapture
4357 : public IRAttribute<
4358 Attribute::NoCapture,
4359 StateWrapper<BitIntegerState<uint16_t, 7, 0>, AbstractAttribute>,
4360 AANoCapture> {
4361 AANoCapture(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
4362
4363
4364 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
4365 Attribute::AttrKind ImpliedAttributeKind,
4366 bool IgnoreSubsumingPositions = false);
4367
4368
4369
4370 static void determineFunctionCaptureCapabilities(const IRPosition &IRP,
4371 const Function &F,
4372 BitIntegerState &State);
4373
4374
4375 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4376 if (!IRP.getAssociatedType()->isPointerTy())
4377 return false;
4378 return IRAttribute::isValidIRPositionForInit(A, IRP);
4379 }
4380
4381
4382
4383 enum {
4384 NOT_CAPTURED_IN_MEM = 1 << 0,
4385 NOT_CAPTURED_IN_INT = 1 << 1,
4386 NOT_CAPTURED_IN_RET = 1 << 2,
4387
4388
4389
4390 NO_CAPTURE_MAYBE_RETURNED = NOT_CAPTURED_IN_MEM | NOT_CAPTURED_IN_INT,
4391
4392
4393
4394 NO_CAPTURE =
4395 NOT_CAPTURED_IN_MEM | NOT_CAPTURED_IN_INT | NOT_CAPTURED_IN_RET,
4396 };
4397
4398
4399
4400 bool isKnownNoCapture() const { return isKnown(NO_CAPTURE); }
4401
4402
4403
4404 bool isAssumedNoCapture() const { return isAssumed(NO_CAPTURE); }
4405
4406
4407
4408 bool isKnownNoCaptureMaybeReturned() const {
4409 return isKnown(NO_CAPTURE_MAYBE_RETURNED);
4410 }
4411
4412
4413
4414 bool isAssumedNoCaptureMaybeReturned() const {
4415 return isAssumed(NO_CAPTURE_MAYBE_RETURNED);
4416 }
4417
4418
4419 static AANoCapture &createForPosition(const IRPosition &IRP, Attributor &A);
4420
4421
4422 const std::string getName() const override { return "AANoCapture"; }
4423
4424
4425 const char *getIdAddr() const override { return &ID; }
4426
4427
4428 static bool classof(const AbstractAttribute *AA) {
4429 return (AA->getIdAddr() == &ID);
4430 }
4431
4432
4433 static const char ID;
4434 };
4435
4436 struct ValueSimplifyStateType : public AbstractState {
4437
4438 ValueSimplifyStateType(Type *Ty) : Ty(Ty) {}
4439
4440 static ValueSimplifyStateType getBestState(Type *Ty) {
4441 return ValueSimplifyStateType(Ty);
4442 }
4443 static ValueSimplifyStateType getBestState(const ValueSimplifyStateType &VS) {
4444 return getBestState(VS.Ty);
4445 }
4446
4447
4448 static ValueSimplifyStateType getWorstState(Type *Ty) {
4449 ValueSimplifyStateType DS(Ty);
4450 DS.indicatePessimisticFixpoint();
4451 return DS;
4452 }
4453 static ValueSimplifyStateType
4454 getWorstState(const ValueSimplifyStateType &VS) {
4455 return getWorstState(VS.Ty);
4456 }
4457
4458
4459 bool isValidState() const override { return BS.isValidState(); }
4460
4461
4462 bool isAtFixpoint() const override { return BS.isAtFixpoint(); }
4463
4464
4465 ValueSimplifyStateType getAssumed() { return *this; }
4466 const ValueSimplifyStateType &getAssumed() const { return *this; }
4467
4468
4469 ChangeStatus indicatePessimisticFixpoint() override {
4470 return BS.indicatePessimisticFixpoint();
4471 }
4472
4473
4474 ChangeStatus indicateOptimisticFixpoint() override {
4475 return BS.indicateOptimisticFixpoint();
4476 }
4477
4478
4479 ValueSimplifyStateType operator^=(const ValueSimplifyStateType &VS) {
4480 BS ^= VS.BS;
4481 unionAssumed(VS.SimplifiedAssociatedValue);
4482 return *this;
4483 }
4484
4485 bool operator==(const ValueSimplifyStateType &RHS) const {
4486 if (isValidState() != RHS.isValidState())
4487 return false;
4488 if (!isValidState() && !RHS.isValidState())
4489 return true;
4490 return SimplifiedAssociatedValue == RHS.SimplifiedAssociatedValue;
4491 }
4492
4493 protected:
4494
4495 Type *Ty;
4496
4497
4498 bool unionAssumed(std::optional<Value *> Other);
4499
4500
4501 BooleanState BS;
4502
4503
4504
4505
4506
4507 std::optional<Value *> SimplifiedAssociatedValue;
4508 };
4509
4510
4511 struct AAValueSimplify
4512 : public StateWrapper<ValueSimplifyStateType, AbstractAttribute, Type *> {
4513 using Base = StateWrapper<ValueSimplifyStateType, AbstractAttribute, Type *>;
4514 AAValueSimplify(const IRPosition &IRP, Attributor &A)
4515 : Base(IRP, IRP.getAssociatedType()) {}
4516
4517
4518 static AAValueSimplify &createForPosition(const IRPosition &IRP,
4519 Attributor &A);
4520
4521
4522 const std::string getName() const override { return "AAValueSimplify"; }
4523
4524
4525 const char *getIdAddr() const override { return &ID; }
4526
4527
4528
4529 static bool classof(const AbstractAttribute *AA) {
4530 return (AA->getIdAddr() == &ID);
4531 }
4532
4533
4534 static const char ID;
4535
4536 private:
4537
4538
4539
4540
4541
4542 virtual std::optional<Value *>
4543 getAssumedSimplifiedValue(Attributor &A) const = 0;
4544
4545 friend struct Attributor;
4546 };
4547
4548 struct AAHeapToStack : public StateWrapper<BooleanState, AbstractAttribute> {
4549 using Base = StateWrapper<BooleanState, AbstractAttribute>;
4550 AAHeapToStack(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
4551
4552
4553 virtual bool isAssumedHeapToStack(const CallBase &CB) const = 0;
4554
4555
4556
4557 virtual bool isAssumedHeapToStackRemovedFree(CallBase &CB) const = 0;
4558
4559
4560 static AAHeapToStack &createForPosition(const IRPosition &IRP, Attributor &A);
4561
4562
4563 const std::string getName() const override { return "AAHeapToStack"; }
4564
4565
4566 const char *getIdAddr() const override { return &ID; }
4567
4568
4569 static bool classof(const AbstractAttribute *AA) {
4570 return (AA->getIdAddr() == &ID);
4571 }
4572
4573
4574 static const char ID;
4575 };
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587 struct AAPrivatizablePtr
4588 : public StateWrapper<BooleanState, AbstractAttribute> {
4589 using Base = StateWrapper<BooleanState, AbstractAttribute>;
4590 AAPrivatizablePtr(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
4591
4592
4593 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4594 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
4595 return false;
4596 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
4597 }
4598
4599
4600 bool isAssumedPrivatizablePtr() const { return getAssumed(); }
4601
4602
4603 bool isKnownPrivatizablePtr() const { return getKnown(); }
4604
4605
4606 static bool requiresCallersForArgOrFunction() { return true; }
4607
4608
4609
4610
4611 virtual std::optional<Type *> getPrivatizableType() const = 0;
4612
4613
4614 static AAPrivatizablePtr &createForPosition(const IRPosition &IRP,
4615 Attributor &A);
4616
4617
4618 const std::string getName() const override { return "AAPrivatizablePtr"; }
4619
4620
4621 const char *getIdAddr() const override { return &ID; }
4622
4623
4624
4625 static bool classof(const AbstractAttribute *AA) {
4626 return (AA->getIdAddr() == &ID);
4627 }
4628
4629
4630 static const char ID;
4631 };
4632
4633
4634
4635 struct AAMemoryBehavior
4636 : public IRAttribute<
4637 Attribute::None,
4638 StateWrapper<BitIntegerState<uint8_t, 3>, AbstractAttribute>,
4639 AAMemoryBehavior> {
4640 AAMemoryBehavior(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
4641
4642
4643 static bool hasTrivialInitializer() { return false; }
4644
4645
4646 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4647 if (!IRP.isFunctionScope() && !IRP.getAssociatedType()->isPointerTy())
4648 return false;
4649 return IRAttribute::isValidIRPositionForInit(A, IRP);
4650 }
4651
4652
4653
4654 enum {
4655 NO_READS = 1 << 0,
4656 NO_WRITES = 1 << 1,
4657 NO_ACCESSES = NO_READS | NO_WRITES,
4658
4659 BEST_STATE = NO_ACCESSES,
4660 };
4661 static_assert(BEST_STATE == getBestState(), "Unexpected BEST_STATE value");
4662
4663
4664
4665 bool isKnownReadNone() const { return isKnown(NO_ACCESSES); }
4666
4667
4668
4669 bool isAssumedReadNone() const { return isAssumed(NO_ACCESSES); }
4670
4671
4672
4673 bool isKnownReadOnly() const { return isKnown(NO_WRITES); }
4674
4675
4676
4677 bool isAssumedReadOnly() const { return isAssumed(NO_WRITES); }
4678
4679
4680
4681 bool isKnownWriteOnly() const { return isKnown(NO_READS); }
4682
4683
4684
4685 bool isAssumedWriteOnly() const { return isAssumed(NO_READS); }
4686
4687
4688 static AAMemoryBehavior &createForPosition(const IRPosition &IRP,
4689 Attributor &A);
4690
4691
4692 const std::string getName() const override { return "AAMemoryBehavior"; }
4693
4694
4695 const char *getIdAddr() const override { return &ID; }
4696
4697
4698
4699 static bool classof(const AbstractAttribute *AA) {
4700 return (AA->getIdAddr() == &ID);
4701 }
4702
4703
4704 static const char ID;
4705 };
4706
4707
4708
4709 struct AAMemoryLocation
4710 : public IRAttribute<
4711 Attribute::None,
4712 StateWrapper<BitIntegerState<uint32_t, 511>, AbstractAttribute>,
4713 AAMemoryLocation> {
4714 using MemoryLocationsKind = StateType::base_t;
4715
4716 AAMemoryLocation(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
4717
4718
4719 static bool requiresCalleeForCallBase() { return true; }
4720
4721
4722 static bool hasTrivialInitializer() { return false; }
4723
4724
4725 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4726 if (!IRP.isFunctionScope() &&
4727 !IRP.getAssociatedType()->isPtrOrPtrVectorTy())
4728 return false;
4729 return IRAttribute::isValidIRPositionForInit(A, IRP);
4730 }
4731
4732
4733
4734 enum {
4735 ALL_LOCATIONS = 0,
4736 NO_LOCAL_MEM = 1 << 0,
4737 NO_CONST_MEM = 1 << 1,
4738 NO_GLOBAL_INTERNAL_MEM = 1 << 2,
4739 NO_GLOBAL_EXTERNAL_MEM = 1 << 3,
4740 NO_GLOBAL_MEM = NO_GLOBAL_INTERNAL_MEM | NO_GLOBAL_EXTERNAL_MEM,
4741 NO_ARGUMENT_MEM = 1 << 4,
4742 NO_INACCESSIBLE_MEM = 1 << 5,
4743 NO_MALLOCED_MEM = 1 << 6,
4744 NO_UNKOWN_MEM = 1 << 7,
4745 NO_LOCATIONS = NO_LOCAL_MEM | NO_CONST_MEM | NO_GLOBAL_INTERNAL_MEM |
4746 NO_GLOBAL_EXTERNAL_MEM | NO_ARGUMENT_MEM |
4747 NO_INACCESSIBLE_MEM | NO_MALLOCED_MEM | NO_UNKOWN_MEM,
4748
4749
4750 VALID_STATE = NO_LOCATIONS + 1,
4751
4752 BEST_STATE = NO_LOCATIONS | VALID_STATE,
4753 };
4754 static_assert(BEST_STATE == getBestState(), "Unexpected BEST_STATE value");
4755
4756
4757
4758 bool isKnownReadNone() const { return isKnown(NO_LOCATIONS); }
4759
4760
4761
4762 bool isAssumedReadNone() const {
4763 return isAssumed(NO_LOCATIONS) || isAssumedStackOnly();
4764 }
4765
4766
4767
4768 bool isKnowStackOnly() const {
4769 return isKnown(inverseLocation(NO_LOCAL_MEM, true, true));
4770 }
4771
4772
4773
4774 bool isAssumedStackOnly() const {
4775 return isAssumed(inverseLocation(NO_LOCAL_MEM, true, true));
4776 }
4777
4778
4779
4780 bool isKnownInaccessibleMemOnly() const {
4781 return isKnown(inverseLocation(NO_INACCESSIBLE_MEM, true, true));
4782 }
4783
4784
4785
4786 bool isAssumedInaccessibleMemOnly() const {
4787 return isAssumed(inverseLocation(NO_INACCESSIBLE_MEM, true, true));
4788 }
4789
4790
4791
4792 bool isKnownArgMemOnly() const {
4793 return isKnown(inverseLocation(NO_ARGUMENT_MEM, true, true));
4794 }
4795
4796
4797
4798 bool isAssumedArgMemOnly() const {
4799 return isAssumed(inverseLocation(NO_ARGUMENT_MEM, true, true));
4800 }
4801
4802
4803
4804
4805 bool isKnownInaccessibleOrArgMemOnly() const {
4806 return isKnown(
4807 inverseLocation(NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM, true, true));
4808 }
4809
4810
4811
4812
4813 bool isAssumedInaccessibleOrArgMemOnly() const {
4814 return isAssumed(
4815 inverseLocation(NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM, true, true));
4816 }
4817
4818
4819
4820 bool mayAccessArgMem() const { return !isAssumed(NO_ARGUMENT_MEM); }
4821
4822
4823
4824 bool isAssumedSpecifiedMemOnly(MemoryLocationsKind MLK) const {
4825 return isAssumed(MLK);
4826 }
4827
4828
4829
4830 MemoryLocationsKind getAssumedNotAccessedLocation() const {
4831 return getAssumed();
4832 }
4833
4834
4835
4836
4837
4838
4839 static MemoryLocationsKind
4840 inverseLocation(MemoryLocationsKind Loc, bool AndLocalMem, bool AndConstMem) {
4841 return NO_LOCATIONS & ~(Loc | (AndLocalMem ? NO_LOCAL_MEM : 0) |
4842 (AndConstMem ? NO_CONST_MEM : 0));
4843 };
4844
4845
4846 static std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK);
4847
4848
4849 enum AccessKind {
4850 NONE = 0,
4851 READ = 1 << 0,
4852 WRITE = 1 << 1,
4853 READ_WRITE = READ | WRITE,
4854 };
4855
4856
4857
4858
4859
4860
4861 virtual bool checkForAllAccessesToMemoryKind(
4862 function_ref<bool(const Instruction *, const Value *, AccessKind,
4863 MemoryLocationsKind)>
4864 Pred,
4865 MemoryLocationsKind MLK) const = 0;
4866
4867
4868 static AAMemoryLocation &createForPosition(const IRPosition &IRP,
4869 Attributor &A);
4870
4871
4872 const std::string getAsStr(Attributor *A) const override {
4873 return getMemoryLocationsAsStr(getAssumedNotAccessedLocation());
4874 }
4875
4876
4877 const std::string getName() const override { return "AAMemoryLocation"; }
4878
4879
4880 const char *getIdAddr() const override { return &ID; }
4881
4882
4883
4884 static bool classof(const AbstractAttribute *AA) {
4885 return (AA->getIdAddr() == &ID);
4886 }
4887
4888
4889 static const char ID;
4890 };
4891
4892
4893 struct AAValueConstantRange
4894 : public StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t> {
4895 using Base = StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t>;
4896 AAValueConstantRange(const IRPosition &IRP, Attributor &A)
4897 : Base(IRP, IRP.getAssociatedType()->getIntegerBitWidth()) {}
4898
4899
4900 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
4901 if (!IRP.getAssociatedType()->isIntegerTy())
4902 return false;
4903 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
4904 }
4905
4906
4907 static bool requiresCallersForArgOrFunction() { return true; }
4908
4909
4910 IntegerRangeState &getState() override { return *this; }
4911 const IntegerRangeState &getState() const override { return *this; }
4912
4913
4914 static AAValueConstantRange &createForPosition(const IRPosition &IRP,
4915 Attributor &A);
4916
4917
4918
4919 virtual ConstantRange
4920 getAssumedConstantRange(Attributor &A,
4921 const Instruction *CtxI = nullptr) const = 0;
4922
4923
4924
4925 virtual ConstantRange
4926 getKnownConstantRange(Attributor &A,
4927 const Instruction *CtxI = nullptr) const = 0;
4928
4929
4930
4931 std::optional<Constant *>
4932 getAssumedConstant(Attributor &A, const Instruction *CtxI = nullptr) const {
4933 ConstantRange RangeV = getAssumedConstantRange(A, CtxI);
4934 if (auto *C = RangeV.getSingleElement()) {
4935 Type *Ty = getAssociatedValue().getType();
4936 return cast_or_null<Constant>(
4937 AA::getWithType(*ConstantInt::get(Ty->getContext(), *C), *Ty));
4938 }
4939 if (RangeV.isEmptySet())
4940 return std::nullopt;
4941 return nullptr;
4942 }
4943
4944
4945 const std::string getName() const override { return "AAValueConstantRange"; }
4946
4947
4948 const char *getIdAddr() const override { return &ID; }
4949
4950
4951
4952 static bool classof(const AbstractAttribute *AA) {
4953 return (AA->getIdAddr() == &ID);
4954 }
4955
4956
4957 static const char ID;
4958 };
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968 template <typename MemberTy> struct PotentialValuesState : AbstractState {
4969 using SetTy = SmallSetVector<MemberTy, 8>;
4970
4971 PotentialValuesState() : IsValidState(true), UndefIsContained(false) {}
4972
4973 PotentialValuesState(bool IsValid)
4974 : IsValidState(IsValid), UndefIsContained(false) {}
4975
4976
4977 bool isValidState() const override { return IsValidState.isValidState(); }
4978
4979
4980 bool isAtFixpoint() const override { return IsValidState.isAtFixpoint(); }
4981
4982
4983 ChangeStatus indicatePessimisticFixpoint() override {
4984 return IsValidState.indicatePessimisticFixpoint();
4985 }
4986
4987
4988 ChangeStatus indicateOptimisticFixpoint() override {
4989 return IsValidState.indicateOptimisticFixpoint();
4990 }
4991
4992
4993 PotentialValuesState &getAssumed() { return *this; }
4994 const PotentialValuesState &getAssumed() const { return *this; }
4995
4996
4997
4998 const SetTy &getAssumedSet() const {
4999 assert(isValidState() && "This set shoud not be used when it is invalid!");
5000 return Set;
5001 }
5002
5003
5004 bool undefIsContained() const {
5005 assert(isValidState() && "This flag shoud not be used when it is invalid!");
5006 return UndefIsContained;
5007 }
5008
5009 bool operator==(const PotentialValuesState &RHS) const {
5010 if (isValidState() != RHS.isValidState())
5011 return false;
5012 if (!isValidState() && !RHS.isValidState())
5013 return true;
5014 if (undefIsContained() != RHS.undefIsContained())
5015 return false;
5016 return Set == RHS.getAssumedSet();
5017 }
5018
5019
5020
5021 static unsigned MaxPotentialValues;
5022
5023
5024 static PotentialValuesState getBestState() {
5025 return PotentialValuesState(true);
5026 }
5027
5028 static PotentialValuesState getBestState(const PotentialValuesState &PVS) {
5029 return getBestState();
5030 }
5031
5032
5033 static PotentialValuesState getWorstState() {
5034 return PotentialValuesState(false);
5035 }
5036
5037
5038 void unionAssumed(const MemberTy &C) { insert(C); }
5039
5040
5041 void unionAssumed(const PotentialValuesState &PVS) { unionWith(PVS); }
5042
5043
5044 void unionAssumedWithUndef() { unionWithUndef(); }
5045
5046
5047 PotentialValuesState operator^=(const PotentialValuesState &PVS) {
5048 IsValidState ^= PVS.IsValidState;
5049 unionAssumed(PVS);
5050 return *this;
5051 }
5052
5053 PotentialValuesState operator&=(const PotentialValuesState &PVS) {
5054 IsValidState &= PVS.IsValidState;
5055 unionAssumed(PVS);
5056 return *this;
5057 }
5058
5059 bool contains(const MemberTy &V) const {
5060 return !isValidState() ? true : Set.contains(V);
5061 }
5062
5063 protected:
5064 SetTy &getAssumedSet() {
5065 assert(isValidState() && "This set shoud not be used when it is invalid!");
5066 return Set;
5067 }
5068
5069 private:
5070
5071
5072 void checkAndInvalidate() {
5073 if (Set.size() >= MaxPotentialValues)
5074 indicatePessimisticFixpoint();
5075 else
5076 reduceUndefValue();
5077 }
5078
5079
5080
5081 void reduceUndefValue() { UndefIsContained = UndefIsContained & Set.empty(); }
5082
5083
5084 void insert(const MemberTy &C) {
5085 if (!isValidState())
5086 return;
5087 Set.insert(C);
5088 checkAndInvalidate();
5089 }
5090
5091
5092 void unionWith(const PotentialValuesState &R) {
5093
5094 if (!isValidState())
5095 return;
5096
5097 if (!R.isValidState()) {
5098 indicatePessimisticFixpoint();
5099 return;
5100 }
5101 for (const MemberTy &C : R.Set)
5102 Set.insert(C);
5103 UndefIsContained |= R.undefIsContained();
5104 checkAndInvalidate();
5105 }
5106
5107
5108 void unionWithUndef() {
5109 UndefIsContained = true;
5110 reduceUndefValue();
5111 }
5112
5113
5114 void intersectWith(const PotentialValuesState &R) {
5115
5116 if (!R.isValidState())
5117 return;
5118
5119 if (!isValidState()) {
5120 *this = R;
5121 return;
5122 }
5123 SetTy IntersectSet;
5124 for (const MemberTy &C : Set) {
5125 if (R.Set.count(C))
5126 IntersectSet.insert(C);
5127 }
5128 Set = IntersectSet;
5129 UndefIsContained &= R.undefIsContained();
5130 reduceUndefValue();
5131 }
5132
5133
5134 BooleanState IsValidState;
5135
5136
5137 SetTy Set;
5138
5139
5140 bool UndefIsContained;
5141 };
5142
5143 struct DenormalFPMathState : public AbstractState {
5144 struct DenormalState {
5145 DenormalMode Mode = DenormalMode::getInvalid();
5146 DenormalMode ModeF32 = DenormalMode::getInvalid();
5147
5148 bool operator==(const DenormalState Other) const {
5149 return Mode == Other.Mode && ModeF32 == Other.ModeF32;
5150 }
5151
5152 bool operator!=(const DenormalState Other) const {
5153 return Mode != Other.Mode || ModeF32 != Other.ModeF32;
5154 }
5155
5156 bool isValid() const { return Mode.isValid() && ModeF32.isValid(); }
5157
5158 static DenormalMode::DenormalModeKind
5159 unionDenormalKind(DenormalMode::DenormalModeKind Callee,
5160 DenormalMode::DenormalModeKind Caller) {
5161 if (Caller == Callee)
5162 return Caller;
5163 if (Callee == DenormalMode::Dynamic)
5164 return Caller;
5165 if (Caller == DenormalMode::Dynamic)
5166 return Callee;
5167 return DenormalMode::Invalid;
5168 }
5169
5170 static DenormalMode unionAssumed(DenormalMode Callee, DenormalMode Caller) {
5171 return DenormalMode{unionDenormalKind(Callee.Output, Caller.Output),
5172 unionDenormalKind(Callee.Input, Caller.Input)};
5173 }
5174
5175 DenormalState unionWith(DenormalState Caller) const {
5176 DenormalState Callee(*this);
5177 Callee.Mode = unionAssumed(Callee.Mode, Caller.Mode);
5178 Callee.ModeF32 = unionAssumed(Callee.ModeF32, Caller.ModeF32);
5179 return Callee;
5180 }
5181 };
5182
5183 DenormalState Known;
5184
5185
5186 bool IsAtFixedpoint = false;
5187
5188 DenormalFPMathState() = default;
5189
5190 DenormalState getKnown() const { return Known; }
5191
5192
5193
5194 DenormalState getAssumed() const { return Known; }
5195
5196 bool isValidState() const override { return Known.isValid(); }
5197
5198
5199
5200 bool isModeFixed() const {
5201 return Known.Mode.Input != DenormalMode::Dynamic &&
5202 Known.Mode.Output != DenormalMode::Dynamic &&
5203 Known.ModeF32.Input != DenormalMode::Dynamic &&
5204 Known.ModeF32.Output != DenormalMode::Dynamic;
5205 }
5206
5207 bool isAtFixpoint() const override { return IsAtFixedpoint; }
5208
5209 ChangeStatus indicateFixpoint() {
5210 bool Changed = !IsAtFixedpoint;
5211 IsAtFixedpoint = true;
5212 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
5213 }
5214
5215 ChangeStatus indicateOptimisticFixpoint() override {
5216 return indicateFixpoint();
5217 }
5218
5219 ChangeStatus indicatePessimisticFixpoint() override {
5220 return indicateFixpoint();
5221 }
5222
5223 DenormalFPMathState operator^=(const DenormalFPMathState &Caller) {
5224 Known = Known.unionWith(Caller.getKnown());
5225 return *this;
5226 }
5227 };
5228
5229 using PotentialConstantIntValuesState = PotentialValuesState<APInt>;
5230 using PotentialLLVMValuesState =
5231 PotentialValuesState<std::pair<AA::ValueAndContext, AA::ValueScope>>;
5232
5233 raw_ostream &operator<<(raw_ostream &OS,
5234 const PotentialConstantIntValuesState &R);
5235 raw_ostream &operator<<(raw_ostream &OS, const PotentialLLVMValuesState &R);
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252 struct AAPotentialConstantValues
5253 : public StateWrapper<PotentialConstantIntValuesState, AbstractAttribute> {
5254 using Base = StateWrapper<PotentialConstantIntValuesState, AbstractAttribute>;
5255 AAPotentialConstantValues(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5256
5257
5258 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
5259 if (!IRP.getAssociatedType()->isIntegerTy())
5260 return false;
5261 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
5262 }
5263
5264
5265 static bool requiresCallersForArgOrFunction() { return true; }
5266
5267
5268 PotentialConstantIntValuesState &getState() override { return *this; }
5269 const PotentialConstantIntValuesState &getState() const override {
5270 return *this;
5271 }
5272
5273
5274 static AAPotentialConstantValues &createForPosition(const IRPosition &IRP,
5275 Attributor &A);
5276
5277
5278 std::optional<Constant *>
5279 getAssumedConstant(Attributor &A, const Instruction *CtxI = nullptr) const {
5280 if (!isValidState())
5281 return nullptr;
5282 if (getAssumedSet().size() == 1) {
5283 Type *Ty = getAssociatedValue().getType();
5284 return cast_or_null<Constant>(AA::getWithType(
5285 *ConstantInt::get(Ty->getContext(), *(getAssumedSet().begin())),
5286 *Ty));
5287 }
5288 if (getAssumedSet().size() == 0) {
5289 if (undefIsContained())
5290 return UndefValue::get(getAssociatedValue().getType());
5291 return std::nullopt;
5292 }
5293
5294 return nullptr;
5295 }
5296
5297
5298 const std::string getName() const override {
5299 return "AAPotentialConstantValues";
5300 }
5301
5302
5303 const char *getIdAddr() const override { return &ID; }
5304
5305
5306
5307 static bool classof(const AbstractAttribute *AA) {
5308 return (AA->getIdAddr() == &ID);
5309 }
5310
5311
5312 static const char ID;
5313 };
5314
5315 struct AAPotentialValues
5316 : public StateWrapper<PotentialLLVMValuesState, AbstractAttribute> {
5317 using Base = StateWrapper<PotentialLLVMValuesState, AbstractAttribute>;
5318 AAPotentialValues(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5319
5320
5321 static bool requiresCallersForArgOrFunction() { return true; }
5322
5323
5324 PotentialLLVMValuesState &getState() override { return *this; }
5325 const PotentialLLVMValuesState &getState() const override { return *this; }
5326
5327
5328 static AAPotentialValues &createForPosition(const IRPosition &IRP,
5329 Attributor &A);
5330
5331
5332 static Value *getSingleValue(Attributor &A, const AbstractAttribute &AA,
5333 const IRPosition &IRP,
5334 SmallVectorImpl<AA::ValueAndContext> &Values);
5335
5336
5337 const std::string getName() const override { return "AAPotentialValues"; }
5338
5339
5340 const char *getIdAddr() const override { return &ID; }
5341
5342
5343
5344 static bool classof(const AbstractAttribute *AA) {
5345 return (AA->getIdAddr() == &ID);
5346 }
5347
5348
5349 static const char ID;
5350
5351 private:
5352 virtual bool getAssumedSimplifiedValues(
5353 Attributor &A, SmallVectorImpl<AA::ValueAndContext> &Values,
5354 AA::ValueScope, bool RecurseForSelectAndPHI = false) const = 0;
5355
5356 friend struct Attributor;
5357 };
5358
5359
5360 struct AANoUndef
5361 : public IRAttribute<Attribute::NoUndef,
5362 StateWrapper<BooleanState, AbstractAttribute>,
5363 AANoUndef> {
5364 AANoUndef(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
5365
5366
5367 static bool isImpliedByUndef() { return false; }
5368
5369
5370 static bool isImpliedByPoison() { return false; }
5371
5372
5373 static bool isImpliedByIR(Attributor &A, const IRPosition &IRP,
5374 Attribute::AttrKind ImpliedAttributeKind,
5375 bool IgnoreSubsumingPositions = false);
5376
5377
5378 bool isAssumedNoUndef() const { return getAssumed(); }
5379
5380
5381 bool isKnownNoUndef() const { return getKnown(); }
5382
5383
5384 static AANoUndef &createForPosition(const IRPosition &IRP, Attributor &A);
5385
5386
5387 const std::string getName() const override { return "AANoUndef"; }
5388
5389
5390 const char *getIdAddr() const override { return &ID; }
5391
5392
5393 static bool classof(const AbstractAttribute *AA) {
5394 return (AA->getIdAddr() == &ID);
5395 }
5396
5397
5398 static const char ID;
5399 };
5400
5401 struct AANoFPClass
5402 : public IRAttribute<
5403 Attribute::NoFPClass,
5404 StateWrapper<BitIntegerState<uint32_t, fcAllFlags, fcNone>,
5405 AbstractAttribute>,
5406 AANoFPClass> {
5407 using Base = StateWrapper<BitIntegerState<uint32_t, fcAllFlags, fcNone>,
5408 AbstractAttribute>;
5409
5410 AANoFPClass(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
5411
5412
5413 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
5414 Type *Ty = IRP.getAssociatedType();
5415 do {
5416 if (Ty->isFPOrFPVectorTy())
5417 return IRAttribute::isValidIRPositionForInit(A, IRP);
5418 if (!Ty->isArrayTy())
5419 break;
5420 Ty = Ty->getArrayElementType();
5421 } while (true);
5422 return false;
5423 }
5424
5425
5426 FPClassTest getAssumedNoFPClass() const {
5427 return static_cast<FPClassTest>(getAssumed());
5428 }
5429
5430 FPClassTest getKnownNoFPClass() const {
5431 return static_cast<FPClassTest>(getKnown());
5432 }
5433
5434
5435 static AANoFPClass &createForPosition(const IRPosition &IRP, Attributor &A);
5436
5437
5438 const std::string getName() const override { return "AANoFPClass"; }
5439
5440
5441 const char *getIdAddr() const override { return &ID; }
5442
5443
5444 static bool classof(const AbstractAttribute *AA) {
5445 return (AA->getIdAddr() == &ID);
5446 }
5447
5448
5449 static const char ID;
5450 };
5451
5452 struct AACallGraphNode;
5453 struct AACallEdges;
5454
5455
5456
5457
5458 class AACallEdgeIterator
5459 : public iterator_adaptor_base<AACallEdgeIterator,
5460 SetVector<Function *>::iterator> {
5461 AACallEdgeIterator(Attributor &A, SetVector<Function *>::iterator Begin)
5462 : iterator_adaptor_base(Begin), A(A) {}
5463
5464 public:
5465 AACallGraphNode *operator*() const;
5466
5467 private:
5468 Attributor &A;
5469 friend AACallEdges;
5470 friend AttributorCallGraph;
5471 };
5472
5473 struct AACallGraphNode {
5474 AACallGraphNode(Attributor &A) : A(A) {}
5475 virtual ~AACallGraphNode() = default;
5476
5477 virtual AACallEdgeIterator optimisticEdgesBegin() const = 0;
5478 virtual AACallEdgeIterator optimisticEdgesEnd() const = 0;
5479
5480
5481 iterator_range<AACallEdgeIterator> optimisticEdgesRange() const {
5482 return iterator_range<AACallEdgeIterator>(optimisticEdgesBegin(),
5483 optimisticEdgesEnd());
5484 }
5485
5486 protected:
5487
5488 Attributor &A;
5489 };
5490
5491
5492
5493
5494 struct AACallEdges : public StateWrapper<BooleanState, AbstractAttribute>,
5495 AACallGraphNode {
5496 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5497
5498 AACallEdges(const IRPosition &IRP, Attributor &A)
5499 : Base(IRP), AACallGraphNode(A) {}
5500
5501
5502 static bool requiresNonAsmForCallBase() { return false; }
5503
5504
5505 virtual const SetVector<Function *> &getOptimisticEdges() const = 0;
5506
5507
5508 virtual bool hasUnknownCallee() const = 0;
5509
5510
5511 virtual bool hasNonAsmUnknownCallee() const = 0;
5512
5513
5514 AACallEdgeIterator optimisticEdgesBegin() const override {
5515 return AACallEdgeIterator(A, getOptimisticEdges().begin());
5516 }
5517
5518
5519 AACallEdgeIterator optimisticEdgesEnd() const override {
5520 return AACallEdgeIterator(A, getOptimisticEdges().end());
5521 }
5522
5523
5524 static AACallEdges &createForPosition(const IRPosition &IRP, Attributor &A);
5525
5526
5527 const std::string getName() const override { return "AACallEdges"; }
5528
5529
5530 const char *getIdAddr() const override { return &ID; }
5531
5532
5533 static bool classof(const AbstractAttribute *AA) {
5534 return (AA->getIdAddr() == &ID);
5535 }
5536
5537
5538 static const char ID;
5539 };
5540
5541
5542 struct AttributorCallGraph : public AACallGraphNode {
5543 AttributorCallGraph(Attributor &A) : AACallGraphNode(A) {}
5544 virtual ~AttributorCallGraph() = default;
5545
5546 AACallEdgeIterator optimisticEdgesBegin() const override {
5547 return AACallEdgeIterator(A, A.Functions.begin());
5548 }
5549
5550 AACallEdgeIterator optimisticEdgesEnd() const override {
5551 return AACallEdgeIterator(A, A.Functions.end());
5552 }
5553
5554
5555 void populateAll() const {
5556 for (const AACallGraphNode *AA : optimisticEdgesRange()) {
5557
5558 (void)AA;
5559 }
5560 }
5561
5562 void print();
5563 };
5564
5565 template <> struct GraphTraits<AACallGraphNode *> {
5566 using NodeRef = AACallGraphNode *;
5567 using ChildIteratorType = AACallEdgeIterator;
5568
5569 static AACallEdgeIterator child_begin(AACallGraphNode *Node) {
5570 return Node->optimisticEdgesBegin();
5571 }
5572
5573 static AACallEdgeIterator child_end(AACallGraphNode *Node) {
5574 return Node->optimisticEdgesEnd();
5575 }
5576 };
5577
5578 template <>
5579 struct GraphTraits<AttributorCallGraph *>
5580 : public GraphTraits<AACallGraphNode *> {
5581 using nodes_iterator = AACallEdgeIterator;
5582
5583 static AACallGraphNode *getEntryNode(AttributorCallGraph *G) {
5584 return static_cast<AACallGraphNode *>(G);
5585 }
5586
5587 static AACallEdgeIterator nodes_begin(const AttributorCallGraph *G) {
5588 return G->optimisticEdgesBegin();
5589 }
5590
5591 static AACallEdgeIterator nodes_end(const AttributorCallGraph *G) {
5592 return G->optimisticEdgesEnd();
5593 }
5594 };
5595
5596 template <>
5597 struct DOTGraphTraits<AttributorCallGraph *> : public DefaultDOTGraphTraits {
5598 DOTGraphTraits(bool Simple = false) : DefaultDOTGraphTraits(Simple) {}
5599
5600 std::string getNodeLabel(const AACallGraphNode *Node,
5601 const AttributorCallGraph *Graph) {
5602 const AACallEdges *AACE = static_cast<const AACallEdges *>(Node);
5603 return AACE->getAssociatedFunction()->getName().str();
5604 }
5605
5606 static bool isNodeHidden(const AACallGraphNode *Node,
5607 const AttributorCallGraph *Graph) {
5608
5609 return static_cast<const AACallGraphNode *>(Graph) == Node;
5610 }
5611 };
5612
5613 struct AAExecutionDomain
5614 : public StateWrapper<BooleanState, AbstractAttribute> {
5615 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5616 AAExecutionDomain(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5617
5618
5619 struct ExecutionDomainTy {
5620 using BarriersSetTy = SmallPtrSet<CallBase *, 2>;
5621 using AssumesSetTy = SmallPtrSet<AssumeInst *, 4>;
5622
5623 void addAssumeInst(Attributor &A, AssumeInst &AI) {
5624 EncounteredAssumes.insert(&AI);
5625 }
5626
5627 void addAlignedBarrier(Attributor &A, CallBase &CB) {
5628 AlignedBarriers.insert(&CB);
5629 }
5630
5631 void clearAssumeInstAndAlignedBarriers() {
5632 EncounteredAssumes.clear();
5633 AlignedBarriers.clear();
5634 }
5635
5636 bool IsExecutedByInitialThreadOnly = true;
5637 bool IsReachedFromAlignedBarrierOnly = true;
5638 bool IsReachingAlignedBarrierOnly = true;
5639 bool EncounteredNonLocalSideEffect = false;
5640 BarriersSetTy AlignedBarriers;
5641 AssumesSetTy EncounteredAssumes;
5642 };
5643
5644
5645 static AAExecutionDomain &createForPosition(const IRPosition &IRP,
5646 Attributor &A);
5647
5648
5649 const std::string getName() const override { return "AAExecutionDomain"; }
5650
5651
5652 const char *getIdAddr() const override { return &ID; }
5653
5654
5655 bool isExecutedByInitialThreadOnly(const Instruction &I) const {
5656 return isExecutedByInitialThreadOnly(*I.getParent());
5657 }
5658
5659
5660 virtual bool isExecutedByInitialThreadOnly(const BasicBlock &) const = 0;
5661
5662
5663
5664
5665 virtual bool isExecutedInAlignedRegion(Attributor &A,
5666 const Instruction &I) const = 0;
5667
5668 virtual ExecutionDomainTy getExecutionDomain(const BasicBlock &) const = 0;
5669
5670
5671 virtual std::pair<ExecutionDomainTy, ExecutionDomainTy>
5672 getExecutionDomain(const CallBase &CB) const = 0;
5673 virtual ExecutionDomainTy getFunctionExecutionDomain() const = 0;
5674
5675
5676
5677 virtual bool isNoOpFence(const FenceInst &FI) const = 0;
5678
5679
5680
5681 static bool classof(const AbstractAttribute *AA) {
5682 return (AA->getIdAddr() == &ID);
5683 }
5684
5685
5686 static const char ID;
5687 };
5688
5689
5690 struct AAInterFnReachability
5691 : public StateWrapper<BooleanState, AbstractAttribute> {
5692 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5693
5694 AAInterFnReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5695
5696
5697 bool canReach(Attributor &A, const Function &Fn) const {
5698 Function *Scope = getAnchorScope();
5699 if (!Scope || Scope->isDeclaration())
5700 return true;
5701 return instructionCanReach(A, Scope->getEntryBlock().front(), Fn);
5702 }
5703
5704
5705
5706 virtual bool instructionCanReach(
5707 Attributor &A, const Instruction &Inst, const Function &Fn,
5708 const AA::InstExclusionSetTy *ExclusionSet = nullptr) const = 0;
5709
5710
5711 static AAInterFnReachability &createForPosition(const IRPosition &IRP,
5712 Attributor &A);
5713
5714
5715 const std::string getName() const override { return "AAInterFnReachability"; }
5716
5717
5718 const char *getIdAddr() const override { return &ID; }
5719
5720
5721 static bool classof(const AbstractAttribute *AA) {
5722 return (AA->getIdAddr() == &ID);
5723 }
5724
5725
5726 static const char ID;
5727 };
5728
5729
5730
5731 struct AANonConvergent : public StateWrapper<BooleanState, AbstractAttribute> {
5732 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5733
5734 AANonConvergent(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5735
5736
5737 static AANonConvergent &createForPosition(const IRPosition &IRP,
5738 Attributor &A);
5739
5740
5741 bool isAssumedNotConvergent() const { return getAssumed(); }
5742
5743
5744 bool isKnownNotConvergent() const { return getKnown(); }
5745
5746
5747 const std::string getName() const override { return "AANonConvergent"; }
5748
5749
5750 const char *getIdAddr() const override { return &ID; }
5751
5752
5753
5754 static bool classof(const AbstractAttribute *AA) {
5755 return (AA->getIdAddr() == &ID);
5756 }
5757
5758
5759 static const char ID;
5760 };
5761
5762
5763 struct AAPointerInfo : public AbstractAttribute {
5764 AAPointerInfo(const IRPosition &IRP) : AbstractAttribute(IRP) {}
5765
5766
5767 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
5768 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
5769 return false;
5770 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
5771 }
5772
5773 enum AccessKind {
5774
5775 AK_MUST = 1 << 0,
5776 AK_MAY = 1 << 1,
5777
5778
5779 AK_R = 1 << 2,
5780 AK_W = 1 << 3,
5781 AK_RW = AK_R | AK_W,
5782
5783
5784
5785
5786 AK_ASSUMPTION = (1 << 4) | AK_MUST,
5787
5788
5789 AK_MAY_READ = AK_MAY | AK_R,
5790 AK_MAY_WRITE = AK_MAY | AK_W,
5791 AK_MAY_READ_WRITE = AK_MAY | AK_R | AK_W,
5792 AK_MUST_READ = AK_MUST | AK_R,
5793 AK_MUST_WRITE = AK_MUST | AK_W,
5794 AK_MUST_READ_WRITE = AK_MUST | AK_R | AK_W,
5795 };
5796
5797
5798
5799
5800 struct OffsetInfo {
5801 using VecTy = SmallSet<int64_t, 4>;
5802 using const_iterator = VecTy::const_iterator;
5803 VecTy Offsets;
5804
5805 const_iterator begin() const { return Offsets.begin(); }
5806 const_iterator end() const { return Offsets.end(); }
5807
5808 bool operator==(const OffsetInfo &RHS) const {
5809 return Offsets == RHS.Offsets;
5810 }
5811
5812 bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); }
5813
5814 bool insert(int64_t Offset) { return Offsets.insert(Offset).second; }
5815 bool isUnassigned() const { return Offsets.size() == 0; }
5816
5817 bool isUnknown() const {
5818 if (isUnassigned())
5819 return false;
5820 if (Offsets.size() == 1)
5821 return *Offsets.begin() == AA::RangeTy::Unknown;
5822 return false;
5823 }
5824
5825 void setUnknown() {
5826 Offsets.clear();
5827 Offsets.insert(AA::RangeTy::Unknown);
5828 }
5829
5830 void addToAll(int64_t Inc) {
5831 VecTy NewOffsets;
5832 for (auto &Offset : Offsets)
5833 NewOffsets.insert(Offset + Inc);
5834 Offsets = std::move(NewOffsets);
5835 }
5836
5837
5838
5839
5840
5841 bool merge(const OffsetInfo &R) { return set_union(Offsets, R.Offsets); }
5842 };
5843
5844
5845 struct RangeList {
5846
5847
5848
5849
5850 using RangeTy = AA::RangeTy;
5851 using VecTy = SmallVector<RangeTy>;
5852 using iterator = VecTy::iterator;
5853 using const_iterator = VecTy::const_iterator;
5854 VecTy Ranges;
5855
5856 RangeList(const RangeTy &R) { Ranges.push_back(R); }
5857 RangeList(ArrayRef<int64_t> Offsets, int64_t Size) {
5858 Ranges.reserve(Offsets.size());
5859 for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
5860 assert(((i + 1 == e) || Offsets[i] < Offsets[i + 1]) &&
5861 "Expected strictly ascending offsets.");
5862 Ranges.emplace_back(Offsets[i], Size);
5863 }
5864 }
5865 RangeList() = default;
5866
5867 iterator begin() { return Ranges.begin(); }
5868 iterator end() { return Ranges.end(); }
5869 const_iterator begin() const { return Ranges.begin(); }
5870 const_iterator end() const { return Ranges.end(); }
5871
5872
5873 using value_type = RangeTy;
5874 void push_back(const RangeTy &R) {
5875 assert((Ranges.empty() || RangeTy::LessThan(Ranges.back(), R)) &&
5876 "Ensure the last element is the greatest.");
5877 Ranges.push_back(R);
5878 }
5879
5880
5881 static void set_difference(const RangeList &L, const RangeList &R,
5882 RangeList &D) {
5883 std::set_difference(L.begin(), L.end(), R.begin(), R.end(),
5884 std::back_inserter(D), RangeTy::LessThan);
5885 }
5886
5887 unsigned size() const { return Ranges.size(); }
5888
5889 bool operator==(const RangeList &OI) const { return Ranges == OI.Ranges; }
5890
5891
5892
5893
5894
5895 bool merge(const RangeList &RHS) {
5896 if (isUnknown())
5897 return false;
5898 if (RHS.isUnknown()) {
5899 setUnknown();
5900 return true;
5901 }
5902
5903 if (Ranges.empty()) {
5904 Ranges = RHS.Ranges;
5905 return true;
5906 }
5907
5908 bool Changed = false;
5909 auto LPos = Ranges.begin();
5910 for (auto &R : RHS.Ranges) {
5911 auto Result = insert(LPos, R);
5912 if (isUnknown())
5913 return true;
5914 LPos = Result.first;
5915 Changed |= Result.second;
5916 }
5917 return Changed;
5918 }
5919
5920
5921
5922
5923
5924
5925
5926 std::pair<iterator, bool> insert(iterator Pos, const RangeTy &R) {
5927 if (isUnknown())
5928 return std::make_pair(Ranges.begin(), false);
5929 if (R.offsetOrSizeAreUnknown()) {
5930 return std::make_pair(setUnknown(), true);
5931 }
5932
5933
5934 auto LB = std::lower_bound(Pos, Ranges.end(), R, RangeTy::LessThan);
5935 if (LB == Ranges.end() || LB->Offset != R.Offset)
5936 return std::make_pair(Ranges.insert(LB, R), true);
5937 bool Changed = *LB != R;
5938 *LB &= R;
5939 if (LB->offsetOrSizeAreUnknown())
5940 return std::make_pair(setUnknown(), true);
5941 return std::make_pair(LB, Changed);
5942 }
5943
5944
5945
5946
5947 std::pair<iterator, bool> insert(const RangeTy &R) {
5948 return insert(Ranges.begin(), R);
5949 }
5950
5951
5952 void addToAllOffsets(int64_t Inc) {
5953 assert(!isUnassigned() &&
5954 "Cannot increment if the offset is not yet computed!");
5955 if (isUnknown())
5956 return;
5957 for (auto &R : Ranges) {
5958 R.Offset += Inc;
5959 }
5960 }
5961
5962
5963 bool isUnique() const {
5964 return Ranges.size() == 1 && !Ranges.front().offsetOrSizeAreUnknown();
5965 }
5966
5967
5968 const RangeTy &getUnique() const {
5969 assert(isUnique() && "No unique range to return!");
5970 return Ranges.front();
5971 }
5972
5973
5974 bool isUnknown() const {
5975 if (isUnassigned())
5976 return false;
5977 if (Ranges.front().offsetOrSizeAreUnknown()) {
5978 assert(Ranges.size() == 1 && "Unknown is a singleton range.");
5979 return true;
5980 }
5981 return false;
5982 }
5983
5984
5985 iterator setUnknown() {
5986 Ranges.clear();
5987 Ranges.push_back(RangeTy::getUnknown());
5988 return Ranges.begin();
5989 }
5990
5991
5992 bool isUnassigned() const { return Ranges.size() == 0; }
5993 };
5994
5995
5996 struct Access {
5997 Access(Instruction *I, int64_t Offset, int64_t Size,
5998 std::optional<Value *> Content, AccessKind Kind, Type *Ty)
5999 : LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size),
6000 Kind(Kind), Ty(Ty) {
6001 verify();
6002 }
6003 Access(Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
6004 std::optional<Value *> Content, AccessKind K, Type *Ty)
6005 : LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
6006 Kind(K), Ty(Ty) {
6007 if (Ranges.size() > 1) {
6008 Kind = AccessKind(Kind | AK_MAY);
6009 Kind = AccessKind(Kind & ~AK_MUST);
6010 }
6011 verify();
6012 }
6013 Access(Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
6014 int64_t Size, std::optional<Value *> Content, AccessKind Kind,
6015 Type *Ty)
6016 : LocalI(LocalI), RemoteI(RemoteI), Content(Content),
6017 Ranges(Offset, Size), Kind(Kind), Ty(Ty) {
6018 verify();
6019 }
6020 Access(const Access &Other) = default;
6021
6022 Access &operator=(const Access &Other) = default;
6023 bool operator==(const Access &R) const {
6024 return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
6025 Content == R.Content && Kind == R.Kind;
6026 }
6027 bool operator!=(const Access &R) const { return !(*this == R); }
6028
6029 Access &operator&=(const Access &R) {
6030 assert(RemoteI == R.RemoteI && "Expected same instruction!");
6031 assert(LocalI == R.LocalI && "Expected same instruction!");
6032
6033
6034
6035
6036
6037 Ranges.merge(R.Ranges);
6038 Content =
6039 AA::combineOptionalValuesInAAValueLatice(Content, R.Content, Ty);
6040
6041
6042
6043
6044 Kind = AccessKind(Kind | R.Kind);
6045 if ((Kind & AK_MAY) || Ranges.size() > 1) {
6046 Kind = AccessKind(Kind | AK_MAY);
6047 Kind = AccessKind(Kind & ~AK_MUST);
6048 }
6049 verify();
6050 return *this;
6051 }
6052
6053 void verify() {
6054 assert(isMustAccess() + isMayAccess() == 1 &&
6055 "Expect must or may access, not both.");
6056 assert(isAssumption() + isWrite() <= 1 &&
6057 "Expect assumption access or write access, never both.");
6058 assert((isMayAccess() || Ranges.size() == 1) &&
6059 "Cannot be a must access if there are multiple ranges.");
6060 }
6061
6062
6063 AccessKind getKind() const { return Kind; }
6064
6065
6066 bool isRead() const { return Kind & AK_R; }
6067
6068
6069 bool isWrite() const { return Kind & AK_W; }
6070
6071
6072 bool isWriteOrAssumption() const { return isWrite() || isAssumption(); }
6073
6074
6075 bool isAssumption() const { return Kind == AK_ASSUMPTION; }
6076
6077 bool isMustAccess() const {
6078 bool MustAccess = Kind & AK_MUST;
6079 assert((!MustAccess || Ranges.size() < 2) &&
6080 "Cannot be a must access if there are multiple ranges.");
6081 return MustAccess;
6082 }
6083
6084 bool isMayAccess() const {
6085 bool MayAccess = Kind & AK_MAY;
6086 assert((MayAccess || Ranges.size() < 2) &&
6087 "Cannot be a must access if there are multiple ranges.");
6088 return MayAccess;
6089 }
6090
6091
6092
6093 Instruction *getLocalInst() const { return LocalI; }
6094
6095
6096 Instruction *getRemoteInst() const { return RemoteI; }
6097
6098
6099 bool isWrittenValueYetUndetermined() const { return !Content; }
6100
6101
6102 bool isWrittenValueUnknown() const {
6103 return Content.has_value() && !*Content;
6104 }
6105
6106
6107 void setWrittenValueUnknown() { Content = nullptr; }
6108
6109
6110 Type *getType() const { return Ty; }
6111
6112
6113 Value *getWrittenValue() const {
6114 assert(!isWrittenValueYetUndetermined() &&
6115 "Value needs to be determined before accessing it.");
6116 return *Content;
6117 }
6118
6119
6120
6121 std::optional<Value *> getContent() const { return Content; }
6122
6123 bool hasUniqueRange() const { return Ranges.isUnique(); }
6124 const AA::RangeTy &getUniqueRange() const { return Ranges.getUnique(); }
6125
6126
6127
6128
6129 void addRange(int64_t Offset, int64_t Size) {
6130 Ranges.insert({Offset, Size});
6131 if (!hasUniqueRange()) {
6132 Kind = AccessKind(Kind | AK_MAY);
6133 Kind = AccessKind(Kind & ~AK_MUST);
6134 }
6135 }
6136
6137 const RangeList &getRanges() const { return Ranges; }
6138
6139 using const_iterator = RangeList::const_iterator;
6140 const_iterator begin() const { return Ranges.begin(); }
6141 const_iterator end() const { return Ranges.end(); }
6142
6143 private:
6144
6145
6146 Instruction *LocalI;
6147
6148
6149 Instruction *RemoteI;
6150
6151
6152
6153 std::optional<Value *> Content;
6154
6155
6156 RangeList Ranges;
6157
6158
6159 AccessKind Kind;
6160
6161
6162
6163 Type *Ty;
6164 };
6165
6166
6167 static AAPointerInfo &createForPosition(const IRPosition &IRP, Attributor &A);
6168
6169
6170 const std::string getName() const override { return "AAPointerInfo"; }
6171
6172
6173 const char *getIdAddr() const override { return &ID; }
6174
6175 using OffsetBinsTy = DenseMap<AA::RangeTy, SmallSet<unsigned, 4>>;
6176 using const_bin_iterator = OffsetBinsTy::const_iterator;
6177 virtual const_bin_iterator begin() const = 0;
6178 virtual const_bin_iterator end() const = 0;
6179 virtual int64_t numOffsetBins() const = 0;
6180 virtual bool reachesReturn() const = 0;
6181 virtual void addReturnedOffsetsTo(OffsetInfo &) const = 0;
6182
6183
6184
6185
6186
6187 virtual bool forallInterferingAccesses(
6188 AA::RangeTy Range, function_ref<bool(const Access &, bool)> CB) const = 0;
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199 virtual bool forallInterferingAccesses(
6200 Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,
6201 bool FindInterferingWrites, bool FindInterferingReads,
6202 function_ref<bool(const Access &, bool)> CB, bool &HasBeenWrittenTo,
6203 AA::RangeTy &Range,
6204 function_ref<bool(const Access &)> SkipCB = nullptr) const = 0;
6205
6206
6207 static bool classof(const AbstractAttribute *AA) {
6208 return (AA->getIdAddr() == &ID);
6209 }
6210
6211
6212 static const char ID;
6213 };
6214
6215 raw_ostream &operator<<(raw_ostream &, const AAPointerInfo::Access &);
6216
6217
6218 struct AAAssumptionInfo
6219 : public StateWrapper<SetState<StringRef>, AbstractAttribute,
6220 DenseSet<StringRef>> {
6221 using Base =
6222 StateWrapper<SetState<StringRef>, AbstractAttribute, DenseSet<StringRef>>;
6223
6224 AAAssumptionInfo(const IRPosition &IRP, Attributor &A,
6225 const DenseSet<StringRef> &Known)
6226 : Base(IRP, Known) {}
6227
6228
6229 virtual bool hasAssumption(const StringRef Assumption) const = 0;
6230
6231
6232 static AAAssumptionInfo &createForPosition(const IRPosition &IRP,
6233 Attributor &A);
6234
6235
6236 const std::string getName() const override { return "AAAssumptionInfo"; }
6237
6238
6239 const char *getIdAddr() const override { return &ID; }
6240
6241
6242
6243 static bool classof(const AbstractAttribute *AA) {
6244 return (AA->getIdAddr() == &ID);
6245 }
6246
6247
6248 static const char ID;
6249 };
6250
6251
6252 struct AAUnderlyingObjects : AbstractAttribute {
6253 AAUnderlyingObjects(const IRPosition &IRP) : AbstractAttribute(IRP) {}
6254
6255
6256 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6257 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
6258 return false;
6259 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
6260 }
6261
6262
6263 static bool requiresCallersForArgOrFunction() { return true; }
6264
6265
6266 static AAUnderlyingObjects &createForPosition(const IRPosition &IRP,
6267 Attributor &A);
6268
6269
6270 const std::string getName() const override { return "AAUnderlyingObjects"; }
6271
6272
6273 const char *getIdAddr() const override { return &ID; }
6274
6275
6276
6277 static bool classof(const AbstractAttribute *AA) {
6278 return (AA->getIdAddr() == &ID);
6279 }
6280
6281
6282 static const char ID;
6283
6284
6285
6286
6287
6288 virtual bool
6289 forallUnderlyingObjects(function_ref<bool(Value &)> Pred,
6290 AA::ValueScope Scope = AA::Interprocedural) const = 0;
6291 };
6292
6293
6294 struct AAAddressSpace : public StateWrapper<BooleanState, AbstractAttribute> {
6295 AAAddressSpace(const IRPosition &IRP, Attributor &A)
6296 : StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
6297
6298
6299 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6300 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
6301 return false;
6302 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
6303 }
6304
6305
6306 static bool requiresCallersForArgOrFunction() { return true; }
6307
6308
6309
6310
6311 virtual uint32_t getAddressSpace() const = 0;
6312
6313
6314 static AAAddressSpace &createForPosition(const IRPosition &IRP,
6315 Attributor &A);
6316
6317
6318 const std::string getName() const override { return "AAAddressSpace"; }
6319
6320
6321 const char *getIdAddr() const override { return &ID; }
6322
6323
6324
6325 static bool classof(const AbstractAttribute *AA) {
6326 return (AA->getIdAddr() == &ID);
6327 }
6328
6329
6330 static const char ID;
6331
6332 protected:
6333
6334 static const uint32_t InvalidAddressSpace = ~0U;
6335 };
6336
6337 struct AAAllocationInfo : public StateWrapper<BooleanState, AbstractAttribute> {
6338 AAAllocationInfo(const IRPosition &IRP, Attributor &A)
6339 : StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
6340
6341
6342 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6343 if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy())
6344 return false;
6345 return AbstractAttribute::isValidIRPositionForInit(A, IRP);
6346 }
6347
6348
6349 static AAAllocationInfo &createForPosition(const IRPosition &IRP,
6350 Attributor &A);
6351
6352 virtual std::optional<TypeSize> getAllocatedSize() const = 0;
6353
6354
6355 const std::string getName() const override { return "AAAllocationInfo"; }
6356
6357
6358 const char *getIdAddr() const override { return &ID; }
6359
6360
6361
6362 static bool classof(const AbstractAttribute *AA) {
6363 return (AA->getIdAddr() == &ID);
6364 }
6365
6366 constexpr static const std::optional<TypeSize> HasNoAllocationSize =
6367 std::optional<TypeSize>(TypeSize(-1, true));
6368
6369 static const char ID;
6370 };
6371
6372
6373 struct AAGlobalValueInfo
6374 : public StateWrapper<BooleanState, AbstractAttribute> {
6375 AAGlobalValueInfo(const IRPosition &IRP, Attributor &A)
6376 : StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
6377
6378
6379 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6380 if (IRP.getPositionKind() != IRPosition::IRP_FLOAT)
6381 return false;
6382 auto *GV = dyn_cast<GlobalValue>(&IRP.getAnchorValue());
6383 if (!GV)
6384 return false;
6385 return GV->hasLocalLinkage();
6386 }
6387
6388
6389 static AAGlobalValueInfo &createForPosition(const IRPosition &IRP,
6390 Attributor &A);
6391
6392
6393 virtual bool isPotentialUse(const Use &U) const = 0;
6394
6395
6396 const std::string getName() const override { return "AAGlobalValueInfo"; }
6397
6398
6399 const char *getIdAddr() const override { return &ID; }
6400
6401
6402
6403 static bool classof(const AbstractAttribute *AA) {
6404 return (AA->getIdAddr() == &ID);
6405 }
6406
6407
6408 static const char ID;
6409 };
6410
6411
6412 struct AAIndirectCallInfo
6413 : public StateWrapper<BooleanState, AbstractAttribute> {
6414 AAIndirectCallInfo(const IRPosition &IRP, Attributor &A)
6415 : StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
6416
6417
6418 static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6419 if (IRP.getPositionKind() != IRPosition::IRP_CALL_SITE)
6420 return false;
6421 auto *CB = cast<CallBase>(IRP.getCtxI());
6422 return CB->getOpcode() == Instruction::Call && CB->isIndirectCall() &&
6423 !CB->isMustTailCall();
6424 }
6425
6426
6427 static AAIndirectCallInfo &createForPosition(const IRPosition &IRP,
6428 Attributor &A);
6429
6430
6431
6432 virtual bool foreachCallee(function_ref<bool(Function *)> CB) const = 0;
6433
6434
6435 const std::string getName() const override { return "AAIndirectCallInfo"; }
6436
6437
6438 const char *getIdAddr() const override { return &ID; }
6439
6440
6441
6442
6443
6444 static bool classof(const AbstractAttribute *AA) {
6445 return (AA->getIdAddr() == &ID);
6446 }
6447
6448
6449 static const char ID;
6450 };
6451
6452
6453
6454 struct AADenormalFPMath
6455 : public StateWrapper<DenormalFPMathState, AbstractAttribute> {
6456 using Base = StateWrapper<DenormalFPMathState, AbstractAttribute>;
6457
6458 AADenormalFPMath(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
6459
6460
6461 static AADenormalFPMath &createForPosition(const IRPosition &IRP,
6462 Attributor &A);
6463
6464
6465 const std::string getName() const override { return "AADenormalFPMath"; }
6466
6467
6468 const char *getIdAddr() const override { return &ID; }
6469
6470
6471
6472 static bool classof(const AbstractAttribute *AA) {
6473 return (AA->getIdAddr() == &ID);
6474 }
6475
6476
6477 static const char ID;
6478 };
6479
6480 raw_ostream &operator<<(raw_ostream &, const AAPointerInfo::Access &);
6481
6482
6483 enum AttributorRunOption {
6484 NONE = 0,
6485 MODULE = 1 << 0,
6486 CGSCC = 1 << 1,
6487 ALL = MODULE | CGSCC
6488 };
6489
6490 namespace AA {
6491
6492 template <Attribute::AttrKind AK, typename AAType = AbstractAttribute>
6493 bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA,
6494 const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown,
6495 bool IgnoreSubsumingPositions = false,
6496 const AAType **AAPtr = nullptr) {
6497 IsKnown = false;
6498 switch (AK) {
6499 #define CASE(ATTRNAME, AANAME, ...) \
6500 case Attribute::ATTRNAME: { \
6501 if (AANAME::isImpliedByIR(A, IRP, AK, IgnoreSubsumingPositions)) \
6502 return IsKnown = true; \
6503 if (!QueryingAA) \
6504 return false; \
6505 const auto *AA = A.getAAFor<AANAME>(*QueryingAA, IRP, DepClass); \
6506 if (AAPtr) \
6507 *AAPtr = reinterpret_cast<const AAType *>(AA); \
6508 if (!AA || !AA->isAssumed(__VA_ARGS__)) \
6509 return false; \
6510 IsKnown = AA->isKnown(__VA_ARGS__); \
6511 return true; \
6512 }
6513 CASE(NoUnwind, AANoUnwind, );
6514 CASE(WillReturn, AAWillReturn, );
6515 CASE(NoFree, AANoFree, );
6516 CASE(NoCapture, AANoCapture, );
6517 CASE(NoRecurse, AANoRecurse, );
6518 CASE(NoReturn, AANoReturn, );
6519 CASE(NoSync, AANoSync, );
6520 CASE(NoAlias, AANoAlias, );
6521 CASE(NonNull, AANonNull, );
6522 CASE(MustProgress, AAMustProgress, );
6523 CASE(NoUndef, AANoUndef, );
6524 CASE(ReadNone, AAMemoryBehavior, AAMemoryBehavior::NO_ACCESSES);
6525 CASE(ReadOnly, AAMemoryBehavior, AAMemoryBehavior::NO_WRITES);
6526 CASE(WriteOnly, AAMemoryBehavior, AAMemoryBehavior::NO_READS);
6527 #undef CASE
6528 default:
6529 llvm_unreachable("hasAssumedIRAttr not available for this attribute kind");
6530 };
6531 }
6532 }
6533
6534 }
6535
6536 #endif