diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2010-12-13 01:44:01 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2010-12-13 01:44:01 +0000 |
commit | 6a57746ea8e94aaf3fbcc961dc95756f5f3dda52 (patch) | |
tree | 418389ced0cb3bfb5be8b76fc94a6aa38f106462 | |
parent | 7b381985353304a7723acb05911ff91634fa1f27 (diff) |
Reduce the number of builtin operator overload candidates added in certain
cases. First, omit all builtin overloads when no non-record type is in the set
of candidate types. Second, avoid arithmetic type overloads for non-arithmetic
or enumeral types (counting vector types as arithmetic due to Clang
extensions). When heavily using constructs such as STL's '<<' based stream
logging, this can have a significant impact. One logging-heavy test case's
compile time dropped by 10% with this. Self-host shows 1-2% improvement in
compile time, but that's likely in the noise.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121665 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 116 |
1 files changed, 89 insertions, 27 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 95c3b84df1..569be26677 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4245,7 +4245,14 @@ class BuiltinCandidateTypeSet { /// \brief The set of vector types that will be used in the built-in /// candidates. TypeSet VectorTypes; - + + /// \brief A flag indicating non-record types are viable candidates + bool HasNonRecordTypes; + + /// \brief A flag indicating whether either arithmetic or enumeration types + /// were present in the candidate set. + bool HasArithmeticOrEnumeralTypes; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -4262,7 +4269,10 @@ public: typedef TypeSet::iterator iterator; BuiltinCandidateTypeSet(Sema &SemaRef) - : SemaRef(SemaRef), Context(SemaRef.Context) { } + : HasNonRecordTypes(false), + HasArithmeticOrEnumeralTypes(false), + SemaRef(SemaRef), + Context(SemaRef.Context) { } void AddTypesConvertedFrom(QualType Ty, SourceLocation Loc, @@ -4290,6 +4300,9 @@ public: iterator vector_begin() { return VectorTypes.begin(); } iterator vector_end() { return VectorTypes.end(); } + + bool hasNonRecordTypes() { return HasNonRecordTypes; } + bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -4419,9 +4432,18 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // We don't care about qualifiers on the type. Ty = Ty.getLocalUnqualifiedType(); + // Flag if we ever add a non-record type. + const RecordType *TyRec = Ty->getAs<RecordType>(); + HasNonRecordTypes = HasNonRecordTypes || !TyRec; + // If we're dealing with an array type, decay to the pointer. if (Ty->isArrayType()) Ty = SemaRef.Context.getArrayDecayedType(Ty); + + // Flag if we encounter an arithmetic type. + HasArithmeticOrEnumeralTypes = + HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(); + if (Ty->isObjCIdType() || Ty->isObjCClassType()) PointerTypes.insert(Ty); else if (Ty->getAs<PointerType>() || Ty->getAs<ObjCObjectPointerType>()) { @@ -4434,35 +4456,36 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) return; } else if (Ty->isEnumeralType()) { + HasArithmeticOrEnumeralTypes = true; EnumerationTypes.insert(Ty); } else if (Ty->isVectorType()) { + // We treat vector types as arithmetic types in many contexts as an + // extension. + HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); - } else if (AllowUserConversions) { - if (const RecordType *TyRec = Ty->getAs<RecordType>()) { - if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { - // No conversion functions in incomplete types. - return; - } + } else if (AllowUserConversions && TyRec) { + // No conversion functions in incomplete types. + if (SemaRef.RequireCompleteType(Loc, Ty, 0)) + return; - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSetImpl *Conversions - = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = I.getDecl(); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + const UnresolvedSetImpl *Conversions + = ClassDecl->getVisibleConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); - // Skip conversion function templates; they don't tell us anything - // about which builtin types we can convert to. - if (isa<FunctionTemplateDecl>(D)) - continue; + // Skip conversion function templates; they don't tell us anything + // about which builtin types we can convert to. + if (isa<FunctionTemplateDecl>(D)) + continue; - CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - if (AllowExplicitConversions || !Conv->isExplicit()) { - AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, - VisibleQuals); - } + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); } } } @@ -4562,6 +4585,7 @@ class BuiltinOperatorOverloadBuilder { Expr **Args; unsigned NumArgs; Qualifiers VisibleTypeConversionsQuals; + bool HasArithmeticOrEnumeralCandidateType; llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; OverloadCandidateSet &CandidateSet; @@ -4697,10 +4721,13 @@ public: BuiltinOperatorOverloadBuilder( Sema &S, Expr **Args, unsigned NumArgs, Qualifiers VisibleTypeConversionsQuals, + bool HasArithmeticOrEnumeralCandidateType, llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, OverloadCandidateSet &CandidateSet) : S(S), Args(Args), NumArgs(NumArgs), VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), + HasArithmeticOrEnumeralCandidateType( + HasArithmeticOrEnumeralCandidateType), CandidateTypes(CandidateTypes), CandidateSet(CandidateSet) { // Validate some of our static helper constants in debug builds. @@ -4735,6 +4762,9 @@ public: // VQ T& operator--(VQ T&); // T operator--(VQ T&, int); void addPlusPlusMinusMinusArithmeticOverloads(OverloadedOperatorKind Op) { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); Arith < NumArithmeticTypes; ++Arith) { addPlusPlusMinusMinusStyleOverloads( @@ -4797,6 +4827,9 @@ public: // T operator+(T); // T operator-(T); void addUnaryPlusOrMinusArithmeticOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { QualType ArithTy = getArithmeticType(Arith); @@ -4834,6 +4867,9 @@ public: // // T operator~(T); void addUnaryTildePromotedIntegralOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { QualType IntTy = getArithmeticType(Int); @@ -5048,6 +5084,9 @@ public: // between types L and R. // Our candidates ignore the first parameter. void addGenericBinaryArithmeticOverloads(bool isComparison) { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Left = FirstPromotedArithmeticType; Left < LastPromotedArithmeticType; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; @@ -5100,6 +5139,9 @@ public: // where LR is the result of the usual arithmetic conversions // between types L and R. void addBinaryBitwiseArithmeticOverloads(OverloadedOperatorKind Op) { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Left = FirstPromotedIntegralType; Left < LastPromotedIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; @@ -5239,6 +5281,9 @@ public: // VQ L& operator+=(VQ L&, R); // VQ L& operator-=(VQ L&, R); void addAssignmentArithmeticOverloads(bool isEqualOp) { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { @@ -5304,6 +5349,9 @@ public: // VQ L& operator^=(VQ L&, R); // VQ L& operator|=(VQ L&, R); void addAssignmentIntegralOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { @@ -5504,12 +5552,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, OverloadCandidateSet& CandidateSet) { // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates - // that make use of these types. + // that make use of these types. Also record whether we encounter non-record + // candidate types or either arithmetic or enumeral candidate types. Qualifiers VisibleTypeConversionsQuals; VisibleTypeConversionsQuals.addConst(); for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); - + + bool HasNonRecordCandidateType = false; + bool HasArithmeticOrEnumeralCandidateType = false; llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); @@ -5520,11 +5571,22 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, Op == OO_AmpAmp || Op == OO_PipePipe), VisibleTypeConversionsQuals); + HasNonRecordCandidateType = HasNonRecordCandidateType || + CandidateTypes[ArgIdx].hasNonRecordTypes(); + HasArithmeticOrEnumeralCandidateType = + HasArithmeticOrEnumeralCandidateType || + CandidateTypes[ArgIdx].hasArithmeticOrEnumeralTypes(); } + // Exit early when no non-record types have been added to the candidate set + // for any of the arguments to the operator. + if (!HasNonRecordCandidateType) + return; + // Setup an object to manage the common state for building overloads. BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs, VisibleTypeConversionsQuals, + HasArithmeticOrEnumeralCandidateType, CandidateTypes, CandidateSet); // Dispatch over the operation to add in only those overloads which apply. |