[llvm] [IPO] Added attributor for identifying invariant loads (PR #141800)
Shilei Tian via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 5 12:13:15 PDT 2025
================
@@ -12534,6 +12535,318 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
};
} // namespace
+/// --------------------- Invariant Load Pointer -------------------------------
+namespace {
+
+struct AAInvariantLoadPointerImpl
+ : public StateWrapper<BitIntegerState<uint8_t, 15>,
+ AAInvariantLoadPointer> {
+
+ enum {
+ // pointer does not alias within the bounds of the function
+ IS_NOALIAS = 1 << 0,
+ // pointer is not involved in any effectful instructions within the bounds
+ // of the function
+ IS_NOEFFECT = 1 << 1,
+ // loads are invariant within the bounds of the function
+ IS_LOCALLY_INVARIANT = 1 << 2,
+ // memory lifetime is constrained within the bounds of the function
+ IS_LOCALLY_CONSTRAINED = 1 << 3,
+
+ IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
+ IS_LOCALLY_CONSTRAINED,
+ };
+ static_assert(getBestState() == IS_BEST_STATE, "Unexpected best state");
+
+ using Base =
+ StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
+
+ // the BitIntegerState is optimistic about IS_NOALIAS and IS_NOEFFECT, but
+ // pessimistic about IS_KNOWN_INVARIANT
+ AAInvariantLoadPointerImpl(const IRPosition &IRP, Attributor &A)
+ : Base(IRP) {}
+
+ bool isKnownInvariant() const final {
+ return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
+ }
+
+ bool isKnownLocallyInvariant() const final {
+ if (isKnown(IS_LOCALLY_INVARIANT))
+ return true;
+ return isKnown(IS_NOALIAS | IS_NOEFFECT);
+ }
+
+ bool isAssumedInvariant() const final {
+ return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
+ }
+
+ bool isAssumedLocallyInvariant() const final {
+ if (isAssumed(IS_LOCALLY_INVARIANT))
+ return true;
+ return isAssumed(IS_NOALIAS | IS_NOEFFECT);
+ }
+
+ ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
+
+ Changed |= updateNoAlias(A);
+ if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
+ return indicatePessimisticFixpoint();
+
+ Changed |= updateNoEffect(A);
+
+ Changed |= updateLocalInvariance(A);
+
+ return Changed;
+ }
+
+ ChangeStatus manifest(Attributor &A) override {
+ if (!isKnownInvariant())
+ return ChangeStatus::UNCHANGED;
+
+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
+ const Value *Ptr = &getAssociatedValue();
+ const auto TagInvariantLoads = [&](const Use &U, bool &) {
+ if (U.get() != Ptr)
+ return true;
+ auto *I = dyn_cast<Instruction>(U.getUser());
+ if (!I)
+ return true;
+
+ // Ensure that we are only changing uses from the corresponding callgraph
+ // SSC in the case that the AA isn't run on the entire module
+ if (!A.isRunOn(I->getFunction()))
+ return true;
+
+ if (I->hasMetadata(LLVMContext::MD_invariant_load))
+ return true;
+
+ if (auto *LI = dyn_cast<LoadInst>(I)) {
+ LI->setMetadata(LLVMContext::MD_invariant_load,
+ MDNode::get(LI->getContext(), {}));
+ Changed = ChangeStatus::CHANGED;
+ }
+ return true;
+ };
+
+ (void)A.checkForAllUses(TagInvariantLoads, *this, *Ptr);
+ return Changed;
+ }
+
+ /// See AbstractAttribute::getAsStr().
+ const std::string getAsStr(Attributor *) const override {
+ if (isKnownInvariant())
+ return "load-invariant pointer";
+ return "non-invariant pointer";
+ }
+
+ /// See AbstractAttribute::trackStatistics().
+ void trackStatistics() const override {}
+
+private:
+ /// Indicate that noalias is required for the pointer to be invariant.
+ bool requiresNoAlias() const {
+ switch (getPositionKind()) {
+ default:
+ return false;
----------------
shiltian wrote:
Do you need to be conservative for `default` here?
https://github.com/llvm/llvm-project/pull/141800
More information about the llvm-commits
mailing list