From ec268660c8dee1cc4831ca36df0577e057742eb8 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 2 Dec 2015 06:58:49 +0000 Subject: [PATCH] [AttributeSet] Overload AttributeSet::addAttribute to reduce compile time. The new overloaded function is used when an attribute is added to a large number of slots of an AttributeSet (for example, to function parameters). This is much faster than calling AttributeSet::addAttribute once per slot, because AttributeSet::getImpl (which calls FoldingSet::FIndNodeOrInsertPos) is called only once per function instead of once per slot. With this commit, clang compiles a file which used to take over 22 minutes in just 13 seconds. rdar://problem/23581000 Differential Revision: http://reviews.llvm.org/D15085 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@254491 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Attributes.h | 5 ++++ lib/IR/Attributes.cpp | 30 ++++++++++++++++++++++ lib/Transforms/InstCombine/InstCombineCalls.cpp | 21 ++++++++++----- .../Scalar/CorrelatedValuePropagation.cpp | 24 +++++++++-------- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 52a9ca83013..286a6dae37d 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -227,6 +227,11 @@ public: AttributeSet addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, StringRef Value) const; + /// Add an attribute to the attribute set at the given indices. Because + /// attribute sets are immutable, this returns a new set. + AttributeSet addAttribute(LLVMContext &C, ArrayRef Indices, + Attribute A) const; + /// \brief Add attributes to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. AttributeSet addAttributes(LLVMContext &C, unsigned Index, diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index bdefe5917fe..e9626ba7e3b 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -770,6 +770,36 @@ AttributeSet AttributeSet::addAttribute(LLVMContext &C, unsigned Index, return addAttributes(C, Index, AttributeSet::get(C, Index, B)); } +AttributeSet AttributeSet::addAttribute(LLVMContext &C, + ArrayRef Indices, + Attribute A) const { + unsigned I = 0, E = pImpl ? pImpl->getNumAttributes() : 0; + auto IdxI = Indices.begin(), IdxE = Indices.end(); + SmallVector AttrSet; + + while (I != E && IdxI != IdxE) { + if (getSlotIndex(I) < *IdxI) + AttrSet.emplace_back(getSlotAttributes(I++)); + else if (getSlotIndex(I) > *IdxI) + AttrSet.emplace_back(AttributeSet::get(C, std::make_pair(*IdxI++, A))); + else { + AttrBuilder B(getSlotAttributes(I), *IdxI); + B.addAttribute(A); + AttrSet.emplace_back(AttributeSet::get(C, *IdxI, B)); + ++I; + ++IdxI; + } + } + + while (I != E) + AttrSet.emplace_back(getSlotAttributes(I++)); + + while (IdxI != IdxE) + AttrSet.emplace_back(AttributeSet::get(C, std::make_pair(*IdxI++, A))); + + return get(C, AttrSet); +} + AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Index, AttributeSet Attrs) const { if (!pImpl) return Attrs; diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 26088bbe018..d2341c8c05d 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1942,20 +1942,27 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) { // Mark any parameters that are known to be non-null with the nonnull // attribute. This is helpful for inlining calls to functions with null // checks on their arguments. + SmallVector Indices; unsigned ArgNo = 0; + for (Value *V : CS.args()) { if (V->getType()->isPointerTy() && !CS.paramHasAttr(ArgNo+1, Attribute::NonNull) && - isKnownNonNullAt(V, CS.getInstruction(), DT, TLI)) { - AttributeSet AS = CS.getAttributes(); - AS = AS.addAttribute(CS.getInstruction()->getContext(), ArgNo+1, - Attribute::NonNull); - CS.setAttributes(AS); - Changed = true; - } + isKnownNonNullAt(V, CS.getInstruction(), DT, TLI)) + Indices.push_back(ArgNo + 1); ArgNo++; } + assert(ArgNo == CS.arg_size() && "sanity check"); + if (!Indices.empty()) { + AttributeSet AS = CS.getAttributes(); + LLVMContext &Ctx = CS.getInstruction()->getContext(); + AS = AS.addAttribute(Ctx, Indices, + Attribute::get(Ctx, Attribute::NonNull)); + CS.setAttributes(AS); + Changed = true; + } + // If the callee is a pointer to a function, attempt to move any casts to the // arguments of the call/invoke. Value *Callee = CS.getCalledValue(); diff --git a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index d7e02b16a28..686bd407110 100644 --- a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -307,27 +307,31 @@ bool CorrelatedValuePropagation::processSwitch(SwitchInst *SI) { /// processCallSite - Infer nonnull attributes for the arguments at the /// specified callsite. bool CorrelatedValuePropagation::processCallSite(CallSite CS) { - bool Changed = false; - + SmallVector Indices; unsigned ArgNo = 0; + for (Value *V : CS.args()) { PointerType *Type = dyn_cast(V->getType()); if (Type && !CS.paramHasAttr(ArgNo + 1, Attribute::NonNull) && LVI->getPredicateAt(ICmpInst::ICMP_EQ, V, ConstantPointerNull::get(Type), - CS.getInstruction()) == LazyValueInfo::False) { - AttributeSet AS = CS.getAttributes(); - AS = AS.addAttribute(CS.getInstruction()->getContext(), ArgNo + 1, - Attribute::NonNull); - CS.setAttributes(AS); - Changed = true; - } + CS.getInstruction()) == LazyValueInfo::False) + Indices.push_back(ArgNo + 1); ArgNo++; } + assert(ArgNo == CS.arg_size() && "sanity check"); - return Changed; + if (Indices.empty()) + return false; + + AttributeSet AS = CS.getAttributes(); + LLVMContext &Ctx = CS.getInstruction()->getContext(); + AS = AS.addAttribute(Ctx, Indices, Attribute::get(Ctx, Attribute::NonNull)); + CS.setAttributes(AS); + + return true; } Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) { -- 2.11.0