diff --git a/llvm/include/llvm/IR/Use.h b/llvm/include/llvm/IR/Use.h --- a/llvm/include/llvm/IR/Use.h +++ b/llvm/include/llvm/IR/Use.h @@ -91,7 +91,7 @@ private: /// Destructor - Only for zap() ~Use() { - if (Val) + if (Val.getPointer()) removeFromList(); } @@ -100,11 +100,22 @@ /// Constructor Use(PrevPtrTag tag) { Prev.setInt(tag); } +#ifndef NDEBUG + bool checkDroppable() const; +#endif + void setDroppable(bool NewVal = true) { Val.setInt(NewVal); } + public: friend class Value; + friend class User; + + bool isDroppable() const { + assert(checkDroppable() && "the use should be marked droppable"); + return Val.getInt(); + } - operator Value *() const { return Val; } - Value *get() const { return Val; } + operator Value *() const { return Val.getPointer(); } + Value *get() const { return Val.getPointer(); } /// Returns the User that contains this Use. /// @@ -117,8 +128,8 @@ inline Value *operator=(Value *RHS); inline const Use &operator=(const Use &RHS); - Value *operator->() { return Val; } - const Value *operator->() const { return Val; } + Value *operator->() { return Val.getPointer(); } + const Value *operator->() const { return Val.getPointer(); } Use *getNext() const { return Next; } @@ -138,7 +149,7 @@ private: const Use *getImpliedUser() const LLVM_READONLY; - Value *Val = nullptr; + PointerIntPair Val = {nullptr, 0}; Use *Next = nullptr; PointerIntPair Prev; diff --git a/llvm/include/llvm/IR/User.h b/llvm/include/llvm/IR/User.h --- a/llvm/include/llvm/IR/User.h +++ b/llvm/include/llvm/IR/User.h @@ -223,6 +223,10 @@ /// from happening. bool isDroppable() const; + /// This will mark every use as droppable if the user is droppable. + /// This should be called from + void maybeMarkUsesAsDroppable(); + // --------------------------------------------------------------------------- // Operand Iterator interface... // diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -449,7 +449,17 @@ /// /// This is specialized because it is a common request and does not require /// traversing the whole use list. - Use *getSingleUndroppableUse(); + Use *getSingleUndroppableUse() { + Use *Result = nullptr; + for (Use &U : uses()) { + if (!U.isDroppable()) { + if (Result) + return nullptr; + Result = &U; + } + } + return Result; + } /// Return true if there this value. /// @@ -756,8 +766,9 @@ } void Use::set(Value *V) { - if (Val) removeFromList(); - Val = V; + if (Val.getPointer()) + removeFromList(); + Val.setPointer(V); if (V) V->addUse(*this); } @@ -767,7 +778,7 @@ } const Use &Use::operator=(const Use &RHS) { - set(RHS.Val); + set(RHS.Val.getPointer()); return *this; } diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -460,6 +460,7 @@ assert(It + 1 == op_end() && "Should add up!"); setName(NameStr); + maybeMarkUsesAsDroppable(); } void CallInst::init(FunctionType *FTy, Value *Func, const Twine &NameStr) { @@ -470,6 +471,7 @@ assert(FTy->getNumParams() == 0 && "Calling a function with bad signature"); setName(NameStr); + maybeMarkUsesAsDroppable(); } CallInst::CallInst(FunctionType *Ty, Value *Func, const Twine &Name, diff --git a/llvm/lib/IR/Use.cpp b/llvm/lib/IR/Use.cpp --- a/llvm/lib/IR/Use.cpp +++ b/llvm/lib/IR/Use.cpp @@ -17,23 +17,23 @@ if (Val == RHS.Val) return; - if (Val) + if (Val.getPointer()) removeFromList(); - Value *OldVal = Val; - if (RHS.Val) { + Value *OldVal = Val.getPointer(); + if (RHS.Val.getPointer()) { RHS.removeFromList(); - Val = RHS.Val; - Val->addUse(*this); + Val.setPointer(RHS.Val.getPointer()); + Val.getPointer()->addUse(*this); } else { - Val = nullptr; + Val.setPointer(nullptr); } if (OldVal) { - RHS.Val = OldVal; - RHS.Val->addUse(RHS); + RHS.Val.setPointer(OldVal); + RHS.Val.getPointer()->addUse(RHS); } else { - RHS.Val = nullptr; + RHS.Val.setPointer(nullptr); } } @@ -48,6 +48,12 @@ return this - getUser()->op_begin(); } +#ifndef NDEBUG +bool Use::checkDroppable() const { + return Val.getInt() == getUser()->isDroppable(); +} +#endif + // Sets up the waymarking algorithm's tags for a series of Uses. See the // algorithm details here: // diff --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp --- a/llvm/lib/IR/User.cpp +++ b/llvm/lib/IR/User.cpp @@ -109,9 +109,18 @@ bool User::isDroppable() const { if (const auto *Intr = dyn_cast(this)) return Intr->getIntrinsicID() == Intrinsic::assume; + /// If you are changing this definition you may need to add calls to + /// maybeMarkUsesAsDroppable in some subclasses return false; } +void User::maybeMarkUsesAsDroppable() { + if (!isDroppable()) + return; + for (unsigned i = 0; i < getNumOperands(); i++) + getOperandUse(i).setDroppable(); +} + //===----------------------------------------------------------------------===// // User operator new Implementations //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -141,33 +141,21 @@ return hasNItemsOrMore(use_begin(), use_end(), N); } -static bool isUnDroppableUser(const User *U) { return !U->isDroppable(); } - -Use *Value::getSingleUndroppableUse() { - Use *Result = nullptr; - for (Use &U : uses()) { - if (!U.getUser()->isDroppable()) { - if (Result) - return nullptr; - Result = &U; - } - } - return Result; -} +static bool isUnDroppableUse(const Use& U) { return !U.isDroppable(); } bool Value::hasNUndroppableUses(unsigned int N) const { - return hasNItems(user_begin(), user_end(), N, isUnDroppableUser); + return hasNItems(use_begin(), use_end(), N, isUnDroppableUse); } bool Value::hasNUndroppableUsesOrMore(unsigned int N) const { - return hasNItemsOrMore(user_begin(), user_end(), N, isUnDroppableUser); + return hasNItemsOrMore(use_begin(), use_end(), N, isUnDroppableUse); } void Value::dropDroppableUses( llvm::function_ref ShouldDrop) { SmallVector ToBeEdited; for (Use &U : uses()) - if (U.getUser()->isDroppable() && ShouldDrop(&U)) + if (U.isDroppable() && ShouldDrop(&U)) ToBeEdited.push_back(&U); for (Use *U : ToBeEdited) { U->removeFromList(); diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -4428,8 +4428,7 @@ /// See CaptureTracker::shouldExplore(...). bool shouldExplore(const Use *U) override { // Check liveness and ignore droppable users. - return !U->getUser()->isDroppable() && - !A.isAssumedDead(*U, &NoCaptureAA, &IsDeadAA); + return !U->isDroppable() && !A.isAssumedDead(*U, &NoCaptureAA, &IsDeadAA); } /// Update the state according to \p CapturedInMem, \p CapturedInInt, and @@ -7452,7 +7451,7 @@ LLVM_DEBUG(dbgs() << "[Attributor] Dead use, skip!\n"); continue; } - if (U->getUser()->isDroppable()) { + if (U->isDroppable()) { LLVM_DEBUG(dbgs() << "[Attributor] Droppable user, skip!\n"); continue; }