llvm.org GIT mirror llvm / 80f3bae
[Attributor] Deduce memory behavior of functions and arguments Deduce the memory behavior, aka "read-none", "read-only", or "write-only", for functions and arguments. Reviewers: sstefan1, uenoku Subscribers: hiraditya, bollu, jfb, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67384 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373965 91177308-0d34-0410-b5e6-96231b3b80d8 Johannes Doerfert 1 year, 1 month ago
17 changed file(s) with 710 addition(s) and 163 deletion(s). Raw diff Collapse all Expand all
407407
408408 /// Return true if any kind in \p AKs existing in the IR at a position that
409409 /// will affect this one. See also getAttrs(...).
410 bool hasAttr(ArrayRef AKs) const;
410 /// \param IgnoreSubsumingPositions Flag to determine if subsuming positions,
411 /// e.g., the function position if this is an
412 /// argument position, should be ignored.
413 bool hasAttr(ArrayRef AKs,
414 bool IgnoreSubsumingPositions = false) const;
411415
412416 /// Return the attributes of any kind in \p AKs existing in the IR at a
413417 /// position that will affect this one. While each position can only have a
431435 if (AttrList.hasAttribute(getAttrIdx(), AK))
432436 return AttrList.getAttribute(getAttrIdx(), AK);
433437 return Attribute();
438 }
439
440 /// Remove the attribute of kind \p AKs existing in the IR at this position.
441 void removeAttrs(ArrayRef AKs) {
442 if (getPositionKind() == IRP_INVALID || getPositionKind() == IRP_FLOAT)
443 return;
444
445 AttributeList AttrList;
446 CallSite CS = CallSite(&getAnchorValue());
447 if (CS)
448 AttrList = CS.getAttributes();
449 else
450 AttrList = getAssociatedFunction()->getAttributes();
451
452 LLVMContext &Ctx = getAnchorValue().getContext();
453 for (Attribute::AttrKind AK : AKs)
454 AttrList = AttrList.removeAttribute(Ctx, getAttrIdx(), AK);
455
456 if (CS)
457 CS.setAttributes(AttrList);
458 else
459 getAssociatedFunction()->setAttributes(AttrList);
434460 }
435461
436462 bool isAnyCallSitePosition() const {
18231849 static const char ID;
18241850 };
18251851
1852 /// An abstract interface for all memory related attributes.
1853 struct AAMemoryBehavior
1854 : public IRAttribute
1855 StateWrapper> {
1856 AAMemoryBehavior(const IRPosition &IRP) : IRAttribute(IRP) {}
1857
1858 /// State encoding bits. A set bit in the state means the property holds.
1859 /// BEST_STATE is the best possible state, 0 the worst possible state.
1860 enum {
1861 NO_READS = 1 << 0,
1862 NO_WRITES = 1 << 1,
1863 NO_ACCESSES = NO_READS | NO_WRITES,
1864
1865 BEST_STATE = NO_ACCESSES,
1866 };
1867
1868 /// Return true if we know that the underlying value is not read or accessed
1869 /// in its respective scope.
1870 bool isKnownReadNone() const { return isKnown(NO_ACCESSES); }
1871
1872 /// Return true if we assume that the underlying value is not read or accessed
1873 /// in its respective scope.
1874 bool isAssumedReadNone() const { return isAssumed(NO_ACCESSES); }
1875
1876 /// Return true if we know that the underlying value is not accessed
1877 /// (=written) in its respective scope.
1878 bool isKnownReadOnly() const { return isKnown(NO_WRITES); }
1879
1880 /// Return true if we assume that the underlying value is not accessed
1881 /// (=written) in its respective scope.
1882 bool isAssumedReadOnly() const { return isAssumed(NO_WRITES); }
1883
1884 /// Return true if we know that the underlying value is not read in its
1885 /// respective scope.
1886 bool isKnownWriteOnly() const { return isKnown(NO_READS); }
1887
1888 /// Return true if we assume that the underlying value is not read in its
1889 /// respective scope.
1890 bool isAssumedWriteOnly() const { return isAssumed(NO_READS); }
1891
1892 /// Create an abstract attribute view for the position \p IRP.
1893 static AAMemoryBehavior &createForPosition(const IRPosition &IRP,
1894 Attributor &A);
1895
1896 /// Unique ID (due to the unique address)
1897 static const char ID;
1898 };
1899
18261900 } // end namespace llvm
18271901
18281902 #endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
417417 }
418418 }
419419
420 bool IRPosition::hasAttr(ArrayRef AKs) const {
421 for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this))
420 bool IRPosition::hasAttr(ArrayRef AKs,
421 bool IgnoreSubsumingPositions) const {
422 for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) {
422423 for (Attribute::AttrKind AK : AKs)
423424 if (EquivIRP.getAttr(AK).getKindAsEnum() == AK)
424425 return true;
426 // The first position returned by the SubsumingPositionIterator is
427 // always the position itself. If we ignore subsuming positions we
428 // are done after the first iteration.
429 if (IgnoreSubsumingPositions)
430 break;
431 }
425432 return false;
426433 }
427434
34363443 };
34373444 } // namespace
34383445
3446 /// -------------------- Memory Behavior Attributes ----------------------------
3447 /// Includes read-none, read-only, and write-only.
3448 /// ----------------------------------------------------------------------------
3449 struct AAMemoryBehaviorImpl : public AAMemoryBehavior {
3450 AAMemoryBehaviorImpl(const IRPosition &IRP) : AAMemoryBehavior(IRP) {}
3451
3452 /// See AbstractAttribute::initialize(...).
3453 void initialize(Attributor &A) override {
3454 intersectAssumedBits(BEST_STATE);
3455 getKnownStateFromValue(getIRPosition(), getState());
3456 IRAttribute::initialize(A);
3457 }
3458
3459 /// Return the memory behavior information encoded in the IR for \p IRP.
3460 static void getKnownStateFromValue(const IRPosition &IRP,
3461 IntegerState &State) {
3462 SmallVector Attrs;
3463 IRP.getAttrs(AttrKinds, Attrs);
3464 for (const Attribute &Attr : Attrs) {
3465 switch (Attr.getKindAsEnum()) {
3466 case Attribute::ReadNone:
3467 State.addKnownBits(NO_ACCESSES);
3468 break;
3469 case Attribute::ReadOnly:
3470 State.addKnownBits(NO_WRITES);
3471 break;
3472 case Attribute::WriteOnly:
3473 State.addKnownBits(NO_READS);
3474 break;
3475 default:
3476 llvm_unreachable("Unexpcted attribute!");
3477 }
3478 }
3479
3480 if (auto *I = dyn_cast(&IRP.getAnchorValue())) {
3481 if (!I->mayReadFromMemory())
3482 State.addKnownBits(NO_READS);
3483 if (!I->mayWriteToMemory())
3484 State.addKnownBits(NO_WRITES);
3485 }
3486 }
3487
3488 /// See AbstractAttribute::getDeducedAttributes(...).
3489 void getDeducedAttributes(LLVMContext &Ctx,
3490 SmallVectorImpl &Attrs) const override {
3491 assert(Attrs.size() == 0);
3492 if (isAssumedReadNone())
3493 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
3494 else if (isAssumedReadOnly())
3495 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
3496 else if (isAssumedWriteOnly())
3497 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
3498 assert(Attrs.size() <= 1);
3499 }
3500
3501 /// See AbstractAttribute::manifest(...).
3502 ChangeStatus manifest(Attributor &A) override {
3503 IRPosition &IRP = getIRPosition();
3504
3505 // Check if we would improve the existing attributes first.
3506 SmallVector DeducedAttrs;
3507 getDeducedAttributes(IRP.getAnchorValue().getContext(), DeducedAttrs);
3508 if (llvm::all_of(DeducedAttrs, [&](const Attribute &Attr) {
3509 return IRP.hasAttr(Attr.getKindAsEnum(),
3510 /* IgnoreSubsumingPositions */ true);
3511 }))
3512 return ChangeStatus::UNCHANGED;
3513
3514 // Clear existing attributes.
3515 IRP.removeAttrs(AttrKinds);
3516
3517 // Use the generic manifest method.
3518 return IRAttribute::manifest(A);
3519 }
3520
3521 /// See AbstractState::getAsStr().
3522 const std::string getAsStr() const override {
3523 if (isAssumedReadNone())
3524 return "readnone";
3525 if (isAssumedReadOnly())
3526 return "readonly";
3527 if (isAssumedWriteOnly())
3528 return "writeonly";
3529 return "may-read/write";
3530 }
3531
3532 /// The set of IR attributes AAMemoryBehavior deals with.
3533 static const Attribute::AttrKind AttrKinds[3];
3534 };
3535
3536 const Attribute::AttrKind AAMemoryBehaviorImpl::AttrKinds[] = {
3537 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
3538
3539 /// Memory behavior attribute for a floating value.
3540 struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
3541 AAMemoryBehaviorFloating(const IRPosition &IRP) : AAMemoryBehaviorImpl(IRP) {}
3542
3543 /// See AbstractAttribute::initialize(...).
3544 void initialize(Attributor &A) override {
3545 AAMemoryBehaviorImpl::initialize(A);
3546 // Initialize the use vector with all direct uses of the associated value.
3547 for (const Use &U : getAssociatedValue().uses())
3548 Uses.insert(&U);
3549 }
3550
3551 /// See AbstractAttribute::updateImpl(...).
3552 ChangeStatus updateImpl(Attributor &A) override;
3553
3554 /// See AbstractAttribute::trackStatistics()
3555 void trackStatistics() const override {
3556 if (isAssumedReadNone())
3557 STATS_DECLTRACK_FLOATING_ATTR(readnone)
3558 else if (isAssumedReadOnly())
3559 STATS_DECLTRACK_FLOATING_ATTR(readonly)
3560 else if (isAssumedWriteOnly())
3561 STATS_DECLTRACK_FLOATING_ATTR(writeonly)
3562 }
3563
3564 private:
3565 /// Return true if users of \p UserI might access the underlying
3566 /// variable/location described by \p U and should therefore be analyzed.
3567 bool followUsersOfUseIn(Attributor &A, const Use *U,
3568 const Instruction *UserI);
3569
3570 /// Update the state according to the effect of use \p U in \p UserI.
3571 void analyzeUseIn(Attributor &A, const Use *U, const Instruction *UserI);
3572
3573 protected:
3574 /// Container for (transitive) uses of the associated argument.
3575 SetVector Uses;
3576 };
3577
3578 /// Memory behavior attribute for function argument.
3579 struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
3580 AAMemoryBehaviorArgument(const IRPosition &IRP)
3581 : AAMemoryBehaviorFloating(IRP) {}
3582
3583 /// See AbstractAttribute::initialize(...).
3584 void initialize(Attributor &A) override {
3585 AAMemoryBehaviorFloating::initialize(A);
3586
3587 // TODO: From readattrs.ll: "inalloca parameters are always
3588 // considered written"
3589 if (hasAttr({Attribute::InAlloca}))
3590 removeAssumedBits(NO_WRITES);
3591
3592 // Initialize the use vector with all direct uses of the associated value.
3593 Argument *Arg = getAssociatedArgument();
3594 if (!Arg || !Arg->getParent()->hasExactDefinition())
3595 indicatePessimisticFixpoint();
3596 }
3597
3598 /// See AbstractAttribute::trackStatistics()
3599 void trackStatistics() const override {
3600 if (isAssumedReadNone())
3601 STATS_DECLTRACK_ARG_ATTR(readnone)
3602 else if (isAssumedReadOnly())
3603 STATS_DECLTRACK_ARG_ATTR(readonly)
3604 else if (isAssumedWriteOnly())
3605 STATS_DECLTRACK_ARG_ATTR(writeonly)
3606 }
3607 };
3608
3609 struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
3610 AAMemoryBehaviorCallSiteArgument(const IRPosition &IRP)
3611 : AAMemoryBehaviorArgument(IRP) {}
3612
3613 /// See AbstractAttribute::updateImpl(...).
3614 ChangeStatus updateImpl(Attributor &A) override {
3615 // TODO: Once we have call site specific value information we can provide
3616 // call site specific liveness liveness information and then it makes
3617 // sense to specialize attributes for call sites arguments instead of
3618 // redirecting requests to the callee argument.
3619 Argument *Arg = getAssociatedArgument();
3620 const IRPosition &ArgPos = IRPosition::argument(*Arg);
3621 auto &ArgAA = A.getAAFor(*this, ArgPos);
3622 return clampStateAndIndicateChange(
3623 getState(),
3624 static_cast(ArgAA.getState()));
3625 }
3626
3627 /// See AbstractAttribute::trackStatistics()
3628 void trackStatistics() const override {
3629 if (isAssumedReadNone())
3630 STATS_DECLTRACK_CSARG_ATTR(readnone)
3631 else if (isAssumedReadOnly())
3632 STATS_DECLTRACK_CSARG_ATTR(readonly)
3633 else if (isAssumedWriteOnly())
3634 STATS_DECLTRACK_CSARG_ATTR(writeonly)
3635 }
3636 };
3637
3638 /// Memory behavior attribute for a call site return position.
3639 struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
3640 AAMemoryBehaviorCallSiteReturned(const IRPosition &IRP)
3641 : AAMemoryBehaviorFloating(IRP) {}
3642
3643 /// See AbstractAttribute::manifest(...).
3644 ChangeStatus manifest(Attributor &A) override {
3645 // We do not annotate returned values.
3646 return ChangeStatus::UNCHANGED;
3647 }
3648
3649 /// See AbstractAttribute::trackStatistics()
3650 void trackStatistics() const override {}
3651 };
3652
3653 /// An AA to represent the memory behavior function attributes.
3654 struct AAMemoryBehaviorFunction final : public AAMemoryBehaviorImpl {
3655 AAMemoryBehaviorFunction(const IRPosition &IRP) : AAMemoryBehaviorImpl(IRP) {}
3656
3657 /// See AbstractAttribute::updateImpl(Attributor &A).
3658 virtual ChangeStatus updateImpl(Attributor &A) override;
3659
3660 /// See AbstractAttribute::manifest(...).
3661 ChangeStatus manifest(Attributor &A) override {
3662 Function &F = cast(getAnchorValue());
3663 if (isAssumedReadNone()) {
3664 F.removeFnAttr(Attribute::ArgMemOnly);
3665 F.removeFnAttr(Attribute::InaccessibleMemOnly);
3666 F.removeFnAttr(Attribute::InaccessibleMemOrArgMemOnly);
3667 }
3668 return AAMemoryBehaviorImpl::manifest(A);
3669 }
3670
3671 /// See AbstractAttribute::trackStatistics()
3672 void trackStatistics() const override {
3673 if (isAssumedReadNone())
3674 STATS_DECLTRACK_FN_ATTR(readnone)
3675 else if (isAssumedReadOnly())
3676 STATS_DECLTRACK_FN_ATTR(readonly)
3677 else if (isAssumedWriteOnly())
3678 STATS_DECLTRACK_FN_ATTR(writeonly)
3679 }
3680 };
3681
3682 /// AAMemoryBehavior attribute for call sites.
3683 struct AAMemoryBehaviorCallSite final : AAMemoryBehaviorImpl {
3684 AAMemoryBehaviorCallSite(const IRPosition &IRP) : AAMemoryBehaviorImpl(IRP) {}
3685
3686 /// See AbstractAttribute::initialize(...).
3687 void initialize(Attributor &A) override {
3688 AAMemoryBehaviorImpl::initialize(A);
3689 Function *F = getAssociatedFunction();
3690 if (!F || !F->hasExactDefinition())
3691 indicatePessimisticFixpoint();
3692 }
3693
3694 /// See AbstractAttribute::updateImpl(...).
3695 ChangeStatus updateImpl(Attributor &A) override {
3696 // TODO: Once we have call site specific value information we can provide
3697 // call site specific liveness liveness information and then it makes
3698 // sense to specialize attributes for call sites arguments instead of
3699 // redirecting requests to the callee argument.
3700 Function *F = getAssociatedFunction();
3701 const IRPosition &FnPos = IRPosition::function(*F);
3702 auto &FnAA = A.getAAFor(*this, FnPos);
3703 return clampStateAndIndicateChange(
3704 getState(), static_cast(FnAA.getState()));
3705 }
3706
3707 /// See AbstractAttribute::trackStatistics()
3708 void trackStatistics() const override {
3709 if (isAssumedReadNone())
3710 STATS_DECLTRACK_CS_ATTR(readnone)
3711 else if (isAssumedReadOnly())
3712 STATS_DECLTRACK_CS_ATTR(readonly)
3713 else if (isAssumedWriteOnly())
3714 STATS_DECLTRACK_CS_ATTR(writeonly)
3715 }
3716 };
3717
3718 ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &A) {
3719
3720 // The current assumed state used to determine a change.
3721 auto AssumedState = getAssumed();
3722
3723 auto CheckRWInst = [&](Instruction &I) {
3724 // If the instruction has an own memory behavior state, use it to restrict
3725 // the local state. No further analysis is required as the other memory
3726 // state is as optimistic as it gets.
3727 if (ImmutableCallSite ICS = ImmutableCallSite(&I)) {
3728 const auto &MemBehaviorAA = A.getAAFor(
3729 *this, IRPosition::callsite_function(ICS));
3730 intersectAssumedBits(MemBehaviorAA.getAssumed());
3731 return !isAtFixpoint();
3732 }
3733
3734 // Remove access kind modifiers if necessary.
3735 if (I.mayReadFromMemory())
3736 removeAssumedBits(NO_READS);
3737 if (I.mayWriteToMemory())
3738 removeAssumedBits(NO_WRITES);
3739 return !isAtFixpoint();
3740 };
3741
3742 if (!A.checkForAllReadWriteInstructions(CheckRWInst, *this))
3743 return indicatePessimisticFixpoint();
3744
3745 return (AssumedState != getAssumed()) ? ChangeStatus::CHANGED
3746 : ChangeStatus::UNCHANGED;
3747 }
3748
3749 ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &A) {
3750
3751 const IRPosition &IRP = getIRPosition();
3752 const IRPosition &FnPos = IRPosition::function_scope(IRP);
3753 AAMemoryBehavior::StateType &S = getState();
3754
3755 // First, check the function scope. We take the known information and we avoid
3756 // work if the assumed information implies the current assumed information for
3757 // this attribute.
3758 const auto &FnMemAA = A.getAAFor(*this, FnPos);
3759 S.addKnownBits(FnMemAA.getKnown());
3760 if ((S.getAssumed() & FnMemAA.getAssumed()) == S.getAssumed())
3761 return ChangeStatus::UNCHANGED;
3762
3763 // Make sure the value is not captured (except through "return"), if
3764 // it is, any information derived would be irrelevant anyway as we cannot
3765 // check the potential aliases introduced by the capture.
3766 const auto &ArgNoCaptureAA = A.getAAFor(*this, IRP);
3767 if (!ArgNoCaptureAA.isAssumedNoCaptureMaybeReturned())
3768 return indicatePessimisticFixpoint();
3769
3770 // The current assumed state used to determine a change.
3771 auto AssumedState = S.getAssumed();
3772
3773 // Liveness information to exclude dead users.
3774 // TODO: Take the FnPos once we have call site specific liveness information.
3775 const auto &LivenessAA = A.getAAFor(
3776 *this, IRPosition::function(*IRP.getAssociatedFunction()));
3777
3778 // Visit and expand uses until all are analyzed or a fixpoint is reached.
3779 for (unsigned i = 0; i < Uses.size() && !isAtFixpoint(); i++) {
3780 const Use *U = Uses[i];
3781 Instruction *UserI = cast(U->getUser());
3782 LLVM_DEBUG(dbgs() << "[AAMemoryBehavior] Use: " << **U << " in " << *UserI
3783 << " [Dead: " << (LivenessAA.isAssumedDead(UserI))
3784 << "]\n");
3785 if (LivenessAA.isAssumedDead(UserI))
3786 continue;
3787
3788 // Check if the users of UserI should also be visited.
3789 if (followUsersOfUseIn(A, U, UserI))
3790 for (const Use &UserIUse : UserI->uses())
3791 Uses.insert(&UserIUse);
3792
3793 // If UserI might touch memory we analyze the use in detail.
3794 if (UserI->mayReadOrWriteMemory())
3795 analyzeUseIn(A, U, UserI);
3796 }
3797
3798 return (AssumedState != getAssumed()) ? ChangeStatus::CHANGED
3799 : ChangeStatus::UNCHANGED;
3800 }
3801
3802 bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &A, const Use *U,
3803 const Instruction *UserI) {
3804 // The loaded value is unrelated to the pointer argument, no need to
3805 // follow the users of the load.
3806 if (isa(UserI))
3807 return false;
3808
3809 // By default we follow all uses assuming UserI might leak information on U,
3810 // we have special handling for call sites operands though.
3811 ImmutableCallSite ICS(UserI);
3812 if (!ICS || !ICS.isArgOperand(U))
3813 return true;
3814
3815 // If the use is a call argument known not to be captured, the users of
3816 // the call do not need to be visited because they have to be unrelated to
3817 // the input. Note that this check is not trivial even though we disallow
3818 // general capturing of the underlying argument. The reason is that the
3819 // call might the argument "through return", which we allow and for which we
3820 // need to check call users.
3821 unsigned ArgNo = ICS.getArgumentNo(U);
3822 const auto &ArgNoCaptureAA =
3823 A.getAAFor(*this, IRPosition::callsite_argument(ICS, ArgNo));
3824 return !ArgNoCaptureAA.isAssumedNoCapture();
3825 }
3826
3827 void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &A, const Use *U,
3828 const Instruction *UserI) {
3829 assert(UserI->mayReadOrWriteMemory());
3830
3831 switch (UserI->getOpcode()) {
3832 default:
3833 // TODO: Handle all atomics and other side-effect operations we know of.
3834 break;
3835 case Instruction::Load:
3836 // Loads cause the NO_READS property to disappear.
3837 removeAssumedBits(NO_READS);
3838 return;
3839
3840 case Instruction::Store:
3841 // Stores cause the NO_WRITES property to disappear if the use is the
3842 // pointer operand. Note that we do assume that capturing was taken care of
3843 // somewhere else.
3844 if (cast(UserI)->getPointerOperand() == U->get())
3845 removeAssumedBits(NO_WRITES);
3846 return;
3847
3848 case Instruction::Call:
3849 case Instruction::CallBr:
3850 case Instruction::Invoke: {
3851 // For call sites we look at the argument memory behavior attribute (this
3852 // could be recursive!) in order to restrict our own state.
3853 ImmutableCallSite ICS(UserI);
3854
3855 // Give up on operand bundles.
3856 if (ICS.isBundleOperand(U)) {
3857 indicatePessimisticFixpoint();
3858 return;
3859 }
3860
3861 // Calling a function does read the function pointer, maybe write it if the
3862 // function is self-modifying.
3863 if (ICS.isCallee(U)) {
3864 removeAssumedBits(NO_READS);
3865 break;
3866 }
3867
3868 // Adjust the possible access behavior based on the information on the
3869 // argument.
3870 unsigned ArgNo = ICS.getArgumentNo(U);
3871 const IRPosition &ArgPos = IRPosition::callsite_argument(ICS, ArgNo);
3872 const auto &MemBehaviorAA = A.getAAFor(*this, ArgPos);
3873 // "assumed" has at most the same bits as the MemBehaviorAA assumed
3874 // and at least "known".
3875 intersectAssumedBits(MemBehaviorAA.getAssumed());
3876 return;
3877 }
3878 };
3879
3880 // Generally, look at the "may-properties" and adjust the assumed state if we
3881 // did not trigger special handling before.
3882 if (UserI->mayReadFromMemory())
3883 removeAssumedBits(NO_READS);
3884 if (UserI->mayWriteToMemory())
3885 removeAssumedBits(NO_WRITES);
3886 }
3887
34393888 /// ----------------------------------------------------------------------------
34403889 /// Attributor
34413890 /// ----------------------------------------------------------------------------
36064055
36074056 auto &OpcodeInstMap =
36084057 InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction);
3609 if (!checkForAllInstructionsImpl(OpcodeInstMap, Pred, &LivenessAA, AnyDead, Opcodes))
4058 if (!checkForAllInstructionsImpl(OpcodeInstMap, Pred, &LivenessAA, AnyDead,
4059 Opcodes))
36104060 return false;
36114061
36124062 // If we actually used liveness information so we have to record a dependence.
39644414 // Every function might be "no-recurse".
39654415 getOrCreateAAFor(FPos);
39664416
4417 // Every function might be "readnone/readonly/writeonly/...".
4418 getOrCreateAAFor(FPos);
4419
39674420 // Every function might be applicable for Heap-To-Stack conversion.
39684421 if (EnableHeapToStack)
39694422 getOrCreateAAFor(FPos);
40184471
40194472 // Every argument with pointer type might be marked nocapture.
40204473 getOrCreateAAFor(ArgPos);
4474
4475 // Every argument with pointer type might be marked
4476 // "readnone/readonly/writeonly/..."
4477 getOrCreateAAFor(ArgPos);
40214478 }
40224479 }
40234480
42314688 const char AANoCapture::ID = 0;
42324689 const char AAValueSimplify::ID = 0;
42334690 const char AAHeapToStack::ID = 0;
4691 const char AAMemoryBehavior::ID = 0;
42344692
42354693 // Macro magic to create the static generator function for attributes that
42364694 // follow the naming scheme.
43094767 return *AA; \
43104768 }
43114769
4770 #define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
4771 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
4772 CLASS *AA = nullptr; \
4773 switch (IRP.getPositionKind()) { \
4774 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
4775 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
4776 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
4777 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
4778 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
4779 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
4780 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
4781 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
4782 } \
4783 AA->initialize(A); \
4784 return *AA; \
4785 }
4786
43124787 CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind)
43134788 CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)
43144789 CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
43284803
43294804 CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack)
43304805
4806 CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior)
4807
43314808 #undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
43324809 #undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
43334810 #undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
66
77
88 ; TEST 1
9 ; ATTRIBUTOR: define align 8 i32* @test1(i32* returned align 8 "no-capture-maybe-returned" %0)
9 ; ATTRIBUTOR: define align 8 i32* @test1(i32* readnone returned align 8 "no-capture-maybe-returned" %0)
1010 define i32* @test1(i32* align 8 %0) #0 {
1111 ret i32* %0
1212 }
1313
1414 ; TEST 2
15 ; ATTRIBUTOR: define i32* @test2(i32* returned "no-capture-maybe-returned" %0)
15 ; ATTRIBUTOR: define i32* @test2(i32* readnone returned "no-capture-maybe-returned" %0)
1616 define i32* @test2(i32* %0) #0 {
1717 ret i32* %0
1818 }
1919
2020 ; TEST 3
21 ; ATTRIBUTOR: define align 4 i32* @test3(i32* align 8 "no-capture-maybe-returned" %0, i32* align 4 "no-capture-maybe-returned" %1, i1 %2)
21 ; ATTRIBUTOR: define align 4 i32* @test3(i32* readnone align 8 "no-capture-maybe-returned" %0, i32* readnone align 4 "no-capture-maybe-returned" %1, i1 %2)
2222 define i32* @test3(i32* align 8 %0, i32* align 4 %1, i1 %2) #0 {
2323 %ret = select i1 %2, i32* %0, i32* %1
2424 ret i32* %ret
2525 }
2626
2727 ; TEST 4
28 ; ATTRIBUTOR: define align 32 i32* @test4(i32* align 32 "no-capture-maybe-returned" %0, i32* align 32 "no-capture-maybe-returned" %1, i1 %2)
28 ; ATTRIBUTOR: define align 32 i32* @test4(i32* readnone align 32 "no-capture-maybe-returned" %0, i32* readnone align 32 "no-capture-maybe-returned" %1, i1 %2)
2929 define i32* @test4(i32* align 32 %0, i32* align 32 %1, i1 %2) #0 {
3030 %ret = select i1 %2, i32* %0, i32* %1
3131 ret i32* %ret
138138
139139 ; TEST 7
140140 ; Better than IR information
141 ; ATTRIBUTOR: define align 32 i32* @test7(i32* returned align 32 "no-capture-maybe-returned" %p)
141 ; ATTRIBUTOR: define align 32 i32* @test7(i32* readnone returned align 32 "no-capture-maybe-returned" %p)
142142 define align 4 i32* @test7(i32* align 32 %p) #0 {
143143 tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
144144 ret i32* %p
161161 }
162162
163163 define internal void @test8(i32* %a, i32* %b, i32* %c) {
164 ; ATTRIBUTOR: define internal void @test8(i32* nocapture align 4 %a, i32* nocapture align 4 %b, i32* nocapture %c)
164 ; ATTRIBUTOR: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c)
165165 ret void
166166 }
167167
115115 ;
116116 ; CHECK: define dereferenceable_or_null(8) i64* @scc_B(double* readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" %a)
117117 ;
118 ; FIXME: readnone missing for %s
119 ; CHECK: define dereferenceable_or_null(2) i8* @scc_C(i16* returned dereferenceable_or_null(2) "no-capture-maybe-returned" %a)
118 ; CHECK: define dereferenceable_or_null(2) i8* @scc_C(i16* readnone returned dereferenceable_or_null(2) "no-capture-maybe-returned" %a)
120119 ;
121120 ; float *scc_A(int *a) {
122121 ; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
244243 ; }
245244 ;
246245 ; There should *not* be a no-capture attribute on %a
247 ; CHECK: define i64* @not_captured_but_returned_0(i64* returned "no-capture-maybe-returned" %a)
246 ; CHECK: define i64* @not_captured_but_returned_0(i64* returned writeonly "no-capture-maybe-returned" %a)
248247 define i64* @not_captured_but_returned_0(i64* %a) #0 {
249248 entry:
250249 store i64 0, i64* %a, align 8
259258 ; }
260259 ;
261260 ; There should *not* be a no-capture attribute on %a
262 ; CHECK: define nonnull i64* @not_captured_but_returned_1(i64* "no-capture-maybe-returned" %a)
261 ; CHECK: define nonnull i64* @not_captured_but_returned_1(i64* writeonly "no-capture-maybe-returned" %a)
263262 define i64* @not_captured_but_returned_1(i64* %a) #0 {
264263 entry:
265264 %add.ptr = getelementptr inbounds i64, i64* %a, i64 1
274273 ; not_captured_but_returned_1(a);
275274 ; }
276275 ;
277 ; FIXME: no-capture missing for %a
278 ; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture %a)
276 ; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture writeonly %a)
279277 define void @test_not_captured_but_returned_calls(i64* %a) #0 {
280278 entry:
281279 %call = call i64* @not_captured_but_returned_0(i64* %a)
290288 ; }
291289 ;
292290 ; There should *not* be a no-capture attribute on %a
293 ; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* returned "no-capture-maybe-returned" %a)
291 ; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* returned writeonly "no-capture-maybe-returned" %a)
294292 define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 {
295293 entry:
296294 %call = call i64* @not_captured_but_returned_0(i64* %a)
304302 ; }
305303 ;
306304 ; There should *not* be a no-capture attribute on %a
307 ; CHECK: define void @negative_test_not_captured_but_returned_call_0b(i64* %a)
305 ; CHECK: define void @negative_test_not_captured_but_returned_call_0b(i64* writeonly %a)
308306 define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 {
309307 entry:
310308 %call = call i64* @not_captured_but_returned_0(i64* %a)
320318 ; }
321319 ;
322320 ; There should *not* be a no-capture attribute on %a
323 ; CHECK: define nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* "no-capture-maybe-returned" %a)
321 ; CHECK: define nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* writeonly "no-capture-maybe-returned" %a)
324322 define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 {
325323 entry:
326324 %call = call i64* @not_captured_but_returned_1(i64* %a)
334332 ; }
335333 ;
336334 ; There should *not* be a no-capture attribute on %a
337 ; CHECK: define void @negative_test_not_captured_but_returned_call_1b(i64* %a)
335 ; CHECK: define void @negative_test_not_captured_but_returned_call_1b(i64* writeonly %a)
338336 define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 {
339337 entry:
340338 %call = call i64* @not_captured_but_returned_1(i64* %a)
390388
391389 ; TEST not captured by readonly external function
392390 ;
393 ; CHECK: define void @not_captured_by_readonly_call(i32* nocapture %b)
391 ; CHECK: define void @not_captured_by_readonly_call(i32* nocapture readonly %b)
394392 declare i32* @readonly_unknown(i32*, i32*) readonly
395393
396394 define void @not_captured_by_readonly_call(i32* %b) #0 {
158158
159159 ; TEST SCC test returning a pointer value argument
160160 ;
161 ; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
162 ; BOTH-NEXT: define double* @ptr_sink_r0(double* readnone returned "no-capture-maybe-returned" %r)
163 ; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
164 ; BOTH-NEXT: define double* @ptr_scc_r1(double* %a, double* readnone returned %r, double* nocapture readnone %b)
165 ; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
166 ; BOTH-NEXT: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone returned %r)
167 ;
168161 ; FNATTR: define double* @ptr_sink_r0(double* readnone returned %r)
169162 ; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b)
170163 ; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r)
171164 ;
172 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
173 ; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* returned "no-capture-maybe-returned" %r)
174 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
175 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* %a, double* returned %r, double* nocapture %b)
176 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
177 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* %a, double* %b, double* returned %r)
165 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
166 ; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* readnone returned "no-capture-maybe-returned" %r)
167 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
168 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* readnone %a, double* readnone returned %r, double* nocapture readnone %b)
169 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
170 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone returned %r)
178171 ;
179172 ; double* ptr_scc_r1(double* a, double* b, double* r);
180173 ; double* ptr_scc_r2(double* a, double* b, double* r);
292285 ;
293286 ; FNATTR: define i32* @rt2_helper(i32* %a)
294287 ; FNATTR: define i32* @rt2(i32* readnone %a, i32* readnone %b)
295 ; BOTH: define i32* @rt2_helper(i32* returned %a)
288 ; BOTH: define i32* @rt2_helper(i32* readnone returned %a)
296289 ; BOTH: define i32* @rt2(i32* readnone %a, i32* readnone "no-capture-maybe-returned" %b)
297290 define i32* @rt2_helper(i32* %a) #0 {
298291 entry:
318311 ;
319312 ; FNATTR: define i32* @rt3_helper(i32* %a, i32* %b)
320313 ; FNATTR: define i32* @rt3(i32* readnone %a, i32* readnone %b)
321 ; BOTH: define i32* @rt3_helper(i32* %a, i32* returned "no-capture-maybe-returned" %b)
314 ; BOTH: define i32* @rt3_helper(i32* readnone %a, i32* readnone returned "no-capture-maybe-returned" %b)
322315 ; BOTH: define i32* @rt3(i32* readnone %a, i32* readnone returned "no-capture-maybe-returned" %b)
323316 define i32* @rt3_helper(i32* %a, i32* %b) #0 {
324317 entry:
354347 ; BOTH: Function Attrs: noinline nounwind uwtable
355348 ; BOTH-NEXT: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
356349 ; FNATTR: define i32* @calls_unknown_fn(i32* readnone returned %r)
357 ; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* returned "no-capture-maybe-returned" %r)
350 ; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
358351 declare void @unknown_fn(i32* (i32*)*) #0
359352
360353 define i32* @calls_unknown_fn(i32* %r) #0 {
442435 ; BOTH-NEXT: define double @select_and_phi(double returned %b)
443436 ;
444437 ; FNATTR: define double @select_and_phi(double %b)
445 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
438 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
446439 ; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
447440 define double @select_and_phi(double %b) #0 {
448441 entry:
474467 ;
475468 ; FNATTR: define double @recursion_select_and_phi(i32 %a, double %b)
476469 ;
477 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
470 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
478471 ; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
479472 define double @recursion_select_and_phi(i32 %a, double %b) #0 {
480473 entry:
505498 ;
506499 ; FNATTR: define double* @bitcast(i32* readnone %b)
507500 ;
508 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
509 ; ATTRIBUTOR-NEXT: define double* @bitcast(i32* returned "no-capture-maybe-returned" %b)
501 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
502 ; ATTRIBUTOR-NEXT: define double* @bitcast(i32* readnone returned "no-capture-maybe-returned" %b)
510503 define double* @bitcast(i32* %b) #0 {
511504 entry:
512505 %bc0 = bitcast i32* %b to double*
528521 ;
529522 ; FNATTR: define double* @bitcasts_select_and_phi(i32* readnone %b)
530523 ;
531 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
532 ; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* returned %b)
524 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
525 ; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* readnone returned %b)
533526 define double* @bitcasts_select_and_phi(i32* %b) #0 {
534527 entry:
535528 %bc0 = bitcast i32* %b to double*
566559 ;
567560 ; FNATTR: define double* @ret_arg_arg_undef(i32* readnone %b)
568561 ;
569 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
570 ; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* returned %b)
562 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
563 ; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* readnone returned %b)
571564 define double* @ret_arg_arg_undef(i32* %b) #0 {
572565 entry:
573566 %bc0 = bitcast i32* %b to double*
604597 ;
605598 ; FNATTR: define double* @ret_undef_arg_arg(i32* readnone %b)
606599 ;
607 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
608 ; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* returned %b)
600 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
601 ; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* readnone returned %b)
609602 define double* @ret_undef_arg_arg(i32* %b) #0 {
610603 entry:
611604 %bc0 = bitcast i32* %b to double*
641634 ; BOTH-NEXT: define double* @ret_undef_arg_undef(i32* readnone returned %b)
642635 ;
643636 ; FNATTR: define double* @ret_undef_arg_undef(i32* readnone %b)
644 ; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* returned %b)
637 ; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* readnone returned %b)
645638 define double* @ret_undef_arg_undef(i32* %b) #0 {
646639 entry:
647640 %bc0 = bitcast i32* %b to double*
845838 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline noreturn nosync nounwind readonly uwtable }
846839 ; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
847840 ; BOTH-DAG: attributes #{{[0-9]*}} = { noreturn }
848 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync willreturn }
849 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync }
850 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noreturn nosync }
841 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline norecurse nosync nounwind readnone uwtable }
842 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync readnone willreturn }
843 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync readnone }
844 ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noreturn nosync readonly }
851845 ; BOTH-NOT: attributes #
66 ; take mininimum of return values
77 ;
88 define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
9 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test1(i32* nonnull dereferenceable(4) "no-capture-maybe-returned" %0, double* nonnull dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
9 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test1(i32* nonnull readnone dereferenceable(4) "no-capture-maybe-returned" %0, double* nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
1010 %4 = bitcast double* %1 to i32*
1111 %5 = select i1 %2, i32* %0, i32* %4
1212 ret i32* %5
1414
1515 ; TEST 2
1616 define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
17 ; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test2(i32* dereferenceable_or_null(4) "no-capture-maybe-returned" %0, double* nonnull dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
17 ; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test2(i32* readnone dereferenceable_or_null(4) "no-capture-maybe-returned" %0, double* nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
1818 %4 = bitcast double* %1 to i32*
1919 %5 = select i1 %2, i32* %0, i32* %4
2020 ret i32* %5
2323 ; TEST 3
2424 ; GEP inbounds
2525 define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
26 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) "no-capture-maybe-returned" %0)
26 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0)
2727 %ret = getelementptr inbounds i32, i32* %0, i64 1
2828 ret i32* %ret
2929 }
3030
3131 define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr {
3232 ; FIXME: Argument should be mark dereferenceable because of GEP `inbounds`.
33 ; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) "no-capture-maybe-returned" %0)
33 ; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* readnone dereferenceable_or_null(32) "no-capture-maybe-returned" %0)
3434 %ret = getelementptr inbounds i32, i32* %0, i64 4
3535 ret i32* %ret
3636 }
3737
3838 define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr {
39 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) "no-capture-maybe-returned" %0, i32* nonnull dereferenceable(16) "no-capture-maybe-returned" %1, i1 %2) local_unnamed_addr
39 ; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0, i32* nonnull readnone dereferenceable(16) "no-capture-maybe-returned" %1, i1 %2) local_unnamed_addr
4040 %ret1 = getelementptr inbounds i32, i32* %0, i64 1
4141 %ret2 = getelementptr inbounds i32, i32* %1, i64 2
4242 %ret = select i1 %2, i32* %ret1, i32* %ret2
4747 ; Better than known in IR.
4848
4949 define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_addr {
50 ; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test4(i32* nonnull returned dereferenceable(8) "no-capture-maybe-returned" %0)
50 ; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test4(i32* nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" %0)
5151 ret i32* %0
5252 }
5353
77 ret i32 %add
88 }
99
10 ; FIXME: Should be something like this.
11 ; define internal i32 @noalias_args(i32* nocapture readonly %A, i32* noalias nocapture readonly %B)
12 ; CHECK: define internal i32 @noalias_args(i32* nocapture %A, i32* noalias nocapture %B)
10 ; CHECK: define internal i32 @noalias_args(i32* nocapture readonly %A, i32* noalias nocapture readonly %B)
1311
1412 define internal i32 @noalias_args(i32* %A, i32* %B) #0 {
1513 entry:
2422
2523 ; FIXME: Should be something like this.
2624 ; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B)
27 ; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture %A, i32* nocapture %B)
25 ; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture readonly %A, i32* nocapture readonly %B)
2826 ;
2927 define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
3028 entry:
3838 ret i32 %2
3939 }
4040
41 ; CHECK: Function Attrs: nofree norecurse nosync nounwind uwtable willreturn
42 ; CHECK-NEXT: define internal i32 @internal_load(i32* nocapture nonnull %0)
41 ; CHECK: Function Attrs: nofree norecurse nosync nounwind readonly uwtable willreturn
42 ; CHECK-NEXT: define internal i32 @internal_load(i32* nocapture nonnull readonly %0)
4343 define internal i32 @internal_load(i32*) norecurse nounwind uwtable {
4444 %2 = load i32, i32* %0, align 4
4545 ret i32 %2
4747 ; TEST 1: Only first block is live.
4848
4949 ; CHECK: Function Attrs: nofree noreturn nosync nounwind
50 ; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nonnull %ptr1, i32* nocapture %ptr2)
50 ; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nonnull readonly %ptr1, i32* nocapture readnone %ptr2)
5151 define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 {
5252 entry:
5353 call i32 @internal_load(i32* %ptr1)
54 ; CHECK: call i32 @internal_load(i32* nocapture nonnull %ptr1)
54 ; CHECK: call i32 @internal_load(i32* nocapture nonnull readonly %ptr1)
5555 call void @no_return_call()
5656 ; CHECK: call void @no_return_call()
5757 ; CHECK-NEXT: unreachable
8383 ; dead block and check if it is deduced.
8484
8585 ; CHECK: Function Attrs: nosync
86 ; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* nocapture %ptr1)
86 ; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* nocapture readnone %ptr1)
8787 define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 {
8888 entry:
8989 %cmp = icmp eq i32 %a, 0
238238 ; TEST 6: Undefined behvior, taken from LangRef.
239239 ; FIXME: Should be able to detect undefined behavior.
240240
241 ; CHECK: define void @ub(i32* nocapture %0)
241 ; CHECK: define void @ub(i32* nocapture writeonly %0)
242242 define void @ub(i32* %0) {
243243 %poison = sub nuw i32 0, 1 ; Results in a poison value.
244244 %still_poison = and i32 %poison, 0 ; 0, but also poison.
659659 ; CHECK: define internal void @non_dead_d13()
660660 ; CHECK: define internal void @non_dead_d14()
661661 ; Verify we actually deduce information for these functions.
662 ; CHECK: Function Attrs: nofree nosync nounwind willreturn
662 ; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
663663 ; CHECK-NEXT: define internal void @non_dead_d15()
664664 ; CHECK-NOT: define internal void @dead_e
665665
152152 ; TEST 9
153153 ; Simple Argument Test
154154 define internal void @test9(i8* %a, i8* %b) {
155 ; CHECK: define internal void @test9(i8* noalias nocapture %a, i8* nocapture %b)
155 ; CHECK: define internal void @test9(i8* noalias nocapture readnone %a, i8* nocapture readnone %b)
156156 ret void
157157 }
158158 define void @test9_helper(i8* %a, i8* %b) {
55 @g = global i32* null ; [#uses=1]
66
77 ; FNATTR: define i32* @c1(i32* readnone returned %q)
8 ; ATTRIBUTOR: define i32* @c1(i32* returned "no-capture-maybe-returned" %q)
8 ; ATTRIBUTOR: define i32* @c1(i32* readnone returned "no-capture-maybe-returned" %q)
99 define i32* @c1(i32* %q) {
1010 ret i32* %q
1111 }
2323 ret void
2424 }
2525
26 ; EITHER: define i1 @c4(i32* %q, i32 %bitno)
26 ; FNATTR: define i1 @c4(i32* %q, i32 %bitno)
27 ; ATTRIBUTOR: define i1 @c4(i32* readnone %q, i32 %bitno)
2728 define i1 @c4(i32* %q, i32 %bitno) {
2829 %tmp = ptrtoint i32* %q to i32
2930 %tmp2 = lshr i32 %tmp, %bitno
125126 }
126127
127128 declare void @external(i8*) readonly nounwind
128 ; FNATTR: define void @nc4(i8* nocapture readonly %p)
129 ; ATTRIBUTOR: define void @nc4(i8* nocapture %p)
129 ; EITHER: define void @nc4(i8* nocapture readonly %p)
130130 define void @nc4(i8* %p) {
131131 call void @external(i8* %p)
132132 ret void
140140 }
141141
142142 ; FNATTR: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1, i1 %c)
143 ; ATTRIBUTOR: define void @test1_1(i8* nocapture %x1_1, i8* nocapture %y1_1, i1 %c)
143 ; ATTRIBUTOR: define void @test1_1(i8* nocapture readnone %x1_1, i8* nocapture readnone %y1_1, i1 %c)
144144 ; It would be acceptable to add readnone to %y1_1 and %y1_2.
145145 define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
146146 call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c)
149149 }
150150
151151 ; FNATTR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2, i1 %c)
152 ; ATTRIBUTOR: define i8* @test1_2(i8* nocapture %x1_2, i8* returned "no-capture-maybe-returned" %y1_2, i1 %c)
152 ; ATTRIBUTOR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* readnone returned "no-capture-maybe-returned" %y1_2, i1 %c)
153153 define i8* @test1_2(i8* %x1_2, i8* %y1_2, i1 %c) {
154154 br i1 %c, label %t, label %f
155155 t:
160160 ret i8* %y1_2
161161 }
162162
163 ; FNATTR: define void @test2(i8* nocapture readnone %x2)
164 ; ATTRIBUTOR: define void @test2(i8* nocapture %x2)
163 ; EITHER: define void @test2(i8* nocapture readnone %x2)
165164 define void @test2(i8* %x2) {
166165 call void @test2(i8* %x2)
167166 store i32* null, i32** @g
168167 ret void
169168 }
170169
171 ; FNATTR: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
172 ; ATTRIBUTOR: define void @test3(i8* nocapture %x3, i8* nocapture %y3, i8* nocapture %z3)
170 ; EITHER: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
173171 define void @test3(i8* %x3, i8* %y3, i8* %z3) {
174172 call void @test3(i8* %z3, i8* %y3, i8* %x3)
175173 store i32* null, i32** @g
177175 }
178176
179177 ; FNATTR: define void @test4_1(i8* %x4_1, i1 %c)
180 ; ATTRIBUTOR: define void @test4_1(i8* nocapture %x4_1, i1 %c)
178 ; ATTRIBUTOR: define void @test4_1(i8* nocapture readnone %x4_1, i1 %c)
181179 define void @test4_1(i8* %x4_1, i1 %c) {
182180 call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1, i1 %c)
183181 store i32* null, i32** @g
185183 }
186184
187185 ; FNATTR: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2, i1 %c)
188 ; ATTRIBUTOR: define i8* @test4_2(i8* nocapture %x4_2, i8* returned "no-capture-maybe-returned" %y4_2, i8* nocapture %z4_2, i1 %c)
186 ; ATTRIBUTOR: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned "no-capture-maybe-returned" %y4_2, i8* nocapture readnone %z4_2, i1 %c)
189187 define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2, i1 %c) {
190188 br i1 %c, label %t, label %f
191189 t:
256254 ret void
257255 }
258256
259 ; EITHER: @nocaptureStrip(i8* nocapture %p)
257 ; FNATTR: @nocaptureStrip(i8* nocapture %p)
258 ; ATTRIBUTOR: @nocaptureStrip(i8* nocapture writeonly %p)
260259 define void @nocaptureStrip(i8* %p) {
261260 entry:
262261 %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
272271 ret void
273272 }
274273
275 ; FNATTR: define i1 @captureICmp(i32* readnone %x)
276 ; ATTRIBUTOR: define i1 @captureICmp(i32* %x)
274 ; EITHER: define i1 @captureICmp(i32* readnone %x)
277275 define i1 @captureICmp(i32* %x) {
278276 %1 = icmp eq i32* %x, null
279277 ret i1 %1
280278 }
281279
282 ; FNATTR: define i1 @captureICmpRev(i32* readnone %x)
283 ; ATTRIBUTOR: define i1 @captureICmpRev(i32* %x)
280 ; EITHER: define i1 @captureICmpRev(i32* readnone %x)
284281 define i1 @captureICmpRev(i32* %x) {
285282 %1 = icmp eq i32* null, %x
286283 ret i1 %1
287284 }
288285
289 ; FNATTR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
290 ; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture %x)
286 ; EITHER: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
291287 define i1 @nocaptureInboundsGEPICmp(i32* %x) {
292288 %1 = getelementptr inbounds i32, i32* %x, i32 5
293289 %2 = bitcast i32* %1 to i8*
295291 ret i1 %3
296292 }
297293
298 ; FNATTR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
299 ; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture %x)
294 ; EITHER: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
300295 define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
301296 %1 = getelementptr inbounds i32, i32* %x, i32 5
302297 %2 = bitcast i32* %1 to i8*
304299 ret i1 %3
305300 }
306301
307 ; FNATTR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
308 ; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture dereferenceable_or_null(4) %x)
302 ; EITHER: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
309303 define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) {
310304 %1 = bitcast i32* %x to i8*
311305 %2 = icmp eq i8* %1, null
312306 ret i1 %2
313307 }
314308
315 ; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
316 ; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x)
309 ; EITHER: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
317310 define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
318311 %1 = bitcast i32* %x to i8*
319312 %2 = icmp eq i8* %1, null
1414 ; TEST 1 (positive case)
1515 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
1616 ; FNATTR-NEXT: define void @only_return()
17 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
17 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
1818 ; ATTRIBUTOR-NEXT: define void @only_return()
1919 define void @only_return() #0 {
2020 ret void
9191
9292 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
9393 ; FNATTR-NEXT: define void @mutual_recursion1()
94 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
94 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
9595 ; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
9696 define void @mutual_recursion1() #0 {
9797 call void @mutual_recursion2()
100100
101101 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
102102 ; FNATTR-NEXT: define void @mutual_recursion2()
103 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
103 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
104104 ; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
105105 define void @mutual_recursion2() #0 {
106106 call void @mutual_recursion1()
157157
158158 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
159159 ; FNATTR-NEXT: define void @call_nofree_function()
160 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
160 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
161161 ; ATTRIBUTOR-NEXT: define void @call_nofree_function()
162162 define void @call_nofree_function() #0 {
163163 tail call void @nofree_function()
210210 ; FNATTRS: Function Attrs: noinline nounwind uwtable
211211 ; FNATTRS-NEXT: define void @call_floor(float %a)
212212 ; FIXME: missing nofree
213 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
213 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
214214 ; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
215215
216216 define void @call_floor(float %a) #0 {
223223
224224 ; FNATTRS: Function Attrs: noinline nounwind uwtable
225225 ; FNATTRS-NEXT: define void @f1()
226 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
226 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
227227 ; ATTRIBUTOR-NEXT: define void @f1()
228228 define void @f1() #0 {
229229 tail call void @nofree_function()
232232
233233 ; FNATTRS: Function Attrs: noinline nounwind uwtable
234234 ; FNATTRS-NEXT: define void @f2()
235 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
235 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
236236 ; ATTRIBUTOR-NEXT: define void @f2()
237237 define void @f2() #0 {
238238 tail call void @f1()
158158 ret void
159159 }
160160 define internal void @test13(i8* %a, i8* %b, i8* %c) {
161 ; ATTRIBUTOR: define internal void @test13(i8* nocapture nonnull %a, i8* nocapture %b, i8* nocapture %c)
161 ; ATTRIBUTOR: define internal void @test13(i8* nocapture nonnull readnone %a, i8* nocapture readnone %b, i8* nocapture readnone %c)
162162 ret void
163163 }
164164
177177
178178
179179 define internal i32* @f1(i32* %arg) {
180 ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull %arg)
181 ; ATTRIBUTOR: define internal nonnull i32* @f1(i32* %arg)
180 ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg)
181 ; ATTRIBUTOR: define internal nonnull i32* @f1(i32* readonly %arg)
182182
183183 bb:
184184 %tmp = icmp eq i32* %arg, null
211211 ; ATTRIBUTOR: define internal nonnull i32* @f2(i32* %arg)
212212 bb:
213213
214 ; FIXME: missing nonnull. It should be @f1(i32* nonnull %arg)
215 ; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* %arg)
214 ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
215 ; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* readonly %arg)
216216 %tmp = tail call i32* @f1(i32* %arg)
217217 ret i32* %tmp
218218 }
219219
220220 define dso_local noalias i32* @f3(i32* %arg) {
221 ; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull %arg)
222 ; ATTRIBUTOR: define dso_local noalias i32* @f3(i32* %arg)
221 ; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg)
222 ; ATTRIBUTOR: define dso_local noalias i32* @f3(i32* readonly %arg)
223223 bb:
224 ; FIXME: missing nonnull. It should be @f1(i32* nonnull %arg)
225 ; ATTRIBUTOR: %tmp = call i32* @f1(i32* %arg)
224 ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
225 ; ATTRIBUTOR: %tmp = call i32* @f1(i32* readonly %arg)
226226 %tmp = call i32* @f1(i32* %arg)
227227 ret i32* null
228228 }
401401 define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){
402402 ; FNATTR-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b)
403403 ; FIXME : missing "nonnull", it should be @parent8(i8* nonnull %a, i8* %bogus1, i8* nonnull %b)
404 ; ATTRIBUTOR-LABEL: @parent8(i8* %a, i8* nocapture %bogus1, i8* %b)
404 ; ATTRIBUTOR-LABEL: @parent8(i8* %a, i8* nocapture readnone %bogus1, i8* %b)
405405 ; BOTH-NEXT: entry:
406406 ; FNATTR-NEXT: invoke void @use2nonnull(i8* %a, i8* %b)
407407 ; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b)
457457 ret i32* %c
458458 }
459459
460 ; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull %a)
460 ; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a)
461461 define internal void @called_by_weak(i32* %a) {
462462 ret void
463463 }
33
44 ; CHECK: Function Attrs
55 ; CHECK-SAME: norecurse nounwind readnone
6 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind willreturn
6 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
77 ; BOTH-NEXT: define i32 @leaf()
88 define i32 @leaf() {
99 ret i32 1
1010 }
1111
1212 ; BOTH: Function Attrs
13 ; CHECK-SAME: readnone
13 ; BOTH-SAME: readnone
1414 ; BOTH-NOT: norecurse
1515 ; BOTH-NEXT: define i32 @self_rec()
1616 define i32 @self_rec() {
1919 }
2020
2121 ; BOTH: Function Attrs
22 ; CHECK-SAME: readnone
22 ; BOTH-SAME: readnone
2323 ; BOTH-NOT: norecurse
2424 ; BOTH-NEXT: define i32 @indirect_rec()
2525 define i32 @indirect_rec() {
2727 ret i32 %a
2828 }
2929 ; BOTH: Function Attrs
30 ; CHECK-SAME: readnone
30 ; BOTH-SAME: readnone
3131 ; BOTH-NOT: norecurse
3232 ; BOTH-NEXT: define i32 @indirect_rec2()
3333 define i32 @indirect_rec2() {
3636 }
3737
3838 ; BOTH: Function Attrs
39 ; CHECK-SAME: readnone
39 ; BOTH-SAME: readnone
4040 ; BOTH-NOT: norecurse
4141 ; BOTH-NEXT: define i32 @extern()
4242 define i32 @extern() {
5252 ; CHECK-SAME: nounwind
5353 ; BOTH-NOT: norecurse
5454 ; CHECK-NEXT: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len)
55 ; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture %dest, i8* nocapture %src, i32 %len)
55 ; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture writeonly %dest, i8* nocapture readonly %src, i32 %len)
5656 define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
5757 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
5858 ret void
6565 ; BOTH: Function Attrs
6666 ; CHECK-SAME: norecurse readnone
6767 ; FIXME: missing "norecurse"
68 ; ATTRIBUTOR-SAME: nosync
68 ; ATTRIBUTOR-SAME: nosync readnone
6969 ; CHECK-NEXT: define internal i32 @called_by_norecurse()
7070 define internal i32 @called_by_norecurse() {
7171 %a = call i32 @k()
137137
138138 declare void @unknown()
139139 ; Call an unknown function in a dead block.
140 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind willreturn
140 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
141141 ; ATTRIBUTOR: define i32 @call_unknown_in_dead_block()
142142 define i32 @call_unknown_in_dead_block() local_unnamed_addr {
143143 ret i32 0
2727 ; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
2828 ; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
2929 ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
30 ; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* "no-capture-maybe-returned" %s)
30 ; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* readnone "no-capture-maybe-returned" %s)
3131 define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
3232 entry:
3333 %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
6060 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
6161 ; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0)
6262 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
63 ; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture %0)
63 ; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture writeonly %0)
6464 define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
6565 store atomic i32 10, i32* %0 monotonic, align 4
6666 ret void
9393 ; FNATTR-NEXT: define void @load_release(i32* nocapture %0)
9494 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
9595 ; ATTRIBUTOR-NOT: nosync
96 ; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture %0)
96 ; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture writeonly %0)
9797 define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
9898 store atomic volatile i32 10, i32* %0 release, align 4
9999 ret void
105105 ; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture %0)
106106 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
107107 ; ATTRIBUTOR-NOT: nosync
108 ; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture %0)
108 ; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture writeonly %0)
109109 define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable {
110110 store atomic volatile i32 10, i32* %0 release, align 4
111111 ret void
184184
185185 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
186186 ; FNATTR-NEXT: define i32 @scc1(i32* %0)
187 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
188 ; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture %0)
187 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
188 ; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture readnone %0)
189189 define i32 @scc1(i32* %0) noinline nounwind uwtable {
190190 tail call void @scc2(i32* %0);
191191 %val = tail call i32 @volatile_load(i32* %0);
194194
195195 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
196196 ; FNATTR-NEXT: define void @scc2(i32* %0)
197 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
198 ; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture %0)
197 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
198 ; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture readnone %0)
199199 define void @scc2(i32* %0) noinline nounwind uwtable {
200200 tail call i32 @scc1(i32* %0);
201201 ret void;
223223 ; FNATTR: Function Attrs: nofree norecurse nounwind
224224 ; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
225225 ; ATTRIBUTOR-NOT: nosync
226 ; ATTRIBUTOR: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
226 ; ATTRIBUTOR: define void @foo1(i32* nocapture writeonly %0, %"struct.std::atomic"* nocapture writeonly %1)
227227 define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
228228 store i32 100, i32* %0, align 4
229229 fence release
235235 ; FNATTR: Function Attrs: nofree norecurse nounwind
236236 ; FNATTR-NEXT: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
237237 ; ATTRIBUTOR-NOT: nosync
238 ; ATTRIBUTOR: define void @bar(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
238 ; ATTRIBUTOR: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
239239 define void @bar(i32* %0, %"struct.std::atomic"* %1) {
240240 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
241241 br label %4
255255 ; FNATTR: Function Attrs: nofree norecurse nounwind
256256 ; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
257257 ; ATTRIBUTOR: Function Attrs: nofree nosync
258 ; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
258 ; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture writeonly %0, %"struct.std::atomic"* nocapture writeonly %1)
259259 define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
260260 store i32 100, i32* %0, align 4
261261 fence syncscope("singlethread") release
267267 ; FNATTR: Function Attrs: nofree norecurse nounwind
268268 ; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
269269 ; ATTRIBUTOR: Function Attrs: nofree nosync
270 ; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
270 ; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
271271 define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
272272 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
273273 br label %4
292292 ;
293293 ; ATTRIBUTOR: Function Attrs: nounwind
294294 ; ATTRIBUTOR-NOT: nosync
295 ; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture %ptr1, i8* nocapture %ptr2)
295 ; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture writeonly %ptr1, i8* nocapture readonly %ptr2)
296296 define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
297297 call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1)
298298 ret i32 4
303303 ; It is odd to add nocapture but a result of the llvm.memset nocapture.
304304 ;
305305 ; ATTRIBUTOR: Function Attrs: nosync
306 ; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture %ptr1, i8 %val)
306 ; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture writeonly %ptr1, i8 %val)
307307 define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
308308 call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0)
309309 ret i32 4
101101 }
102102
103103 ; CHECK: Function Attrs: nofree norecurse nosync nounwind
104 ; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned "no-capture-maybe-returned" %w0)
104 ; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned writeonly "no-capture-maybe-returned" %w0)
105105 define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
106106 entry:
107107 %tobool = icmp ne i32* %n0, null
None ; RUN: opt < %s -functionattrs -S | FileCheck %s
1 ; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s
0 ; RUN: opt < %s -functionattrs -S | FileCheck %s --check-prefixes=CHECK,FNATTR
1 ; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s --check-prefixes=CHECK,FNATTR
2 ; RUN: opt < %s -attributor -attributor-disable=false -S | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
3 ; RUN: opt < %s -aa-pipeline=basic-aa -passes='attributor' -attributor-disable=false -S | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
4
25 @x = global i32 0
36
47 declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...)
58
69 ; NOTE: readonly for %y1_2 would be OK here but not for the similar situation in test13.
710 ;
8 ; CHECK: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2)
11 ; FNATTR: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2)
12 ; ATTRIBUTOR: define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2)
913 define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
1014 call void (i8*, i8*, ...) @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2)
1115 store i32 0, i32* @x
1216 ret void
1317 }
1418
15 ; CHECK: define i8* @test2(i8* readnone returned %p)
19 ; FNATTR: define i8* @test2(i8* readnone returned %p)
20 ; ATTRIBUTOR: define i8* @test2(i8* readnone returned %p)
1621 define i8* @test2(i8* %p) {
1722 store i32 0, i32* @x
1823 ret i8* %p
3237 ret void
3338 }
3439
35 ; CHECK: define void @test5(i8** nocapture %p, i8* %q)
40 ; FNATTR: define void @test5(i8** nocapture %p, i8* %q)
41 ; ATTRIBUTOR: define void @test5(i8** nocapture writeonly %p, i8* %q)
3642 ; Missed optz'n: we could make %q readnone, but don't break test6!
3743 define void @test5(i8** %p, i8* %q) {
3844 store i8* %q, i8** %p
4046 }
4147
4248 declare void @test6_1()
43 ; CHECK: define void @test6_2(i8** nocapture %p, i8* %q)
49 ; FNATTR: define void @test6_2(i8** nocapture %p, i8* %q)
50 ; ATTRIBUTOR: define void @test6_2(i8** nocapture writeonly %p, i8* %q)
4451 ; This is not a missed optz'n.
4552 define void @test6_2(i8** %p, i8* %q) {
4653 store i8* %q, i8** %p
4855 ret void
4956 }
5057
51 ; CHECK: define void @test7_1(i32* inalloca nocapture %a)
58 ; FNATTR: define void @test7_1(i32* inalloca nocapture %a)
59 ; ATTRIBUTOR: define void @test7_1(i32* inalloca nocapture writeonly %a)
5260 ; inalloca parameters are always considered written
5361 define void @test7_1(i32* inalloca %a) {
5462 ret void
5563 }
5664
57 ; CHECK: define i32* @test8_1(i32* readnone returned %p)
65 ; FNATTR: define i32* @test8_1(i32* readnone returned %p)
66 ; ATTRIBUTOR: define i32* @test8_1(i32* readnone returned %p)
5867 define i32* @test8_1(i32* %p) {
5968 entry:
6069 ret i32* %p
6170 }
6271
63 ; CHECK: define void @test8_2(i32* %p)
72 ; FNATTR: define void @test8_2(i32* %p)
73 ; ATTRIBUTOR: define void @test8_2(i32* nocapture writeonly %p)
6474 define void @test8_2(i32* %p) {
6575 entry:
6676 %call = call i32* @test8_1(i32* %p)
114124 ret i32 %load
115125 }
116126
117 declare void @escape_readonly_ptr(i8** %addr, i8* readnone %ptr)
118 declare void @escape_readnone_ptr(i8** %addr, i8* readonly %ptr)
127 declare void @escape_readnone_ptr(i8** %addr, i8* readnone %ptr)
128 declare void @escape_readonly_ptr(i8** %addr, i8* readonly %ptr)
119129
120130 ; The argument pointer %escaped_then_written cannot be marked readnone/only even
121131 ; though the only direct use, in @escape_readnone_ptr/@escape_readonly_ptr,
122132 ; is marked as readnone/only. However, the functions can write the pointer into
123133 ; %addr, causing the store to write to %escaped_then_written.
124134 ;
125 ; FIXME: This test currently exposes a bug!
135 ; FIXME: This test currently exposes a bug in functionattrs!
126136 ;
127 ; BUG: define void @unsound_readnone(i8* %ignored, i8* readnone %escaped_then_written)
128 ; BUG: define void @unsound_readonly(i8* %ignored, i8* readonly %escaped_then_written)
137 ; FNATTR: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* readnone %escaped_then_written)
138 ; FNATTR: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* readonly %escaped_then_written)
139 ;
140 ; ATTRIBUTOR: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* %escaped_then_written)
141 ; ATTRIBUTOR: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* %escaped_then_written)
129142 define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) {
130143 %addr = alloca i8*
131144 call void @escape_readnone_ptr(i8** %addr, i8* %escaped_then_written)
1010 ; TEST 1 (positive case)
1111 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
1212 ; FNATTR-NEXT: define void @only_return()
13 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable willreturn
13 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
1414 ; ATTRIBUTOR-NEXT: define void @only_return()
1515 define void @only_return() #0 {
1616 ret void
2727 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
2828 ; FNATTR-NEXT: define i32 @fib(i32 %0)
2929 ; FIXME: missing willreturn
30 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
30 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
3131 ; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr
3232 define i32 @fib(i32 %0) local_unnamed_addr #0 {
3333 %2 = icmp slt i32 %0, 2
5858 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
5959 ; FNATTR-NOT: willreturn
6060 ; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
61 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
61 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
6262 ; ATTRIBUTOR-NOT: willreturn
6363 ; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
6464 define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
9494 ; FIXME: missing willreturn
9595 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
9696 ; FNATTR-NEXT: define i32 @fact_loop(i32 %0)
97 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
97 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
9898 ; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr
9999 define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
100100 %2 = icmp slt i32 %0, 1
125125 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
126126 ; FNATTR-NOT: willreturn
127127 ; FNATTR-NEXT: define void @mutual_recursion1(i1 %c)
128 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
128 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
129129 ; ATTRIBUTOR-NOT: willreturn
130130 ; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
131131 define void @mutual_recursion1(i1 %c) #0 {
141141 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
142142 ; FNATTR-NOT: willreturn
143143 ; FNATTR-NEXT: define void @mutual_recursion2(i1 %c)
144 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
144 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
145145 ; ATTRIBUTOR-NOT: willreturn
146146 ; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
147147 define void @mutual_recursion2(i1 %c) #0 {
215215 ; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
216216 declare float @llvm.floor.f32(float)
217217
218 ; FNATTRS: Function Attrs: noinline nounwind uwtable
218 ; FNATTRS: Function Attrs: noinline nounwind readnone uwtable
219219 ; FNATTRS-NEXT: define void @call_floor(float %a)
220220 ; FIXME: missing willreturn
221 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
221 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
222222 ; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
223223 define void @call_floor(float %a) #0 {
224224 tail call float @llvm.floor.f32(float %a)
336336 ; FIXME: missing willreturn
337337 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
338338 ; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
339 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
339 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
340340 ; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
341341 define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
342342 br label %3
369369 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
370370 ; FNATTR-NOT: willreturn
371371 ; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
372 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
372 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
373373 ; ATTRIBUTOR-NOT: willreturn
374374 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
375375 define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 {
407407 ; FIXME: missing willreturn
408408 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
409409 ; FNATTR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1)
410 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
410 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
411411 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
412412
413413 define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
438438
439439 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
440440 ; FNATTR-NEXT: define i32 @multiple_return(i32 %a)
441 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable willreturn
441 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
442442 ; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a)
443443 define i32 @multiple_return(i32 %a) #0 {
444444 %b = icmp eq i32 %a, 0
470470 ; FIXME: missing willreturn
471471 ; FNATTR: Function Attrs: noinline nounwind uwtable
472472 ; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
473 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind uwtable
473 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
474474 ; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
475475 define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
476476 %2 = icmp slt i32 %0, 1
514514 ; FNATTR: Function Attrs: noinline nounwind uwtable
515515 ; FNATTR-NOT: willreturn
516516 ; FNATTR-NEXT: define void @unreachable_exit_negative2()
517 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse noreturn nosync nounwind uwtable
517 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
518518 ; ATTRIBUTOR-NOT: willreturn
519519 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
520520 define void @unreachable_exit_negative2() #0 {