const AbstractAttribute *AA,
SmallVectorImpl<AA::ValueAndContext> &Values,
AA::ValueScope S,
- bool &UsedAssumedInformation);
+ bool &UsedAssumedInformation,
+ bool RecurseForSelectAndPHI = true);
/// Register \p CB as a simplification callback.
/// `Attributor::getAssumedSimplified` will use these callbacks before
bool &UsedAssumedInformation,
bool CheckPotentiallyDead = false);
- /// Check \p Pred on all values potentially returned by \p F.
- ///
- /// This method will evaluate \p Pred on all values potentially returned by
- /// the function associated with \p QueryingAA. The returned values are
- /// matched with their respective return instructions. Returns true if \p Pred
- /// holds on all of them.
- bool checkForAllReturnedValuesAndReturnInsts(
- function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred,
- const AbstractAttribute &QueryingAA);
-
/// Check \p Pred on all values potentially returned by the function
/// associated with \p QueryingAA.
///
/// This is the context insensitive version of the method above.
- bool checkForAllReturnedValues(function_ref<bool(Value &)> Pred,
- const AbstractAttribute &QueryingAA);
+ bool
+ checkForAllReturnedValues(function_ref<bool(Value &)> Pred,
+ const AbstractAttribute &QueryingAA,
+ AA::ValueScope S = AA::ValueScope::Intraprocedural,
+ bool RecurseForSelectAndPHI = true);
/// Check \p Pred on all instructions in \p Fn with an opcode present in
/// \p Opcodes.
/// Abstract Attribute Classes
/// ----------------------------------------------------------------------------
-/// An abstract attribute for the returned values of a function.
-struct AAReturnedValues
- : public IRAttribute<Attribute::Returned, AbstractAttribute,
- AAReturnedValues> {
- AAReturnedValues(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
-
- /// Check \p Pred on all returned values.
- ///
- /// This method will evaluate \p Pred on returned values and return
- /// true if (1) all returned values are known, and (2) \p Pred returned true
- /// for all returned values.
- ///
- /// Note: Unlike the Attributor::checkForAllReturnedValuesAndReturnInsts
- /// method, this one will not filter dead return instructions.
- virtual bool checkForAllReturnedValuesAndReturnInsts(
- function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred)
- const = 0;
-
- using iterator =
- MapVector<Value *, SmallSetVector<ReturnInst *, 4>>::iterator;
- using const_iterator =
- MapVector<Value *, SmallSetVector<ReturnInst *, 4>>::const_iterator;
- virtual llvm::iterator_range<iterator> returned_values() = 0;
- virtual llvm::iterator_range<const_iterator> returned_values() const = 0;
-
- virtual size_t getNumReturnValues() const = 0;
-
- /// Create an abstract attribute view for the position \p IRP.
- static AAReturnedValues &createForPosition(const IRPosition &IRP,
- Attributor &A);
-
- /// See AbstractAttribute::getName()
- const std::string getName() const override { return "AAReturnedValues"; }
-
- /// See AbstractAttribute::getIdAddr()
- const char *getIdAddr() const override { return &ID; }
-
- /// This function should return true if the type of the \p AA is
- /// AAReturnedValues
- static bool classof(const AbstractAttribute *AA) {
- return (AA->getIdAddr() == &ID);
- }
-
- /// Unique ID (due to the unique address)
- static const char ID;
-};
-
struct AANoUnwind
: public IRAttribute<Attribute::NoUnwind,
StateWrapper<BooleanState, AbstractAttribute>,
static const char ID;
private:
- virtual bool
- getAssumedSimplifiedValues(Attributor &A,
- SmallVectorImpl<AA::ValueAndContext> &Values,
- AA::ValueScope) const = 0;
+ virtual bool getAssumedSimplifiedValues(
+ Attributor &A, SmallVectorImpl<AA::ValueAndContext> &Values,
+ AA::ValueScope, bool RecurseForSelectAndPHI = false) const = 0;
friend struct Attributor;
};
}
bool Attributor::getAssumedSimplifiedValues(
- const IRPosition &IRP, const AbstractAttribute *AA,
+ const IRPosition &InitialIRP, const AbstractAttribute *AA,
SmallVectorImpl<AA::ValueAndContext> &Values, AA::ValueScope S,
- bool &UsedAssumedInformation) {
- // First check all callbacks provided by outside AAs. If any of them returns
- // a non-null value that is different from the associated value, or
- // std::nullopt, we assume it's simplified.
- const auto &SimplificationCBs = SimplificationCallbacks.lookup(IRP);
- for (const auto &CB : SimplificationCBs) {
- std::optional<Value *> CBResult = CB(IRP, AA, UsedAssumedInformation);
- if (!CBResult.has_value())
- continue;
- Value *V = *CBResult;
- if (!V)
- return false;
- if ((S & AA::ValueScope::Interprocedural) ||
- AA::isValidInScope(*V, IRP.getAnchorScope()))
- Values.push_back(AA::ValueAndContext{*V, nullptr});
- else
- return false;
- }
- if (!SimplificationCBs.empty())
- return true;
+ bool &UsedAssumedInformation, bool RecurseForSelectAndPHI) {
+ SmallPtrSet<Value *, 8> Seen;
+ SmallVector<IRPosition, 8> Worklist;
+ Worklist.push_back(InitialIRP);
+ while (!Worklist.empty()) {
+ const IRPosition &IRP = Worklist.pop_back_val();
+
+ // First check all callbacks provided by outside AAs. If any of them returns
+ // a non-null value that is different from the associated value, or
+ // std::nullopt, we assume it's simplified.
+ int NV = Values.size();
+ const auto &SimplificationCBs = SimplificationCallbacks.lookup(IRP);
+ for (const auto &CB : SimplificationCBs) {
+ std::optional<Value *> CBResult = CB(IRP, AA, UsedAssumedInformation);
+ if (!CBResult.has_value())
+ continue;
+ Value *V = *CBResult;
+ if (!V)
+ return false;
+ if ((S & AA::ValueScope::Interprocedural) ||
+ AA::isValidInScope(*V, IRP.getAnchorScope()))
+ Values.push_back(AA::ValueAndContext{*V, nullptr});
+ else
+ return false;
+ }
+ if (SimplificationCBs.empty()) {
+ // If no high-level/outside simplification occurred, use
+ // AAPotentialValues.
+ const auto *PotentialValuesAA =
+ getOrCreateAAFor<AAPotentialValues>(IRP, AA, DepClassTy::OPTIONAL);
+ if (PotentialValuesAA && PotentialValuesAA->getAssumedSimplifiedValues(*this, Values, S)) {
+ UsedAssumedInformation |= !PotentialValuesAA->isAtFixpoint();
+ } else if (IRP.getPositionKind() != IRPosition::IRP_RETURNED) {
+ Values.push_back({IRP.getAssociatedValue(), IRP.getCtxI()});
+ } else {
+ // TODO: We could visit all returns and add the operands.
+ return false;
+ }
+ }
- // If no high-level/outside simplification occurred, use AAPotentialValues.
- const auto *PotentialValuesAA =
- getOrCreateAAFor<AAPotentialValues>(IRP, AA, DepClassTy::OPTIONAL);
- if (!PotentialValuesAA ||
- !PotentialValuesAA->getAssumedSimplifiedValues(*this, Values, S))
- return false;
- UsedAssumedInformation |= !PotentialValuesAA->isAtFixpoint();
+ if (!RecurseForSelectAndPHI)
+ break;
+
+ for (int I = NV, E = Values.size(); I < E; ++I) {
+ Value *V = Values[I].getValue();
+ if (!isa<PHINode>(V) && !isa<SelectInst>(V))
+ continue;
+ if (!Seen.insert(V).second)
+ continue;
+ // Move the last element to this slot.
+ Values[I] = Values[E - 1];
+ // Eliminate the last slot, adjust the indices.
+ Values.pop_back();
+ --E;
+ --I;
+ // Add a new value (select or phi) to the worklist.
+ Worklist.push_back(IRPosition::value(*V));
+ }
+ }
return true;
}
return EnableCallSiteSpecific;
}
-bool Attributor::checkForAllReturnedValuesAndReturnInsts(
- function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred,
- const AbstractAttribute &QueryingAA) {
+bool Attributor::checkForAllReturnedValues(function_ref<bool(Value &)> Pred,
+ const AbstractAttribute &QueryingAA,
+ AA::ValueScope S,
+ bool RecurseForSelectAndPHI) {
const IRPosition &IRP = QueryingAA.getIRPosition();
- // Since we need to provide return instructions we have to have an exact
- // definition.
const Function *AssociatedFunction = IRP.getAssociatedFunction();
if (!AssociatedFunction)
return false;
- // If this is a call site query we use the call site specific return values
- // and liveness information.
- // TODO: use the function scope once we have call site AAReturnedValues.
- const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction);
- const auto *AARetVal =
- getAAFor<AAReturnedValues>(QueryingAA, QueryIRP, DepClassTy::REQUIRED);
- if (!AARetVal || !AARetVal->getState().isValidState())
- return false;
-
- return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred);
-}
-
-bool Attributor::checkForAllReturnedValues(
- function_ref<bool(Value &)> Pred, const AbstractAttribute &QueryingAA) {
-
- const IRPosition &IRP = QueryingAA.getIRPosition();
- const Function *AssociatedFunction = IRP.getAssociatedFunction();
- if (!AssociatedFunction)
- return false;
-
- // TODO: use the function scope once we have call site AAReturnedValues.
- const IRPosition &QueryIRP = IRPosition::function(
- *AssociatedFunction, QueryingAA.getCallBaseContext());
- const auto *AARetVal =
- getAAFor<AAReturnedValues>(QueryingAA, QueryIRP, DepClassTy::REQUIRED);
- if (!AARetVal || !AARetVal->getState().isValidState())
+ bool UsedAssumedInformation;
+ SmallVector<AA::ValueAndContext> Values;
+ if (!getAssumedSimplifiedValues(
+ IRPosition::returned(*AssociatedFunction), &QueryingAA, Values, S,
+ UsedAssumedInformation, RecurseForSelectAndPHI))
return false;
- return AARetVal->checkForAllReturnedValuesAndReturnInsts(
- [&](Value &RV, const SmallSetVector<ReturnInst *, 4> &) {
- return Pred(RV);
- });
+ return llvm::all_of(Values, [&](const AA::ValueAndContext &VAC) {
+ return Pred(*VAC.getValue());
+ });
}
static bool checkForAllInstructionsImpl(
if (!Fn || Fn->isDeclaration())
return false;
- // TODO: use the function scope once we have call site AAReturnedValues.
const IRPosition &QueryIRP = IRPosition::function(*Fn);
const auto *LivenessAA =
CheckPotentiallyDead
if (!AssociatedFunction)
return false;
- // TODO: use the function scope once we have call site AAReturnedValues.
const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction);
const auto *LivenessAA =
getAAFor<AAIsDead>(QueryingAA, QueryIRP, DepClassTy::NONE);
// Return attributes are only appropriate if the return type is non void.
Type *ReturnType = F.getReturnType();
if (!ReturnType->isVoidTy()) {
- // Argument attribute "returned" --- Create only one per function even
- // though it is an argument attribute.
- getOrCreateAAFor<AAReturnedValues>(FPos);
-
IRPosition RetPos = IRPosition::returned(F);
AttributeSet RetAttrs = Attrs.getRetAttrs();
PIPE_OPERATOR(AANonConvergent)
PIPE_OPERATOR(AAWillReturn)
PIPE_OPERATOR(AANoReturn)
-PIPE_OPERATOR(AAReturnedValues)
PIPE_OPERATOR(AANonNull)
PIPE_OPERATOR(AAMustProgress)
PIPE_OPERATOR(AANoAlias)
/// Clamp the information known for all returned values of a function
/// (identified by \p QueryingAA) into \p S.
template <typename AAType, typename StateType = typename AAType::StateType,
- Attribute::AttrKind IRAttributeKind = Attribute::None>
+ Attribute::AttrKind IRAttributeKind = Attribute::None,
+ bool RecurseForSelectAndPHI = true>
static void clampReturnedValueStates(
Attributor &A, const AAType &QueryingAA, StateType &S,
const IRPosition::CallBaseContext *CBContext = nullptr) {
return T->isValidState();
};
- if (!A.checkForAllReturnedValues(CheckReturnValue, QueryingAA))
+ if (!A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,
+ AA::ValueScope::Intraprocedural,
+ RecurseForSelectAndPHI))
S.indicatePessimisticFixpoint();
else if (T)
S ^= *T;
template <typename AAType, typename BaseType,
typename StateType = typename BaseType::StateType,
bool PropagateCallBaseContext = false,
- Attribute::AttrKind IRAttributeKind = Attribute::None>
+ Attribute::AttrKind IRAttributeKind = Attribute::None,
+ bool RecurseForSelectAndPHI = true>
struct AAReturnedFromReturnedValues : public BaseType {
AAReturnedFromReturnedValues(const IRPosition &IRP, Attributor &A)
: BaseType(IRP, A) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
StateType S(StateType::getBestState(this->getState()));
- clampReturnedValueStates<AAType, StateType, IRAttributeKind>(
+ clampReturnedValueStates<AAType, StateType, IRAttributeKind, RecurseForSelectAndPHI>(
A, *this, S,
PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
// TODO: If we know we visited all returned values, thus no are assumed
};
} // namespace
-/// --------------------- Function Return Values -------------------------------
-
-namespace {
-/// "Attribute" that collects all potential returned values and the return
-/// instructions that they arise from.
-///
-/// If there is a unique returned value R, the manifest method will:
-/// - mark R with the "returned" attribute, if R is an argument.
-class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState {
-
- /// Mapping of values potentially returned by the associated function to the
- /// return instructions that might return them.
- MapVector<Value *, SmallSetVector<ReturnInst *, 4>> ReturnedValues;
-
- /// State flags
- ///
- ///{
- bool IsFixed = false;
- bool IsValidState = true;
- ///}
-
-public:
- AAReturnedValuesImpl(const IRPosition &IRP, Attributor &A)
- : AAReturnedValues(IRP, A) {}
-
- /// See AbstractAttribute::initialize(...).
- void initialize(Attributor &A) override {
- // Reset the state.
- IsFixed = false;
- IsValidState = true;
- ReturnedValues.clear();
-
- Function *F = getAssociatedFunction();
- if (!F || F->isDeclaration() || F->getReturnType()->isVoidTy()) {
- indicatePessimisticFixpoint();
- return;
- }
-
- // The map from instruction opcodes to those instructions in the function.
- auto &OpcodeInstMap = A.getInfoCache().getOpcodeInstMapForFunction(*F);
-
- // Look through all arguments, if one is marked as returned we are done.
- for (Argument &Arg : F->args()) {
- if (Arg.hasReturnedAttr()) {
- auto &ReturnInstSet = ReturnedValues[&Arg];
- if (auto *Insts = OpcodeInstMap.lookup(Instruction::Ret))
- for (Instruction *RI : *Insts)
- ReturnInstSet.insert(cast<ReturnInst>(RI));
-
- indicateOptimisticFixpoint();
- return;
- }
- }
- }
-
- /// See AbstractAttribute::manifest(...).
- ChangeStatus manifest(Attributor &A) override;
-
- /// See AbstractAttribute::getState(...).
- AbstractState &getState() override { return *this; }
-
- /// See AbstractAttribute::getState(...).
- const AbstractState &getState() const override { return *this; }
-
- /// See AbstractAttribute::updateImpl(Attributor &A).
- ChangeStatus updateImpl(Attributor &A) override;
-
- llvm::iterator_range<iterator> returned_values() override {
- return llvm::make_range(ReturnedValues.begin(), ReturnedValues.end());
- }
-
- llvm::iterator_range<const_iterator> returned_values() const override {
- return llvm::make_range(ReturnedValues.begin(), ReturnedValues.end());
- }
-
- /// Return the number of potential return values, -1 if unknown.
- size_t getNumReturnValues() const override {
- return isValidState() ? ReturnedValues.size() : -1;
- }
-
- /// Return an assumed unique return value if a single candidate is found. If
- /// there cannot be one, return a nullptr. If it is not clear yet, return
- /// std::nullopt.
- std::optional<Value *> getAssumedUniqueReturnValue(Attributor &A) const;
-
- /// See AbstractState::checkForAllReturnedValues(...).
- bool checkForAllReturnedValuesAndReturnInsts(
- function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred)
- const override;
-
- /// Pretty print the attribute similar to the IR representation.
- const std::string getAsStr(Attributor *A) const override;
-
- /// See AbstractState::isAtFixpoint().
- bool isAtFixpoint() const override { return IsFixed; }
-
- /// See AbstractState::isValidState().
- bool isValidState() const override { return IsValidState; }
-
- /// See AbstractState::indicateOptimisticFixpoint(...).
- ChangeStatus indicateOptimisticFixpoint() override {
- IsFixed = true;
- return ChangeStatus::UNCHANGED;
- }
-
- ChangeStatus indicatePessimisticFixpoint() override {
- IsFixed = true;
- IsValidState = false;
- return ChangeStatus::CHANGED;
- }
-};
-
-ChangeStatus AAReturnedValuesImpl::manifest(Attributor &A) {
- ChangeStatus Changed = ChangeStatus::UNCHANGED;
-
- // Bookkeeping.
- assert(isValidState());
- STATS_DECLTRACK(KnownReturnValues, FunctionReturn,
- "Number of function with known return values");
-
- // Check if we have an assumed unique return value that we could manifest.
- std::optional<Value *> UniqueRV = getAssumedUniqueReturnValue(A);
-
- if (!UniqueRV || !*UniqueRV)
- return Changed;
-
- // Bookkeeping.
- STATS_DECLTRACK(UniqueReturnValue, FunctionReturn,
- "Number of function with unique return");
- // If the assumed unique return value is an argument, annotate it.
- if (auto *UniqueRVArg = dyn_cast<Argument>(*UniqueRV)) {
- if (UniqueRVArg->getType()->canLosslesslyBitCastTo(
- getAssociatedFunction()->getReturnType())) {
- getIRPosition() = IRPosition::argument(*UniqueRVArg);
- Changed = IRAttribute::manifest(A);
- }
- }
- return Changed;
-}
-
-const std::string AAReturnedValuesImpl::getAsStr(Attributor *A) const {
- return (isAtFixpoint() ? "returns(#" : "may-return(#") +
- (isValidState() ? std::to_string(getNumReturnValues()) : "?") + ")";
-}
-
-std::optional<Value *>
-AAReturnedValuesImpl::getAssumedUniqueReturnValue(Attributor &A) const {
- // If checkForAllReturnedValues provides a unique value, ignoring potential
- // undef values that can also be present, it is assumed to be the actual
- // return value and forwarded to the caller of this method. If there are
- // multiple, a nullptr is returned indicating there cannot be a unique
- // returned value.
- std::optional<Value *> UniqueRV;
- Type *Ty = getAssociatedFunction()->getReturnType();
-
- auto Pred = [&](Value &RV) -> bool {
- UniqueRV = AA::combineOptionalValuesInAAValueLatice(UniqueRV, &RV, Ty);
- return UniqueRV != std::optional<Value *>(nullptr);
- };
-
- if (!A.checkForAllReturnedValues(Pred, *this))
- UniqueRV = nullptr;
-
- return UniqueRV;
-}
-
-bool AAReturnedValuesImpl::checkForAllReturnedValuesAndReturnInsts(
- function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred)
- const {
- if (!isValidState())
- return false;
-
- // Check all returned values but ignore call sites as long as we have not
- // encountered an overdefined one during an update.
- for (const auto &It : ReturnedValues) {
- Value *RV = It.first;
- if (!Pred(*RV, It.second))
- return false;
- }
-
- return true;
-}
-
-ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) {
- ChangeStatus Changed = ChangeStatus::UNCHANGED;
-
- SmallVector<AA::ValueAndContext> Values;
- bool UsedAssumedInformation = false;
- auto ReturnInstCB = [&](Instruction &I) {
- ReturnInst &Ret = cast<ReturnInst>(I);
- Values.clear();
- if (!A.getAssumedSimplifiedValues(IRPosition::value(*Ret.getReturnValue()),
- *this, Values, AA::Intraprocedural,
- UsedAssumedInformation))
- Values.push_back({*Ret.getReturnValue(), Ret});
-
- for (auto &VAC : Values) {
- assert(AA::isValidInScope(*VAC.getValue(), Ret.getFunction()) &&
- "Assumed returned value should be valid in function scope!");
- if (ReturnedValues[VAC.getValue()].insert(&Ret))
- Changed = ChangeStatus::CHANGED;
- }
- return true;
- };
-
- // Discover returned values from all live returned instructions in the
- // associated function.
- if (!A.checkForAllInstructions(ReturnInstCB, *this, {Instruction::Ret},
- UsedAssumedInformation))
- return indicatePessimisticFixpoint();
- return Changed;
-}
-
-struct AAReturnedValuesFunction final : public AAReturnedValuesImpl {
- AAReturnedValuesFunction(const IRPosition &IRP, Attributor &A)
- : AAReturnedValuesImpl(IRP, A) {}
-
- /// See AbstractAttribute::trackStatistics()
- void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(returned) }
-};
-
-/// Returned values information for a call sites.
-struct AAReturnedValuesCallSite final : AAReturnedValuesImpl {
- AAReturnedValuesCallSite(const IRPosition &IRP, Attributor &A)
- : AAReturnedValuesImpl(IRP, A) {}
-
- /// See AbstractAttribute::initialize(...).
- void initialize(Attributor &A) override {
- // TODO: Once we have call site specific value information we can provide
- // call site specific liveness information and then it makes
- // sense to specialize attributes for call sites instead of
- // redirecting requests to the callee.
- llvm_unreachable("Abstract attributes for returned values are not "
- "supported for call sites yet!");
- }
-
- /// See AbstractAttribute::updateImpl(...).
- ChangeStatus updateImpl(Attributor &A) override {
- return indicatePessimisticFixpoint();
- }
-
- /// See AbstractAttribute::trackStatistics()
- void trackStatistics() const override {}
-};
-} // namespace
-
/// ------------------------ NoSync Function Attribute -------------------------
bool AANoSync::isAlignedBarrier(const CallBase &CB, bool ExecutedAligned) {
// TODO: we could do this in a more sophisticated way inside
// AAReturnedValues, e.g., track all values that escape through returns
// directly somehow.
- auto CheckReturnedArgs = [&](const AAReturnedValues *RVAA) {
- if (!RVAA || !RVAA->getState().isValidState())
+ auto CheckReturnedArgs = [&](bool &UsedAssumedInformation) {
+ SmallVector<AA::ValueAndContext> Values;
+ if (!A.getAssumedSimplifiedValues(IRPosition::returned(*F), this, Values,
+ AA::ValueScope::Intraprocedural,
+ UsedAssumedInformation))
return false;
bool SeenConstant = false;
- for (const auto &It : RVAA->returned_values()) {
- if (isa<Constant>(It.first)) {
+ for (const AA::ValueAndContext &VAC : Values) {
+ if (isa<Constant>(VAC.getValue())) {
if (SeenConstant)
return false;
SeenConstant = true;
- } else if (!isa<Argument>(It.first) ||
- It.first == getAssociatedArgument())
+ } else if (!isa<Argument>(VAC.getValue()) ||
+ VAC.getValue() == getAssociatedArgument())
return false;
}
return true;
if (AA::hasAssumedIRAttr<Attribute::NoUnwind>(
A, this, FnPos, DepClassTy::OPTIONAL, IsKnownNoUnwind)) {
bool IsVoidTy = F->getReturnType()->isVoidTy();
- const AAReturnedValues *RVAA =
- IsVoidTy ? nullptr
- : A.getAAFor<AAReturnedValues>(*this, FnPos,
-
- DepClassTy::OPTIONAL);
- if (IsVoidTy || CheckReturnedArgs(RVAA)) {
+ bool UsedAssumedInformation = false;
+ if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
T.addKnownBits(NOT_CAPTURED_IN_RET);
if (T.isKnown(NOT_CAPTURED_IN_MEM))
return ChangeStatus::UNCHANGED;
- if (IsKnownNoUnwind && (IsVoidTy || RVAA->getState().isAtFixpoint())) {
+ if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
addKnownBits(NOT_CAPTURED_IN_RET);
if (isKnown(NOT_CAPTURED_IN_MEM))
return indicateOptimisticFixpoint();
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
- auto Before = SimplifiedAssociatedValue;
- auto *RetAA = A.getAAFor<AAReturnedValues>(
- *this, IRPosition::function(*getAssociatedFunction()),
- DepClassTy::REQUIRED);
- auto PredForReturned =
- [&](Value &RetVal, const SmallSetVector<ReturnInst *, 4> &RetInsts) {
- bool UsedAssumedInformation = false;
- std::optional<Value *> CSRetVal =
- A.translateArgumentToCallSiteContent(
- &RetVal, *cast<CallBase>(getCtxI()), *this,
- UsedAssumedInformation);
- SimplifiedAssociatedValue = AA::combineOptionalValuesInAAValueLatice(
- SimplifiedAssociatedValue, CSRetVal, getAssociatedType());
- return SimplifiedAssociatedValue != std::optional<Value *>(nullptr);
- };
- if (!RetAA ||
- !RetAA->checkForAllReturnedValuesAndReturnInsts(PredForReturned))
- if (!askSimplifiedValueForOtherAAs(A))
return indicatePessimisticFixpoint();
- return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
- : ChangeStatus ::CHANGED;
}
void trackStatistics() const override {
: Base(IRP, A) {}
/// See AbstractAttribute::initialize(...).
- void initialize(Attributor &A) override {}
+ void initialize(Attributor &A) override {
+ if (!A.isFunctionIPOAmendable(*getAssociatedFunction()))
+ indicatePessimisticFixpoint();
+ }
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
AAPotentialConstantValuesReturned(const IRPosition &IRP, Attributor &A)
: Base(IRP, A) {}
+ void initialize(Attributor &A) override {
+ if (!A.isFunctionIPOAmendable(*getAssociatedFunction()))
+ indicatePessimisticFixpoint();
+ Base::initialize(A);
+ }
+
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
STATS_DECLTRACK_FNRET_ATTR(potential_values)
};
struct AANoFPClassReturned final
- : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl> {
+ : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
+ AANoFPClassImpl::StateType, false, Attribute::None, false> {
AANoFPClassReturned(const IRPosition &IRP, Attributor &A)
- : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl>(IRP, A) {}
+ : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
+ AANoFPClassImpl::StateType, false, Attribute::None, false>(
+ IRP, A) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
return nullptr;
}
- void addValue(Attributor &A, StateType &State, Value &V,
- const Instruction *CtxI, AA::ValueScope S,
- Function *AnchorScope) const {
+ virtual void addValue(Attributor &A, StateType &State, Value &V,
+ const Instruction *CtxI, AA::ValueScope S,
+ Function *AnchorScope) const {
IRPosition ValIRP = IRPosition::value(V);
if (auto *CB = dyn_cast_or_null<CallBase>(CtxI)) {
return ChangeStatus::UNCHANGED;
}
- bool getAssumedSimplifiedValues(Attributor &A,
- SmallVectorImpl<AA::ValueAndContext> &Values,
- AA::ValueScope S) const override {
+ bool getAssumedSimplifiedValues(
+ Attributor &A, SmallVectorImpl<AA::ValueAndContext> &Values,
+ AA::ValueScope S, bool RecurseForSelectAndPHI = false) const override {
if (!isValidState())
return false;
+ bool UsedAssumedInformation = false;
for (const auto &It : getAssumedSet())
- if (It.second & S)
+ if (It.second & S) {
+ if (RecurseForSelectAndPHI && (isa<PHINode>(It.first.getValue()) ||
+ isa<SelectInst>(It.first.getValue()))) {
+ if (A.getAssumedSimplifiedValues(
+ IRPosition::inst(*cast<Instruction>(It.first.getValue())),
+ this, Values, S, UsedAssumedInformation))
+ continue;
+ }
Values.push_back(It.first);
+ }
assert(!undefIsContained() && "Undef should be an explicit value!");
return true;
}
ChangeStatus updateImpl(Attributor &A) override {
auto AssumedBefore = getAssumed();
- genericValueTraversal(A);
+ genericValueTraversal(A, &getAssociatedValue());
return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
: ChangeStatus::CHANGED;
return false;
}
- void genericValueTraversal(Attributor &A) {
+ void genericValueTraversal(Attributor &A, Value *InitialV) {
SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
- Value *InitialV = &getAssociatedValue();
SmallSet<ItemInfo, 16> Visited;
SmallVector<ItemInfo, 16> Worklist;
Worklist.push_back({{*InitialV, getCtxI()}, AA::AnyScope});
}
};
-struct AAPotentialValuesReturned
- : AAReturnedFromReturnedValues<AAPotentialValues, AAPotentialValuesImpl> {
- using Base =
- AAReturnedFromReturnedValues<AAPotentialValues, AAPotentialValuesImpl>;
+struct AAPotentialValuesReturned : public AAPotentialValuesFloating {
+ using Base = AAPotentialValuesFloating;
AAPotentialValuesReturned(const IRPosition &IRP, Attributor &A)
: Base(IRP, A) {}
/// See AbstractAttribute::initialize(..).
void initialize(Attributor &A) override {
- if (A.hasSimplificationCallback(getIRPosition()))
+ Function *F = getAssociatedFunction();
+ if (!F || F->isDeclaration() || F->getReturnType()->isVoidTy()) {
indicatePessimisticFixpoint();
- else
- AAPotentialValues::initialize(A);
+ return;
+ }
+
+ for (Argument &Arg : F->args())
+ if (Arg.hasReturnedAttr()) {
+ addValue(A, getState(), Arg, nullptr, AA::AnyScope, F);
+ ReturnedArg = &Arg;
+ break;
+ }
+ if (!A.isFunctionIPOAmendable(*F) ||
+ A.hasSimplificationCallback(getIRPosition())) {
+ if (!ReturnedArg)
+ indicatePessimisticFixpoint();
+ else
+ indicateOptimisticFixpoint();
+ }
+ }
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ auto AssumedBefore = getAssumed();
+ bool UsedAssumedInformation;
+
+ SmallVector<AA::ValueAndContext> Values;
+ Function *AnchorScope = getAnchorScope();
+ auto HandleReturnedValue = [&](Value &V, Instruction *CtxI,
+ bool AddValues) {
+ for (AA::ValueScope S : {AA::Interprocedural, AA::Intraprocedural}) {
+ Values.clear();
+ if (!A.getAssumedSimplifiedValues(IRPosition::value(V), this, Values, S,
+ UsedAssumedInformation,
+ /* RecurseForSelectAndPHI */ true))
+ return false;
+ if (!AddValues)
+ continue;
+ for (const AA::ValueAndContext &VAC : Values)
+ addValue(A, getState(), *VAC.getValue(),
+ VAC.getCtxI() ? VAC.getCtxI() : CtxI, S, AnchorScope);
+ }
+ return true;
+ };
+
+ if (ReturnedArg) {
+ HandleReturnedValue(*ReturnedArg, nullptr, true);
+ } else {
+ auto RetInstPred = [&](Instruction &RetI) {
+ bool AddValues = true;
+ if (isa<PHINode>(RetI.getOperand(0)) ||
+ isa<SelectInst>(RetI.getOperand(0))) {
+ addValue(A, getState(), *RetI.getOperand(0), &RetI, AA::AnyScope,
+ AnchorScope);
+ AddValues = false;
+ }
+ return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
+ };
+
+ if (!A.checkForAllInstructions(RetInstPred, *this, {Instruction::Ret},
+ UsedAssumedInformation,
+ /* CheckBBLivenessOnly */ true))
+ return indicatePessimisticFixpoint();
+ }
+
+ return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
+ : ChangeStatus::CHANGED;
+ }
+
+ void addValue(Attributor &A, StateType &State, Value &V,
+ const Instruction *CtxI, AA::ValueScope S,
+ Function *AnchorScope) const override {
+ Function *F = getAssociatedFunction();
+ if (auto *CB = dyn_cast<CallBase>(&V))
+ if (CB->getCalledOperand() == F)
+ return;
+ Base::addValue(A, State, V, CtxI, S, AnchorScope);
}
ChangeStatus manifest(Attributor &A) override {
- // We queried AAValueSimplify for the returned values so they will be
- // replaced if a simplified form was found. Nothing to do here.
- return ChangeStatus::UNCHANGED;
+ if (ReturnedArg)
+ return ChangeStatus::UNCHANGED;
+ SmallVector<AA::ValueAndContext> Values;
+ if (!getAssumedSimplifiedValues(A, Values, AA::ValueScope::Intraprocedural,
+ /* RecurseForSelectAndPHI */ true))
+ return ChangeStatus::UNCHANGED;
+ Value *NewVal = getSingleValue(A, *this, getIRPosition(), Values);
+ if (!NewVal)
+ return ChangeStatus::UNCHANGED;
+
+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
+ if (auto *Arg = dyn_cast<Argument>(NewVal)) {
+ STATS_DECLTRACK(UniqueReturnValue, FunctionReturn,
+ "Number of function with unique return");
+ Changed |= A.manifestAttrs(
+ IRPosition::argument(*Arg),
+ {Attribute::get(Arg->getContext(), Attribute::Returned)});
+ STATS_DECLTRACK_ARG_ATTR(returned);
+ }
+
+ auto RetInstPred = [&](Instruction &RetI) {
+ Value *RetOp = RetI.getOperand(0);
+ if (isa<UndefValue>(RetOp) || RetOp == NewVal)
+ return true;
+ if (AA::isValidAtPosition({*NewVal, RetI}, A.getInfoCache()))
+ if (A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
+ Changed = ChangeStatus::CHANGED;
+ return true;
+ };
+ bool UsedAssumedInformation;
+ (void)A.checkForAllInstructions(RetInstPred, *this, {Instruction::Ret},
+ UsedAssumedInformation,
+ /* CheckBBLivenessOnly */ true);
+ return Changed;
}
ChangeStatus indicatePessimisticFixpoint() override {
}
/// See AbstractAttribute::trackStatistics()
- void trackStatistics() const override {
- STATS_DECLTRACK_FNRET_ATTR(potential_values)
- }
+ void trackStatistics() const override{
+ STATS_DECLTRACK_FNRET_ATTR(potential_values)}
+
+ /// The argumented with an existing `returned` attribute.
+ Argument *ReturnedArg = nullptr;
};
struct AAPotentialValuesFunction : AAPotentialValuesImpl {
};
} // namespace
-const char AAReturnedValues::ID = 0;
const char AANoUnwind::ID = 0;
const char AANoSync::ID = 0;
const char AANoFree::ID = 0;
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoRecurse)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAWillReturn)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn)
-CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryLocation)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAssumptionInfo)
; TUNIT-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4
; TUNIT-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4
; TUNIT-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]
-; TUNIT-NEXT: [[CA:%.*]] = musttail call noundef i32 @bar(ptr undef, i32 [[V]]) #[[ATTR5:[0-9]+]]
+; TUNIT-NEXT: [[CA:%.*]] = musttail call i32 @bar(ptr undef, i32 [[V]]) #[[ATTR5:[0-9]+]]
; TUNIT-NEXT: ret i32 [[CA]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; TUNIT-LABEL: define {{[^@]+}}@caller2b
; TUNIT-SAME: (ptr nocapture nofree readonly [[G:%.*]]) #[[ATTR3]] {
-; TUNIT-NEXT: [[V:%.*]] = call noundef i32 @test2b(ptr nocapture nofree readonly [[G]], i32 undef) #[[ATTR6:[0-9]+]]
-; TUNIT-NEXT: ret i32 [[V]]
+; TUNIT-NEXT: [[V:%.*]] = call i32 @test2b(ptr nocapture nofree readonly [[G]], i32 undef) #[[ATTR6:[0-9]+]]
+; TUNIT-NEXT: ret i32 0
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
; CGSCC-LABEL: define {{[^@]+}}@caller2b
; TUNIT: RET:
; TUNIT-NEXT: ret void
;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@caller
; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2:[0-9]+]] personality ptr @__gxx_personality_v0 {
; CGSCC-NEXT: [[Q:%.*]] = alloca i32, align 4
-; CGSCC-NEXT: [[W:%.*]] = call align 4 ptr @incdec(i1 noundef [[C]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[Q]]) #[[ATTR3:[0-9]+]]
+; CGSCC-NEXT: [[W:%.*]] = call align 4 ptr @incdec(i1 noundef [[C]], ptr noalias nofree noundef nonnull align 4 dereferenceable(4) [[Q]]) #[[ATTR3:[0-9]+]]
; CGSCC-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR4:[0-9]+]]
; CGSCC-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
; CGSCC-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR5:[0-9]+]]
;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn }
+; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR3]] = { nofree nounwind willreturn }
; CGSCC: attributes #[[ATTR4]] = { nofree willreturn }
; CGSCC: attributes #[[ATTR5]] = { nofree nounwind willreturn memory(none) }
; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_ret: [@-1]} with state set-state(< { %5 = getelementptr inbounds i32, ptr %0, i64 4[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
; GRAPH-NEXT: updates [AAPotentialValues] for CtxI ' %.0 = phi ptr [ %6, %4 ], [ %0, %7 ]' at position {flt:.0 [.0@-1]} with state set-state(< {ptr %0[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
; GRAPH-EMPTY:
-; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state set-state(< {ptr %0[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
+; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state set-state(< { %.0 = phi ptr [ %6, %4 ], [ %0, %7 ][3], } >)
; GRAPH-NEXT: updates [AAPotentialValues] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_ret: [@-1]} with state set-state(< { %5 = getelementptr inbounds i32, ptr %0, i64 4[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
-; GRAPH-EMPTY:
-; GRAPH-NEXT: [AAReturnedValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance@-1]} with state may-return(#2)
-; GRAPH-NEXT: updates [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state set-state(< {ptr %0[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
+; GRAPH-NEXT: updates [AANoUndef] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state may-undef-or-poison
; GRAPH-NEXT: updates [AANoCapture] for CtxI ' %2 = load i32, ptr %0, align 4' at position {arg: [@0]} with state assumed not-captured-maybe-returned
; GRAPH-NEXT: updates [AAAlign] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state align<1-16>
; GRAPH-NEXT: updates [AANonNull] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state nonnull
-; GRAPH-EMPTY:
+; GRAPH-NEXT: updates [AADereferenceable] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state unknown-dereferenceable
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %.0 = phi ptr [ %6, %4 ], [ %0, %7 ]' at position {flt:.0 [.0@-1]} with state set-state(< {ptr %0[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
-; GRAPH-NEXT: updates [AAReturnedValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance@-1]} with state may-return(#2)
-; GRAPH-EMPTY:
+; GRAPH-NEXT: updates [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state set-state(< { %.0 = phi ptr [ %6, %4 ], [ %0, %7 ][3], } >)
+; GRAPH-NEXT: updates [AAPotentialValues] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_ret: [@-1]} with state set-state(< { %5 = getelementptr inbounds i32, ptr %0, i64 4[3], %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
+; GRAPH-NEXT: updates [AANoCapture] for CtxI ' %2 = load i32, ptr %0, align 4' at position {arg: [@0]} with state assumed not-captured-maybe-returned
+; GRAPH-NEXT: updates [AAAlign] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state align<1-16>
+; GRAPH-NEXT: updates [AANonNull] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn_ret:checkAndAdvance [checkAndAdvance@-1]} with state nonnull
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %5 = getelementptr inbounds i32, ptr %0, i64 4' at position {flt: [@-1]} with state set-state(< { %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
-; GRAPH-EMPTY:
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAPotentialValues] for CtxI <<null inst>> at position {flt: [@-1]} with state set-state(< {i64 4[3], } >)
-; GRAPH-EMPTY:
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {flt:checkAndAdvance [checkAndAdvance@-1]} with state set-state(< {@checkAndAdvance[3], } >)
-; GRAPH-EMPTY:
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_arg: [@0]} with state set-state(< { %5 = getelementptr inbounds i32, ptr %0, i64 4[3], } >)
-; GRAPH-EMPTY:
+; GRAPH-EMPTY:
; GRAPH-NEXT: [AAInstanceInfo] for CtxI ' %5 = getelementptr inbounds i32, ptr %0, i64 4' at position {flt: [@-1]} with state <unique [fAa]>
; GRAPH-EMPTY:
; GRAPH-NEXT: [AANoRecurse] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance@-1]} with state may-recurse
; DOT-DAG: Node[[Node18:0x[a-z0-9]+]] [shape=record,label="{[AAMemoryBehavior]
; DOT-DAG: Node[[Node19:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
; DOT-DAG: Node[[Node20:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
-; DOT-DAG: Node[[Node21:0x[a-z0-9]+]] [shape=record,label="{[AAReturnedValues]
; DOT-DAG: Node[[Node22:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
; DOT-DAG: Node[[Node23:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
; DOT-DAG: Node[[Node24:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
; DOT-DAG: Node[[Node13]] -> Node[[Node12]];
; DOT-DAG: Node[[Node55]] -> Node[[Node56]];
; DOT-DAG: Node[[Node68]] -> Node[[Node73]];
-; DOT-DAG: Node[[Node21]] -> Node[[Node20]];
; DOT-DAG: Node[[Node64]] -> Node[[Node61]];
; DOT-DAG: Node[[Node61]] -> Node[[Node64]];
; DOT-DAG: Node[[Node12]] -> Node[[Node13]];
; DOT-DAG: Node[[Node11]] -> Node[[Node61]];
; DOT-DAG: Node[[Node14]] -> Node[[Node18]];
-; DOT-DAG: Node[[Node22]] -> Node[[Node21]];
; DOT-DAG: Node[[Node43]] -> Node[[Node68]];
; DOT-DAG: Node[[Node19]] -> Node[[Node22]];
-; DOT-DAG: Node[[Node21]] -> Node[[Node51]];
; DOT-DAG: Node[[Node10]] -> Node[[Node11]];
; DOT-DAG: Node[[Node41]] -> Node[[Node42]];
; DOT-DAG: Node[[Node42]] -> Node[[Node41]];
; DOT-DAG: Node[[Node11]] -> Node[[Node10]];
-; DOT-DAG: Node[[Node21]] -> Node[[Node61]];
; DOT-DAG: Node[[Node67]] -> Node[[Node66]];
; DOT-DAG: Node[[Node18]] -> Node[[Node14]];
; DOT-DAG: Node[[Node66]] -> Node[[Node67]];
-; DOT-DAG: Node[[Node21]] -> Node[[Node47]];
; DOT-DAG: Node[[Node44]] -> Node[[Node43]];
; DOT-DAG: Node[[Node43]] -> Node[[Node44]];
;.
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
; TUNIT-LABEL: define {{[^@]+}}@c3
; TUNIT-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR1]] {
-; TUNIT-NEXT: call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR14:[0-9]+]]
+; TUNIT-NEXT: call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR16:[0-9]+]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
; CGSCC-LABEL: define {{[^@]+}}@c3
; CGSCC-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR2:[0-9]+]] {
-; CGSCC-NEXT: call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR17:[0-9]+]]
+; CGSCC-NEXT: call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR19:[0-9]+]]
; CGSCC-NEXT: ret void
;
call void @c2(ptr %q)
; CHECK-LABEL: define {{[^@]+}}@c4
; CHECK-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
-; CHECK-NEXT: [[TRUETMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
-; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TRUETMP2]] to i1
+; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
+; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
; CHECK-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
; CHECK: l0:
; CHECK-NEXT: ret i1 false
; CHECK-LABEL: define {{[^@]+}}@c4b
; CHECK-SAME: (ptr nocapture nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
-; CHECK-NEXT: [[TRUETMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
-; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TRUETMP2]] to i1
+; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
+; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
; CHECK-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
; CHECK: l0:
; CHECK-NEXT: ret i1 false
; TUNIT-LABEL: define {{[^@]+}}@c5
; TUNIT-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2:[0-9]+]] {
; TUNIT-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
-; TUNIT-NEXT: [[TRUETMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
-; TUNIT-NEXT: [[BIT:%.*]] = and i32 [[TRUETMP2]], 1
+; TUNIT-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
+; TUNIT-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1
; TUNIT-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
; TUNIT-NEXT: [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1
; TUNIT-NEXT: ret i1 [[VAL]]
; CGSCC-LABEL: define {{[^@]+}}@c5
; CGSCC-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR3:[0-9]+]] {
; CGSCC-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
-; CGSCC-NEXT: [[TRUETMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
-; CGSCC-NEXT: [[BIT:%.*]] = and i32 [[TRUETMP2]], 1
+; CGSCC-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
+; CGSCC-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1
; CGSCC-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
; CGSCC-NEXT: [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1
; CGSCC-NEXT: ret i1 [[VAL]]
; CHECK-LABEL: define {{[^@]+}}@lookup_bit
; CHECK-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
-; CHECK-NEXT: [[TRUETMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
-; CHECK-NEXT: [[BIT:%.*]] = and i32 [[TRUETMP2]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
+; CHECK-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1
; CHECK-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
; CHECK-NEXT: ret ptr [[LOOKUP]]
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@c7
; TUNIT-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr noalias nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR15:[0-9]+]]
+; TUNIT-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr noalias nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR17:[0-9]+]]
; TUNIT-NEXT: [[VAL:%.*]] = load i1, ptr [[PTR]], align 1
; TUNIT-NEXT: ret i1 [[VAL]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@c7
; CGSCC-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR5:[0-9]+]] {
-; CGSCC-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr noalias nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR18:[0-9]+]]
+; CGSCC-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr noalias nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR20:[0-9]+]]
; CGSCC-NEXT: [[VAL:%.*]] = load i1, ptr [[PTR]], align 1
; CGSCC-NEXT: ret i1 [[VAL]]
;
; TUNIT: l:
; TUNIT-NEXT: [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ]
; TUNIT-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
-; TUNIT-NEXT: [[TRUETMP2:%.*]] = select i1 [[B]], ptr [[P]], ptr [[Q]]
-; TUNIT-NEXT: [[VAL:%.*]] = load i32, ptr [[TRUETMP2]], align 4
+; TUNIT-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[P]], ptr [[Q]]
+; TUNIT-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
; TUNIT-NEXT: store i32 0, ptr [[P]], align 4
; TUNIT-NEXT: store ptr [[Q]], ptr @g, align 8
; TUNIT-NEXT: ret i32 [[VAL]]
; CGSCC: l:
; CGSCC-NEXT: [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ]
; CGSCC-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
-; CGSCC-NEXT: [[TRUETMP2:%.*]] = select i1 [[B]], ptr [[P]], ptr [[Q]]
-; CGSCC-NEXT: [[VAL:%.*]] = load i32, ptr [[TRUETMP2]], align 4
+; CGSCC-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[P]], ptr [[Q]]
+; CGSCC-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
; CGSCC-NEXT: store i32 0, ptr [[P]], align 4
; CGSCC-NEXT: store ptr [[Q]], ptr @g, align 8
; CGSCC-NEXT: ret i32 [[VAL]]
; TUNIT-NEXT: [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ]
; TUNIT-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
; TUNIT-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[P]] to ptr
-; TUNIT-NEXT: [[TRUETMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]]
-; TUNIT-NEXT: [[VAL:%.*]] = load i32, ptr [[TRUETMP2]], align 4
+; TUNIT-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]]
+; TUNIT-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
; TUNIT-NEXT: store i32 0, ptr addrspace(1) [[P]], align 4
; TUNIT-NEXT: store ptr [[Q]], ptr @g, align 8
; TUNIT-NEXT: ret i32 [[VAL]]
; CGSCC-NEXT: [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ]
; CGSCC-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
; CGSCC-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[P]] to ptr
-; CGSCC-NEXT: [[TRUETMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]]
-; CGSCC-NEXT: [[VAL:%.*]] = load i32, ptr [[TRUETMP2]], align 4
+; CGSCC-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]]
+; CGSCC-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
; CGSCC-NEXT: store i32 0, ptr addrspace(1) [[P]], align 4
; CGSCC-NEXT: store ptr [[Q]], ptr @g, align 8
; CGSCC-NEXT: ret i32 [[VAL]]
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@nc2
; TUNIT-SAME: (ptr nocapture nofree [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nocapture nofree [[P]], i1 noundef false) #[[ATTR16:[0-9]+]]
+; TUNIT-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nocapture nofree [[P]], i1 noundef false) #[[ATTR18:[0-9]+]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@nc2
; CGSCC-SAME: (ptr nocapture nofree align 4 [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR7:[0-9]+]] {
-; CGSCC-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nocapture nofree align 4 [[P]], i1 noundef false) #[[ATTR19:[0-9]+]]
+; CGSCC-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nocapture nofree align 4 [[P]], i1 noundef false) #[[ATTR21:[0-9]+]]
; CGSCC-NEXT: ret void
;
%1 = call i32 @nc1(ptr %q, ptr %p, i1 0) ; <i32> [#uses=0]
; TUNIT: Function Attrs: nounwind memory(argmem: readwrite)
; TUNIT-LABEL: define {{[^@]+}}@nc4
; TUNIT-SAME: (ptr nofree [[P:%.*]]) #[[ATTR5:[0-9]+]] {
-; TUNIT-NEXT: call void @external(ptr nofree readonly [[P]]) #[[ATTR17:[0-9]+]]
+; TUNIT-NEXT: call void @external(ptr nofree readonly [[P]]) #[[ATTR19:[0-9]+]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: nounwind memory(argmem: readwrite)
; CGSCC-LABEL: define {{[^@]+}}@nc4
; CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR8:[0-9]+]] {
-; CGSCC-NEXT: call void @external(ptr nofree readonly [[P]]) #[[ATTR20:[0-9]+]]
+; CGSCC-NEXT: call void @external(ptr nofree readonly [[P]]) #[[ATTR22:[0-9]+]]
; CGSCC-NEXT: ret void
;
call void @external(ptr %p)
}
define void @nocaptureLaunder(ptr %p) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
; TUNIT-LABEL: define {{[^@]+}}@nocaptureLaunder
-; TUNIT-SAME: (ptr nocapture nofree [[P:%.*]]) #[[ATTR4]] {
+; TUNIT-SAME: (ptr nocapture nofree [[P:%.*]]) #[[ATTR8:[0-9]+]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR18:[0-9]+]]
+; TUNIT-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR20:[0-9]+]]
; TUNIT-NEXT: store i8 42, ptr [[B]], align 1
; TUNIT-NEXT: ret void
;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
; CGSCC-LABEL: define {{[^@]+}}@nocaptureLaunder
-; CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) #[[ATTR6]] {
+; CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) #[[ATTR11:[0-9]+]] {
; CGSCC-NEXT: entry:
-; CGSCC-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR18]]
+; CGSCC-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR20]]
; CGSCC-NEXT: store i8 42, ptr [[B]], align 1
; CGSCC-NEXT: ret void
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@captureLaunder
; TUNIT-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR18]]
+; TUNIT-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR20]]
; TUNIT-NEXT: store ptr [[B]], ptr @g2, align 8
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@captureLaunder
; CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR6]] {
-; CGSCC-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR18]]
+; CGSCC-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr nofree [[P]]) #[[ATTR20]]
; CGSCC-NEXT: store ptr [[B]], ptr @g2, align 8
; CGSCC-NEXT: ret void
;
}
define void @nocaptureStrip(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; CHECK-LABEL: define {{[^@]+}}@nocaptureStrip
-; CHECK-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr noalias nofree readnone [[P]]) #[[ATTR18:[0-9]+]]
-; CHECK-NEXT: store i8 42, ptr [[B]], align 1
-; CHECK-NEXT: ret void
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-LABEL: define {{[^@]+}}@nocaptureStrip
+; TUNIT-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR9:[0-9]+]] {
+; TUNIT-NEXT: entry:
+; TUNIT-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr noalias nofree readnone [[P]]) #[[ATTR20]]
+; TUNIT-NEXT: store i8 42, ptr [[B]], align 1
+; TUNIT-NEXT: ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@nocaptureStrip
+; CGSCC-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR12:[0-9]+]] {
+; CGSCC-NEXT: entry:
+; CGSCC-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr noalias nofree readnone [[P]]) #[[ATTR20]]
+; CGSCC-NEXT: store i8 42, ptr [[B]], align 1
+; CGSCC-NEXT: ret void
;
entry:
%b = call ptr @llvm.strip.invariant.group.p0(ptr %p)
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
; CHECK-LABEL: define {{[^@]+}}@captureStrip
; CHECK-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr noalias nofree readnone [[P]]) #[[ATTR18]]
+; CHECK-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr noalias nofree readnone [[P]]) #[[ATTR20:[0-9]+]]
; CHECK-NEXT: store ptr [[B]], ptr @g3, align 8
; CHECK-NEXT: ret void
;
define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@captureDereferenceableOrNullICmp
-; TUNIT-SAME: (ptr nofree noundef readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR8:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree noundef readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR10:[0-9]+]] {
; TUNIT-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; TUNIT-NEXT: ret i1 [[TMP1]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@captureDereferenceableOrNullICmp
-; CGSCC-SAME: (ptr nofree noundef readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR11:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree noundef readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR13:[0-9]+]] {
; CGSCC-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; CGSCC-NEXT: ret i1 [[TMP1]]
;
define ptr @test_returned1(ptr %A, ptr returned %B) nounwind readonly {
; TUNIT: Function Attrs: nounwind memory(read)
; TUNIT-LABEL: define {{[^@]+}}@test_returned1
-; TUNIT-SAME: (ptr nocapture [[A:%.*]], ptr returned [[B:%.*]]) #[[ATTR9:[0-9]+]] {
+; TUNIT-SAME: (ptr nocapture [[A:%.*]], ptr returned [[B:%.*]]) #[[ATTR11:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr [[A]], ptr [[B]])
; TUNIT-NEXT: ret ptr [[P]]
;
; CGSCC: Function Attrs: nounwind memory(read)
; CGSCC-LABEL: define {{[^@]+}}@test_returned1
-; CGSCC-SAME: (ptr nocapture [[A:%.*]], ptr returned [[B:%.*]]) #[[ATTR12:[0-9]+]] {
+; CGSCC-SAME: (ptr nocapture [[A:%.*]], ptr returned [[B:%.*]]) #[[ATTR14:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr [[A]], ptr [[B]])
; CGSCC-NEXT: ret ptr [[P]]
define ptr @test_returned2(ptr %A, ptr %B) {
; TUNIT: Function Attrs: nounwind memory(read)
; TUNIT-LABEL: define {{[^@]+}}@test_returned2
-; TUNIT-SAME: (ptr readonly [[A:%.*]], ptr readonly [[B:%.*]]) #[[ATTR9]] {
+; TUNIT-SAME: (ptr readonly [[A:%.*]], ptr readonly [[B:%.*]]) #[[ATTR11]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr readonly [[A]], ptr readonly [[B]]) #[[ATTR9]]
+; TUNIT-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr readonly [[A]], ptr readonly [[B]]) #[[ATTR11]]
; TUNIT-NEXT: ret ptr [[P]]
;
; CGSCC: Function Attrs: nounwind memory(read)
; CGSCC-LABEL: define {{[^@]+}}@test_returned2
-; CGSCC-SAME: (ptr readonly [[A:%.*]], ptr readonly [[B:%.*]]) #[[ATTR12]] {
+; CGSCC-SAME: (ptr readonly [[A:%.*]], ptr readonly [[B:%.*]]) #[[ATTR14]] {
; CGSCC-NEXT: entry:
-; CGSCC-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr readonly [[A]], ptr readonly [[B]]) #[[ATTR12]]
+; CGSCC-NEXT: [[P:%.*]] = call ptr @unknownpi8pi8(ptr readonly [[A]], ptr readonly [[B]]) #[[ATTR14]]
; CGSCC-NEXT: ret ptr [[P]]
;
entry:
define void @ptr_uses(ptr %ptr, ptr %wptr) {
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@ptr_uses
-; TUNIT-SAME: (ptr nofree [[PTR:%.*]], ptr nocapture nofree noundef nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) #[[ATTR11:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree [[PTR:%.*]], ptr nocapture nofree noundef nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) #[[ATTR13:[0-9]+]] {
; TUNIT-NEXT: store i8 0, ptr [[WPTR]], align 1
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@ptr_uses
-; CGSCC-SAME: (ptr nofree [[PTR:%.*]], ptr nocapture nofree noundef nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) #[[ATTR14:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree [[PTR:%.*]], ptr nocapture nofree noundef nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) #[[ATTR16:[0-9]+]] {
; CGSCC-NEXT: store i8 0, ptr [[WPTR]], align 1
; CGSCC-NEXT: ret void
;
; TUNIT: attributes #[[ATTR5]] = { nounwind memory(argmem: readwrite) }
; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind memory(write) }
; TUNIT: attributes #[[ATTR7]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR8]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
-; TUNIT: attributes #[[ATTR9]] = { nounwind memory(read) }
-; TUNIT: attributes #[[ATTR10:[0-9]+]] = { nounwind willreturn memory(read) }
-; TUNIT: attributes #[[ATTR11]] = { mustprogress nounwind willreturn }
-; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) }
-; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; TUNIT: attributes #[[ATTR14]] = { nofree nosync nounwind willreturn memory(write) }
-; TUNIT: attributes #[[ATTR15]] = { nofree nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR16]] = { nofree nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR17]] = { nounwind }
-; TUNIT: attributes #[[ATTR18]] = { nofree willreturn }
+; TUNIT: attributes #[[ATTR8]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
+; TUNIT: attributes #[[ATTR9]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; TUNIT: attributes #[[ATTR10]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
+; TUNIT: attributes #[[ATTR11]] = { nounwind memory(read) }
+; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nounwind willreturn memory(read) }
+; TUNIT: attributes #[[ATTR13]] = { mustprogress nounwind willreturn }
+; TUNIT: attributes #[[ATTR14:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) }
+; TUNIT: attributes #[[ATTR15:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR16]] = { nofree nosync nounwind willreturn memory(write) }
+; TUNIT: attributes #[[ATTR17]] = { nofree nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR18]] = { nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR19]] = { nounwind }
+; TUNIT: attributes #[[ATTR20]] = { nofree willreturn }
;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(write) }
; CGSCC: attributes #[[ATTR8]] = { nounwind memory(argmem: readwrite) }
; CGSCC: attributes #[[ATTR9]] = { nofree nosync nounwind memory(write) }
; CGSCC: attributes #[[ATTR10]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) }
-; CGSCC: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
-; CGSCC: attributes #[[ATTR12]] = { nounwind memory(read) }
-; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn memory(read) }
-; CGSCC: attributes #[[ATTR14]] = { mustprogress nounwind willreturn }
-; CGSCC: attributes #[[ATTR15:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) }
-; CGSCC: attributes #[[ATTR16:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; CGSCC: attributes #[[ATTR17]] = { nofree nounwind willreturn memory(write) }
-; CGSCC: attributes #[[ATTR18]] = { nofree willreturn }
-; CGSCC: attributes #[[ATTR19]] = { nofree nounwind willreturn }
-; CGSCC: attributes #[[ATTR20]] = { nounwind }
+; CGSCC: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
+; CGSCC: attributes #[[ATTR12]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
+; CGSCC: attributes #[[ATTR14]] = { nounwind memory(read) }
+; CGSCC: attributes #[[ATTR15:[0-9]+]] = { nounwind willreturn memory(read) }
+; CGSCC: attributes #[[ATTR16]] = { mustprogress nounwind willreturn }
+; CGSCC: attributes #[[ATTR17:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) }
+; CGSCC: attributes #[[ATTR18:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CGSCC: attributes #[[ATTR19]] = { nofree nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR20]] = { nofree willreturn }
+; CGSCC: attributes #[[ATTR21]] = { nofree nounwind willreturn }
+; CGSCC: attributes #[[ATTR22]] = { nounwind }
;.
declare float @llvm.arithmetic.fence.f32(float)
define float @ret_select_nnan_flag(i1 %cond, float %arg0, float %arg1) {
-; CHECK-LABEL: define float @ret_select_nnan_flag
+; CHECK-LABEL: define nofpclass(nan) float @ret_select_nnan_flag
; CHECK-SAME: (i1 [[COND:%.*]], float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[SELECT:%.*]] = select nnan i1 [[COND]], float [[ARG0]], float [[ARG1]]
; CHECK-NEXT: ret float [[SELECT]]
}
define float @ret_select_ninf_flag(i1 %cond, float %arg0, float %arg1) {
-; CHECK-LABEL: define float @ret_select_ninf_flag
+; CHECK-LABEL: define nofpclass(inf) float @ret_select_ninf_flag
; CHECK-SAME: (i1 [[COND:%.*]], float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[SELECT:%.*]] = select ninf i1 [[COND]], float [[ARG0]], float [[ARG1]]
; CHECK-NEXT: ret float [[SELECT]]
}
define float @ret_select_nnan_ninf_flag(i1 %cond, float %arg0, float %arg1) {
-; CHECK-LABEL: define float @ret_select_nnan_ninf_flag
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_select_nnan_ninf_flag
; CHECK-SAME: (i1 [[COND:%.*]], float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[SELECT:%.*]] = select nnan ninf i1 [[COND]], float [[ARG0]], float [[ARG1]]
; CHECK-NEXT: ret float [[SELECT]]
ret float %fence
}
-; TODO: Remove all the fences beyond here when attributor bug is fixed.
-
define float @ret_select_nonan__noinf_nonan(i1 %cond, float nofpclass(nan) %arg0, float nofpclass(nan inf) %arg1) {
; CHECK-LABEL: define nofpclass(nan) float @ret_select_nonan__noinf_nonan
; CHECK-SAME: (i1 [[COND:%.*]], float nofpclass(nan) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[ARG0]], float [[ARG1]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%select = select i1 %cond, float %arg0, float %arg1
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
; Clamp nan to 0 pattern
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = fcmp uno float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = fcmp uno float %arg, 0.0
%select = select i1 %is.nan, float 0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_nan_to_zero_ord(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[NOT_NAN]], float [[ARG]], float 0.000000e+00
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%not.nan = fcmp ord float %arg, 0.0
%select = select i1 %not.nan, float %arg, float 0.0
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_onlynans(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[NOT_NAN]], float 0x7FF8000000000000, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(inf zero sub norm) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%not.nan = fcmp ord float %arg, 0.0
%select = select i1 %not.nan, float 0x7FF8000000000000, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_nonfinite_to_normal_olt(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_FINITE]], float [[ARG]], float 1.024000e+03
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan inf) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.finite = fcmp olt float %fabs, 0x7FF0000000000000
%select = select i1 %is.finite, float %arg, float 1024.0
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_eq_inf_to_pnormal(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float 1.024000e+03, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(inf) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
%select = select i1 %is.inf, float 1024.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_eq_pinf_to_pnormal(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[ARG]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float 1.024000e+03, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(pinf) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.inf = fcmp oeq float %arg, 0x7FF0000000000000
%select = select i1 %is.inf, float 1024.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_eq_ninf_to_negnormal(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[ARG]], 0xFFF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float -1.024000e+03, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(ninf) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.inf = fcmp oeq float %arg, 0xFFF0000000000000
%select = select i1 %is.inf, float -1024.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_eq_inf_to_nan(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float 0x7FF8000000000000, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(inf) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
%select = select i1 %is.inf, float 0x7FF8000000000000, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_nan_to_zero_uno_returned_different_arg(float %arg0, float %arg1) {
; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = fcmp uno float [[ARG0]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG1]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = fcmp uno float %arg0, 0.0
%select = select i1 %is.nan, float 0.0, float %arg1
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @isfinite_select_fabs_val_0(float %arg) {
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @isfinite_select_fabs_val_0
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_FINITE]], float [[FABS]], float 1.024000e+03
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.finite = fcmp olt float %fabs, 0x7FF0000000000000
%select = select i1 %is.finite, float %fabs, float 1024.0
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @isfinite_select_fabs_val_1(float %arg) {
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @isfinite_select_fabs_val_1
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[NOT_IS_FINITE:%.*]] = fcmp uge float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[NOT_IS_FINITE]], float 1.024000e+03, float [[FABS]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%not.is.finite = fcmp uge float %fabs, 0x3810000000000000
%select = select i1 %not.is.finite, float 1024.0, float %fabs
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_denormal_to_poszero(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float 0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nzero sub) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%select = select i1 %is.denorm.or.zero, float 0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_denormal_to_negzero(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float -0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(pzero sub) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%select = select i1 %is.denorm.or.zero, float -0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_denormal_to_zero_copysign(float %arg) {
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[ZERO:%.*]] = call float @llvm.copysign.f32(float noundef 0.000000e+00, float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float [[ZERO]], float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(sub) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%zero = call float @llvm.copysign.f32(float 0.0, float %arg)
%select = select i1 %is.denorm.or.zero, float %zero, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_only_denormal_or_zero(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float [[ARG]], float 0.000000e+00
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan inf norm) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%select = select i1 %is.denorm.or.zero, float %arg, float 0.0
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_inf_to_fabs(float %arg) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float [[FABS]], float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
%select = select i1 %is.inf, float %fabs, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @not_clamp_inf_to_fabs(float %arg) {
; CHECK-LABEL: define float @not_clamp_inf_to_fabs
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_INF]], float [[ARG]], float [[FABS]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
%select = select i1 %is.inf, float %arg, float %fabs
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_zero_to_inf(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_ZERO]], float 0x7FF0000000000000, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(zero) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.zero = fcmp oeq float %arg, 0.0
%select = select i1 %is.zero, float 0x7FF0000000000000, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_zero_to_only_inf(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_ZERO]], float [[ARG]], float 0x7FF0000000000000
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan ninf sub norm) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.zero = fcmp oeq float %arg, 0.0
%select = select i1 %is.zero, float %arg, float 0x7FF0000000000000
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_is_class_subnormal_or_inf_to_nan(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_SUBNORMAL_OR_INF:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 660) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_SUBNORMAL_OR_INF]], float 0x7FF8000000000000, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(inf sub) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.subnormal.or.inf = call i1 @llvm.is.fpclass.f32(float %arg, i32 660)
%select = select i1 %is.subnormal.or.inf, float 0x7FF8000000000000, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_is_class_subnormal_or_inf_to_nan_swap(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[NOT_IS_SUBNORMAL_OR_INF:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 363) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[NOT_IS_SUBNORMAL_OR_INF]], float [[ARG]], float 0x7FF8000000000000
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(inf sub) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%not.is.subnormal.or.inf = call i1 @llvm.is.fpclass.f32(float %arg, i32 363)
%select = select i1 %not.is.subnormal.or.inf, float %arg, float 0x7FF8000000000000
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_nan_to_zero_fpclass(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 3) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(nan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = call i1 @llvm.is.fpclass.f32(float %arg, i32 3)
%select = select i1 %is.nan, float 0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_snan_to_zero_fpclass(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 1) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(snan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = call i1 @llvm.is.fpclass.f32(float %arg, i32 1)
%select = select i1 %is.nan, float 0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_qnan_to_zero_fpclass(float %arg) {
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 2) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call nofpclass(qnan) float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = call i1 @llvm.is.fpclass.f32(float %arg, i32 2)
%select = select i1 %is.nan, float 0.0, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @ret_select_clamp_nan_to_zero_fpclass_other_val(float %arg0, float %arg1) {
; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[IS_NAN:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG0]], i32 noundef 3) #[[ATTR2]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_NAN]], float 0.000000e+00, float [[ARG1]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%is.nan = call i1 @llvm.is.fpclass.f32(float %arg0, i32 3)
%select = select i1 %is.nan, float 0.0, float %arg1
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @clamp_is_denorm_or_zero_to_fneg(float %arg) {
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[NEG_ARG:%.*]] = fneg float [[ARG]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float [[NEG_ARG]], float [[ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%neg.arg = fneg float %arg
%select = select i1 %is.denorm.or.zero, float %neg.arg, float %arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @select_is_denorm_or_zero_to_fneg_or_fabs(float %arg) {
; CHECK-LABEL: define float @select_is_denorm_or_zero_to_fneg_or_fabs
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[NEG_ARG:%.*]] = fneg float [[ARG]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float [[NEG_ARG]], float [[FABS]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%neg.arg = fneg float %arg
%select = select i1 %is.denorm.or.zero, float %neg.arg, float %fabs
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
define float @select_is_denorm_or_zero_to_fabs_or_fneg(float %arg) {
; CHECK-NEXT: [[IS_DENORM_OR_ZERO:%.*]] = fcmp olt float [[FABS]], 0x3810000000000000
; CHECK-NEXT: [[NEG_ARG:%.*]] = fneg float [[ARG]]
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_DENORM_OR_ZERO]], float [[FABS]], float [[NEG_ARG]]
-; CHECK-NEXT: [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]]) #[[ATTR2]]
-; CHECK-NEXT: ret float [[FENCE]]
+; CHECK-NEXT: ret float [[SELECT]]
;
%fabs = call float @llvm.fabs.f32(float %arg)
%is.denorm.or.zero = fcmp olt float %fabs, 0x3810000000000000
%neg.arg = fneg float %arg
%select = select i1 %is.denorm.or.zero, float %fabs, float %neg.arg
- %fence = call float @llvm.arithmetic.fence.f32(float %select)
- ret float %fence
+ ret float %select
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@iszero1
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
-; CGSCC-NEXT: ret i1 [[CMP]]
+; CGSCC-NEXT: ret i1 false
;
%cmp = icmp eq i32 %c, 0
ret i1 %cmp
; CGSCC-LABEL: define {{[^@]+}}@potential_test1
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: [[ARG:%.*]] = select i1 [[C]], i32 -1, i32 1
-; CGSCC-NEXT: [[RET:%.*]] = call i1 @iszero1(i32 noundef [[ARG]]) #[[ATTR2:[0-9]+]]
+; CGSCC-NEXT: [[RET:%.*]] = call noundef i1 @iszero1(i32 noundef [[ARG]]) #[[ATTR2:[0-9]+]]
; CGSCC-NEXT: ret i1 [[RET]]
;
%arg = select i1 %c, i32 -1, i32 1
; CHECK-NEXT: [[I_1]] = add i32 [[I_0]], 1
; CHECK-NEXT: br label [[COND]]
; CHECK: end:
-; CHECK-NEXT: [[RET:%.*]] = icmp eq i32 [[C_0]], 0
-; CHECK-NEXT: ret i1 [[RET]]
+; CHECK-NEXT: ret i1 false
;
entry:
br label %cond
}
; Test 10
-; FIXME: potential returned values of @may_return_undef is {1, -1}
-; and returned value of @potential_test10 can be simplified to 0(false)
+; potential returned values of @may_return_undef is {1, -1}
+; and returned value of @potential_test10 can be simplified to 0(false)
define internal i32 @may_return_undef(i32 %c) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@may_return_undef
-; CHECK-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
-; CHECK-NEXT: i32 1, label [[A:%.*]]
-; CHECK-NEXT: i32 -1, label [[B:%.*]]
-; CHECK-NEXT: ]
-; CHECK: a:
-; CHECK-NEXT: ret i32 1
-; CHECK: b:
-; CHECK-NEXT: ret i32 -1
-; CHECK: otherwise:
-; CHECK-NEXT: ret i32 undef
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@may_return_undef
+; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] {
+; CGSCC-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
+; CGSCC-NEXT: i32 1, label [[A:%.*]]
+; CGSCC-NEXT: i32 -1, label [[B:%.*]]
+; CGSCC-NEXT: ]
+; CGSCC: a:
+; CGSCC-NEXT: ret i32 1
+; CGSCC: b:
+; CGSCC-NEXT: ret i32 -1
+; CGSCC: otherwise:
+; CGSCC-NEXT: ret i32 undef
;
switch i32 %c, label %otherwise [i32 1, label %a
i32 -1, label %b]
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test10
; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
-; TUNIT-NEXT: [[RET:%.*]] = call i32 @may_return_undef(i32 noundef [[C]]) #[[ATTR1]]
-; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i32 [[RET]], 0
-; TUNIT-NEXT: ret i1 [[CMP]]
+; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@potential_test10
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test11
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
-; TUNIT-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR1]], !range [[RNG0]]
-; TUNIT-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR1]], !range [[RNG2:![0-9]+]]
-; TUNIT-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 noundef [[C]]) #[[ATTR1]], !range [[RNG0]]
+; TUNIT-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR1]]
+; TUNIT-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR1]]
+; TUNIT-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 noundef [[C]]) #[[ATTR1]]
; TUNIT-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
; TUNIT-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]]
; TUNIT-NEXT: ret i32 [[ACC2]]
; CHECK: t:
; CHECK-NEXT: ret i32 0
; CHECK: f:
-; CHECK-NEXT: [[POISON:%.*]] = sub nuw i32 0, 1
-; CHECK-NEXT: ret i32 [[POISON]]
+; CHECK-NEXT: ret i32 0
;
br i1 %c, label %t, label %f
t:
ret i32 %poison
}
-; FIXME: returned value can be simplified to 0
+; returned value can be simplified to 0
define i32 @potential_test12(i1 %c) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test12
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@potential_test12
; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT: [[ZERO:%.*]] = call i32 @optimize_poison_1(i1 noundef [[C]]) #[[ATTR2]]
+; CGSCC-NEXT: [[ZERO:%.*]] = call noundef i32 @optimize_poison_1(i1 noundef [[C]]) #[[ATTR2]]
; CGSCC-NEXT: ret i32 [[ZERO]]
;
%zero = call i32 @optimize_poison_1(i1 %c)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller1
; TUNIT-SAME: () #[[ATTR0]] {
-; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 0) #[[ATTR1]], !range [[RNG0]]
+; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 0) #[[ATTR1]]
; TUNIT-NEXT: ret i32 [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller1
; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 0) #[[ATTR2]]
+; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 0) #[[ATTR2]]
; CGSCC-NEXT: ret i32 [[RET]]
;
%ret = call i32 @potential_test13_callee(i32 0)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller2
; TUNIT-SAME: () #[[ATTR0]] {
-; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 1) #[[ATTR1]], !range [[RNG0]]
+; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 1) #[[ATTR1]]
; TUNIT-NEXT: ret i32 [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller2
; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 1) #[[ATTR2]]
+; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 1) #[[ATTR2]]
; CGSCC-NEXT: ret i32 [[RET]]
;
%ret = call i32 @potential_test13_callee(i32 1)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller3
; TUNIT-SAME: () #[[ATTR0]] {
-; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) #[[ATTR1]], !range [[RNG0]]
+; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) #[[ATTR1]]
; TUNIT-NEXT: ret i32 [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller3
; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) #[[ATTR2]]
+; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 undef) #[[ATTR2]]
; CGSCC-NEXT: ret i32 [[RET]]
;
%ret = call i32 @potential_test13_callee(i32 undef)
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@potential_test15
; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
-; CHECK-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
-; CHECK-NEXT: [[RET:%.*]] = icmp eq i32 [[X1]], 7
-; CHECK-NEXT: ret i1 [[RET]]
+; CHECK-NEXT: ret i1 false
;
%x0 = select i1 %c0, i32 0, i32 1
%x1 = select i1 %c1, i32 %x0, i32 undef
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@potential_test16
; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 0, i32 1
-; CHECK-NEXT: [[RET:%.*]] = icmp eq i32 [[X1]], 7
-; CHECK-NEXT: ret i1 [[RET]]
+; CHECK-NEXT: ret i1 false
;
%x0 = select i1 %c0, i32 0, i32 undef
%x1 = select i1 %c1, i32 %x0, i32 1
;.
; TUNIT: [[RNG0]] = !{i32 0, i32 2}
; TUNIT: [[RNG1]] = !{i32 0, i32 3}
-; TUNIT: [[RNG2]] = !{i32 -1, i32 1}
;.
; TUNIT-LABEL: define {{[^@]+}}@select
; TUNIT-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
-; TUNIT-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
-; TUNIT-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
-; TUNIT-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
-; TUNIT-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
-; TUNIT-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
-; TUNIT-NEXT: ret i1 [[CMP6]]
+; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@select
; CGSCC-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
; CGSCC-NEXT: entry:
-; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
-; CGSCC-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
-; CGSCC-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
-; CGSCC-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
-; CGSCC-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
-; CGSCC-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
-; CGSCC-NEXT: ret i1 [[CMP6]]
+; CGSCC-NEXT: ret i1 false
;
entry:
%cmp = icmp sgt i32 %a, 5
; TUNIT-LABEL: define {{[^@]+}}@select_zext
; TUNIT-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
-; TUNIT-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
-; TUNIT-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
-; TUNIT-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
-; TUNIT-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
-; TUNIT-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
-; TUNIT-NEXT: [[DOT13:%.*]] = zext i1 [[CMP6]] to i32
-; TUNIT-NEXT: ret i32 [[DOT13]]
+; TUNIT-NEXT: ret i32 0
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@select_zext
; CGSCC-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
; CGSCC-NEXT: entry:
-; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
-; CGSCC-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
-; CGSCC-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
-; CGSCC-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
-; CGSCC-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
-; CGSCC-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
-; CGSCC-NEXT: [[DOT13:%.*]] = zext i1 [[CMP6]] to i32
-; CGSCC-NEXT: ret i32 [[DOT13]]
+; CGSCC-NEXT: ret i32 0
;
entry:
%cmp = icmp sgt i32 %a, 5
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@non_zero
; CGSCC-SAME: (i8 [[V:%.*]]) #[[ATTR2]] {
-; CGSCC-NEXT: [[R:%.*]] = icmp ne i8 [[V]], 0
-; CGSCC-NEXT: ret i1 [[R]]
+; CGSCC-NEXT: ret i1 true
;
%r = icmp ne i8 %v, 0
ret i1 %r
; CGSCC-NEXT: [[C:%.*]] = icmp slt i8 0, [[L]]
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: t:
-; CGSCC-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) #[[ATTR6]]
+; CGSCC-NEXT: [[R:%.*]] = call noundef i1 @non_zero(i8 [[L]]) #[[ATTR6]]
; CGSCC-NEXT: ret i1 [[R]]
; CGSCC: f:
; CGSCC-NEXT: ret i1 false
; TUNIT-NEXT: store i32 10, ptr [[P]], align 4
; TUNIT-NEXT: ret void
;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write)
; CGSCC-LABEL: define {{[^@]+}}@test8_2
; CGSCC-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR4:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { memory(read) }
; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
-; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: write) }
; CGSCC: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(write) }
; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(read) }
; CGSCC: attributes #[[ATTR7]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(read) }
; We can use the alignment information of the weak function non_exact_3 argument
; because it was given to us and not derived.
; We can use the return information of the weak function non_exact_4.
-; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
+; %c2 and %c3 should be replaced but not %c0 or %c1!
define i32 @exact(ptr align 8 %a, ptr align 8 %b) {
; CHECK-LABEL: define {{[^@]+}}@exact
; CHECK-SAME: (ptr align 8 [[A:%.*]], ptr align 8 [[B:%.*]]) {
; CHECK-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 noundef 2)
; CHECK-NEXT: [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr align 32 [[A]])
; CHECK-NEXT: [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr align 32 [[B]])
-; CHECK-NEXT: [[C3L:%.*]] = load i32, ptr [[C3]], align 32
+; CHECK-NEXT: [[C3L:%.*]] = load i32, ptr [[A]], align 32
; CHECK-NEXT: [[C4L:%.*]] = load i32, ptr [[C4]], align 16
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
-; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[C2]]
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], 2
; CHECK-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
; CHECK-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
; CHECK-NEXT: ret i32 [[ADD4]]
; TUNIT-LABEL: define {{[^@]+}}@test
; TUNIT-SAME: (i1 [[C:%.*]]) {
; TUNIT-NEXT: [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
-; TUNIT-NEXT: [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]])
+; TUNIT-NEXT: [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]]), !range [[RNG0:![0-9]+]]
; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[R1]], [[R2]]
; TUNIT-NEXT: ret i32 [[ADD]]
;
; TUNIT: t:
; TUNIT-NEXT: br label [[F]]
; TUNIT: f:
-; TUNIT-NEXT: [[P:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[T]] ]
-; TUNIT-NEXT: [[RC1:%.*]] = call i1 @ret(i1 noundef [[P]]) #[[ATTR9]]
-; TUNIT-NEXT: ret i1 [[RC1]]
+; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@test_liveness
}
define internal i1 @ret(i1 %c) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@ret
-; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; CHECK: t:
-; CHECK-NEXT: br label [[F]]
-; CHECK: f:
-; CHECK-NEXT: [[P:%.*]] = phi i1 [ [[C]], [[ENTRY:%.*]] ], [ false, [[T]] ]
-; CHECK-NEXT: ret i1 [[P]]
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ret
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT: entry:
+; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC: t:
+; CGSCC-NEXT: br label [[F]]
+; CGSCC: f:
+; CGSCC-NEXT: [[P:%.*]] = phi i1 [ [[C]], [[ENTRY:%.*]] ], [ false, [[T]] ]
+; CGSCC-NEXT: ret i1 false
;
entry:
br i1 %c, label %t, label %f
; CGSCC: attributes #[[ATTR15]] = { nofree willreturn memory(readwrite) }
; CGSCC: attributes #[[ATTR16]] = { nounwind }
;.
+; TUNIT: [[RNG0]] = !{i32 0, i32 -2147483648}
+;.