Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -1686,6 +1686,29 @@ static const char ID; }; +/// An abstract attribute for undefined behavior. +struct AAUndefinedBehavior + : public StateWrapper, + public IRPosition { + AAUndefinedBehavior(const IRPosition &IRP) : IRPosition(IRP) {} + + /// Return true if "undefined behavior" is assumed. + bool isAssumedToCauseUB() const { return getAssumed(); } + + /// Return true if "undefined behavior" is known. + bool isKnownToCauseUB() const { return getKnown(); } + + /// Return an IR position, see struct IRPosition. + const IRPosition &getIRPosition() const override { return *this; } + + /// Create an abstract attribute view for the position \p IRP. + static AAUndefinedBehavior &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// Unique ID (due to the unique address) + static const char ID; +}; + /// An abstract interface to determine reachability of point A to B. struct AAReachability : public StateWrapper, public IRPosition { Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -1987,6 +1987,73 @@ void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(norecurse); } }; +/// -------------------- Undefined-Behavior Attributes ------------------------ + +struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior { + AAUndefinedBehaviorImpl(const IRPosition &IRP) : AAUndefinedBehavior(IRP) {} + + SmallPtrSet NoUBLoads; + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + AAUndefinedBehavior::initialize(A); + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + size_t PrevSize = NoUBLoads.size(); + + auto CannotCauseUB = [&](Instruction &I) { + // If this load instruction is not one of the instructions + // that are already assumed to cause UB. + if (NoUBLoads.find(&I) == NoUBLoads.end()) { + // Find whether it can cause UB by checking if the pointer + // is null. However, null dereference is defined for some + // targets, so it is assumed to cause UB only for those + // that it is not. + bool CanCauseUB = false; + Value *PtrOp = cast(&I)->getPointerOperand(); + if (isa(PtrOp)) { + Type *PtrTy = PtrOp->getType(); + const Function *F = I.getFunction(); + bool NullPointerIsDefined = + F ? llvm::NullPointerIsDefined(F, PtrTy->getPointerAddressSpace()) + : true; + if (!NullPointerIsDefined) { + CanCauseUB = true; + } + } + if (!CanCauseUB) { + NoUBLoads.insert(&I); + } + } + return true; + }; + A.checkForAllInstructions(CannotCauseUB, *this, {Instruction::Load}); + if (PrevSize != NoUBLoads.size()) + return ChangeStatus::CHANGED; + return ChangeStatus::UNCHANGED; + } + + /// See AbstractAttribute::getAsStr() + const std::string getAsStr() const override { + return getAssumed() ? "undefined-behavior" : "no-ub"; + } +}; + +struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl { + AAUndefinedBehaviorFunction(const IRPosition &IRP) + : AAUndefinedBehaviorImpl(IRP) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECL(UndefinedBehaviorInstruction, Instruction, + "Number of instructions known to have UB"); + BUILD_STAT_NAME(UndefinedBehaviorInstruction, Instruction) += + NoUBLoads.size(); + } +}; + /// ------------------------ Will-Return Attributes ---------------------------- // Helper function that checks whether a function has any cycle. @@ -5523,6 +5590,9 @@ // Every function might be "will-return". getOrCreateAAFor(FPos); + // Every function might contain instructions that cause "undefined behavior". + getOrCreateAAFor(FPos); + // Every function can be nounwind. getOrCreateAAFor(FPos); @@ -5827,6 +5897,7 @@ const char AANonNull::ID = 0; const char AANoRecurse::ID = 0; const char AAWillReturn::ID = 0; +const char AAUndefinedBehavior::ID = 0; const char AANoAlias::ID = 0; const char AAReachability::ID = 0; const char AANoReturn::ID = 0; @@ -5949,6 +6020,7 @@ CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReachability) +CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior) CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior)