예제 #1
0
/// Deduce nocapture attributes for the SCC.
static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
    bool Changed = false;

    ArgumentGraph AG;

    AttrBuilder B;
    B.addAttribute(Attribute::NoCapture);

    // Check each function in turn, determining which pointer arguments are not
    // captured.
    for (Function *F : SCCNodes) {
        // Definitions with weak linkage may be overridden at linktime with
        // something that captures pointers, so treat them like declarations.
        if (F->isDeclaration() || F->mayBeOverridden())
            continue;

        // Functions that are readonly (or readnone) and nounwind and don't return
        // a value can't capture arguments. Don't analyze them.
        if (F->onlyReadsMemory() && F->doesNotThrow() &&
                F->getReturnType()->isVoidTy()) {
            for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E;
                    ++A) {
                if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) {
                    A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B));
                    ++NumNoCapture;
                    Changed = true;
                }
            }
            continue;
        }

        for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E;
                ++A) {
            if (!A->getType()->isPointerTy())
                continue;
            bool HasNonLocalUses = false;
            if (!A->hasNoCaptureAttr()) {
                ArgumentUsesTracker Tracker(SCCNodes);
                PointerMayBeCaptured(&*A, &Tracker);
                if (!Tracker.Captured) {
                    if (Tracker.Uses.empty()) {
                        // If it's trivially not captured, mark it nocapture now.
                        A->addAttr(
                            AttributeSet::get(F->getContext(), A->getArgNo() + 1, B));
                        ++NumNoCapture;
                        Changed = true;
                    } else {
                        // If it's not trivially captured and not trivially not captured,
                        // then it must be calling into another function in our SCC. Save
                        // its particulars for Argument-SCC analysis later.
                        ArgumentGraphNode *Node = AG[&*A];
                        for (SmallVectorImpl<Argument *>::iterator
                                UI = Tracker.Uses.begin(),
                                UE = Tracker.Uses.end();
                                UI != UE; ++UI) {
                            Node->Uses.push_back(AG[*UI]);
                            if (*UI != A)
                                HasNonLocalUses = true;
                        }
                    }
                }
                // Otherwise, it's captured. Don't bother doing SCC analysis on it.
            }
            if (!HasNonLocalUses && !A->onlyReadsMemory()) {
                // Can we determine that it's readonly/readnone without doing an SCC?
                // Note that we don't allow any calls at all here, or else our result
                // will be dependent on the iteration order through the functions in the
                // SCC.
                SmallPtrSet<Argument *, 8> Self;
                Self.insert(&*A);
                Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self);
                if (R != Attribute::None) {
                    AttrBuilder B;
                    B.addAttribute(R);
                    A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B));
                    Changed = true;
                    R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
                }
            }
        }
    }

    // The graph we've collected is partial because we stopped scanning for
    // argument uses once we solved the argument trivially. These partial nodes
    // show up as ArgumentGraphNode objects with an empty Uses list, and for
    // these nodes the final decision about whether they capture has already been
    // made.  If the definition doesn't have a 'nocapture' attribute by now, it
    // captures.

    for (scc_iterator<ArgumentGraph *> I = scc_begin(&AG); !I.isAtEnd(); ++I) {
        const std::vector<ArgumentGraphNode *> &ArgumentSCC = *I;
        if (ArgumentSCC.size() == 1) {
            if (!ArgumentSCC[0]->Definition)
                continue; // synthetic root node

            // eg. "void f(int* x) { if (...) f(x); }"
            if (ArgumentSCC[0]->Uses.size() == 1 &&
                    ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
                Argument *A = ArgumentSCC[0]->Definition;
                A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B));
                ++NumNoCapture;
                Changed = true;
            }
            continue;
        }

        bool SCCCaptured = false;
        for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end();
                I != E && !SCCCaptured; ++I) {
            ArgumentGraphNode *Node = *I;
            if (Node->Uses.empty()) {
                if (!Node->Definition->hasNoCaptureAttr())
                    SCCCaptured = true;
            }
        }
        if (SCCCaptured)
            continue;

        SmallPtrSet<Argument *, 8> ArgumentSCCNodes;
        // Fill ArgumentSCCNodes with the elements of the ArgumentSCC.  Used for
        // quickly looking up whether a given Argument is in this ArgumentSCC.
        for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E; ++I) {
            ArgumentSCCNodes.insert((*I)->Definition);
        }

        for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end();
                I != E && !SCCCaptured; ++I) {
            ArgumentGraphNode *N = *I;
            for (SmallVectorImpl<ArgumentGraphNode *>::iterator UI = N->Uses.begin(),
                    UE = N->Uses.end();
                    UI != UE; ++UI) {
                Argument *A = (*UI)->Definition;
                if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A))
                    continue;
                SCCCaptured = true;
                break;
            }
        }
        if (SCCCaptured)
            continue;

        for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
            Argument *A = ArgumentSCC[i]->Definition;
            A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B));
            ++NumNoCapture;
            Changed = true;
        }

        // We also want to compute readonly/readnone. With a small number of false
        // negatives, we can assume that any pointer which is captured isn't going
        // to be provably readonly or readnone, since by definition we can't
        // analyze all uses of a captured pointer.
        //
        // The false negatives happen when the pointer is captured by a function
        // that promises readonly/readnone behaviour on the pointer, then the
        // pointer's lifetime ends before anything that writes to arbitrary memory.
        // Also, a readonly/readnone pointer may be returned, but returning a
        // pointer is capturing it.

        Attribute::AttrKind ReadAttr = Attribute::ReadNone;
        for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
            Argument *A = ArgumentSCC[i]->Definition;
            Attribute::AttrKind K = determinePointerReadAttrs(A, ArgumentSCCNodes);
            if (K == Attribute::ReadNone)
                continue;
            if (K == Attribute::ReadOnly) {
                ReadAttr = Attribute::ReadOnly;
                continue;
            }
            ReadAttr = K;
            break;
        }

        if (ReadAttr != Attribute::None) {
            AttrBuilder B, R;
            B.addAttribute(ReadAttr);
            R.addAttribute(Attribute::ReadOnly).addAttribute(Attribute::ReadNone);
            for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
                Argument *A = ArgumentSCC[i]->Definition;
                // Clear out existing readonly/readnone attributes
                A->removeAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, R));
                A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B));
                ReadAttr == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
                Changed = true;
            }
        }
    }

    return Changed;
}