Skip to content

Commit 4e321bb

Browse files
dougsonosyuxuanchen1997
authored andcommitted
Performance optimizations for function effects (nonblocking attribute etc.) (#96844)
Summary: - Put new FunctionProtoType trailing objects last. - Inline FunctionEffectsRef::get() - Manually inline FunctionEffectsRef::Profile(). --------- Co-authored-by: Doug Wyatt <[email protected]> Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60250936
1 parent f66f385 commit 4e321bb

File tree

8 files changed

+119
-108
lines changed

8 files changed

+119
-108
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
643643
/// address spaces (e.g. OpenCL/CUDA)
644644
bool AddrSpaceMapMangling;
645645

646+
/// For performance, track whether any function effects are in use.
647+
mutable bool AnyFunctionEffects = false;
648+
646649
const TargetInfo *Target = nullptr;
647650
const TargetInfo *AuxTarget = nullptr;
648651
clang::PrintingPolicy PrintingPolicy;
@@ -2909,6 +2912,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
29092912
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
29102913
}
29112914

2915+
bool hasAnyFunctionEffects() const { return AnyFunctionEffects; }
2916+
29122917
// Merges two exception specifications, such that the resulting
29132918
// exception spec is the union of both. For example, if either
29142919
// of them can throw something, the result can throw it as well.

clang/include/clang/AST/Type.h

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ class TemplateArgument;
132132
class TemplateArgumentListInfo;
133133
class TemplateArgumentLoc;
134134
class TemplateTypeParmDecl;
135-
template <typename> class TreeTransform;
136135
class TypedefNameDecl;
137136
class UnresolvedUsingTypenameDecl;
138137
class UsingShadowDecl;
@@ -4901,7 +4900,6 @@ class FunctionEffectsRef {
49014900
return !(LHS == RHS);
49024901
}
49034902

4904-
void Profile(llvm::FoldingSetNodeID &ID) const;
49054903
void dump(llvm::raw_ostream &OS) const;
49064904
};
49074905

@@ -4971,8 +4969,8 @@ class FunctionProtoType final
49714969
FunctionProtoType, QualType, SourceLocation,
49724970
FunctionType::FunctionTypeExtraBitfields,
49734971
FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
4974-
Expr *, FunctionDecl *, FunctionType::ExtParameterInfo,
4975-
FunctionEffect, EffectConditionExpr, Qualifiers> {
4972+
Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
4973+
FunctionEffect, EffectConditionExpr> {
49764974
friend class ASTContext; // ASTContext creates these.
49774975
friend TrailingObjects;
49784976

@@ -5003,21 +5001,21 @@ class FunctionProtoType final
50035001
// an ExtParameterInfo for each of the parameters. Present if and
50045002
// only if hasExtParameterInfos() is true.
50055003
//
5004+
// * Optionally a Qualifiers object to represent extra qualifiers that can't
5005+
// be represented by FunctionTypeBitfields.FastTypeQuals. Present if and
5006+
// only if hasExtQualifiers() is true.
5007+
//
50065008
// * Optionally, an array of getNumFunctionEffects() FunctionEffect.
50075009
// Present only when getNumFunctionEffects() > 0
50085010
//
50095011
// * Optionally, an array of getNumFunctionEffects() EffectConditionExpr.
50105012
// Present only when getNumFunctionEffectConditions() > 0.
50115013
//
5012-
// * Optionally a Qualifiers object to represent extra qualifiers that can't
5013-
// be represented by FunctionTypeBitfields.FastTypeQuals. Present if and
5014-
// only if hasExtQualifiers() is true.
5015-
//
50165014
// The optional FunctionTypeExtraBitfields has to be before the data
50175015
// related to the exception specification since it contains the number
50185016
// of exception types.
50195017
//
5020-
// We put the ExtParameterInfos last. If all were equal, it would make
5018+
// We put the ExtParameterInfos later. If all were equal, it would make
50215019
// more sense to put these before the exception specification, because
50225020
// it's much easier to skip past them compared to the elaborate switch
50235021
// required to skip the exception specification. However, all is not
@@ -5134,6 +5132,10 @@ class FunctionProtoType final
51345132
return hasExtParameterInfos() ? getNumParams() : 0;
51355133
}
51365134

5135+
unsigned numTrailingObjects(OverloadToken<Qualifiers>) const {
5136+
return hasExtQualifiers() ? 1 : 0;
5137+
}
5138+
51375139
unsigned numTrailingObjects(OverloadToken<FunctionEffect>) const {
51385140
return getNumFunctionEffects();
51395141
}
@@ -8616,6 +8618,18 @@ QualType DecayedType::getPointeeType() const {
86168618
void FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val,
86178619
unsigned Scale);
86188620

8621+
inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) {
8622+
while (true) {
8623+
QualType Pointee = QT->getPointeeType();
8624+
if (Pointee.isNull())
8625+
break;
8626+
QT = Pointee;
8627+
}
8628+
if (const auto *FPT = QT->getAs<FunctionProtoType>())
8629+
return FPT->getFunctionEffects();
8630+
return {};
8631+
}
8632+
86198633
} // namespace clang
86208634

86218635
#endif // LLVM_CLANG_AST_TYPE_H

clang/lib/AST/ASTContext.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4896,21 +4896,23 @@ QualType ASTContext::getFunctionTypeInternal(
48964896
size_t Size = FunctionProtoType::totalSizeToAlloc<
48974897
QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
48984898
FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
4899-
Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo,
4900-
FunctionEffect, EffectConditionExpr, Qualifiers>(
4899+
Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers,
4900+
FunctionEffect, EffectConditionExpr>(
49014901
NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(),
49024902
EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType,
49034903
ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
4904-
EPI.ExtParameterInfos ? NumArgs : 0, EPI.FunctionEffects.size(),
4905-
EPI.FunctionEffects.conditions().size(),
4906-
EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0);
4904+
EPI.ExtParameterInfos ? NumArgs : 0,
4905+
EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0, EPI.FunctionEffects.size(),
4906+
EPI.FunctionEffects.conditions().size());
49074907

49084908
auto *FTP = (FunctionProtoType *)Allocate(Size, alignof(FunctionProtoType));
49094909
FunctionProtoType::ExtProtoInfo newEPI = EPI;
49104910
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
49114911
Types.push_back(FTP);
49124912
if (!Unique)
49134913
FunctionProtoTypes.InsertNode(FTP, InsertPos);
4914+
if (!EPI.FunctionEffects.empty())
4915+
AnyFunctionEffects = true;
49144916
return QualType(FTP, 0);
49154917
}
49164918

clang/lib/AST/Type.cpp

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3798,9 +3798,18 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
37983798
}
37993799

38003800
epi.ExtInfo.Profile(ID);
3801-
ID.AddInteger((epi.AArch64SMEAttributes << 1) | epi.HasTrailingReturn);
38023801

3803-
epi.FunctionEffects.Profile(ID);
3802+
unsigned EffectCount = epi.FunctionEffects.size();
3803+
bool HasConds = !epi.FunctionEffects.Conditions.empty();
3804+
3805+
ID.AddInteger((EffectCount << 3) | (HasConds << 2) |
3806+
(epi.AArch64SMEAttributes << 1) | epi.HasTrailingReturn);
3807+
3808+
for (unsigned Idx = 0; Idx != EffectCount; ++Idx) {
3809+
ID.AddInteger(epi.FunctionEffects.Effects[Idx].toOpaqueInt32());
3810+
if (HasConds)
3811+
ID.AddPointer(epi.FunctionEffects.Conditions[Idx].getCondition());
3812+
}
38043813
}
38053814

38063815
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
@@ -5181,17 +5190,6 @@ bool FunctionEffect::shouldDiagnoseFunctionCall(
51815190

51825191
// =====
51835192

5184-
void FunctionEffectsRef::Profile(llvm::FoldingSetNodeID &ID) const {
5185-
bool HasConds = !Conditions.empty();
5186-
5187-
ID.AddInteger(size() | (HasConds << 31u));
5188-
for (unsigned Idx = 0, Count = Effects.size(); Idx != Count; ++Idx) {
5189-
ID.AddInteger(Effects[Idx].toOpaqueInt32());
5190-
if (HasConds)
5191-
ID.AddPointer(Conditions[Idx].getCondition());
5192-
}
5193-
}
5194-
51955193
bool FunctionEffectSet::insert(const FunctionEffectWithCondition &NewEC,
51965194
Conflicts &Errs) {
51975195
FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind();
@@ -5313,18 +5311,6 @@ LLVM_DUMP_METHOD void FunctionEffectSet::dump(llvm::raw_ostream &OS) const {
53135311
FunctionEffectsRef(*this).dump(OS);
53145312
}
53155313

5316-
FunctionEffectsRef FunctionEffectsRef::get(QualType QT) {
5317-
while (true) {
5318-
QualType Pointee = QT->getPointeeType();
5319-
if (Pointee.isNull())
5320-
break;
5321-
QT = Pointee;
5322-
}
5323-
if (const auto *FPT = QT->getAs<FunctionProtoType>())
5324-
return FPT->getFunctionEffects();
5325-
return {};
5326-
}
5327-
53285314
FunctionEffectsRef
53295315
FunctionEffectsRef::create(ArrayRef<FunctionEffect> FX,
53305316
ArrayRef<EffectConditionExpr> Conds) {

clang/lib/Sema/Sema.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -718,8 +718,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
718718

719719
diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc());
720720
diagnoseZeroToNullptrConversion(Kind, E);
721-
if (!isCast(CCK) && Kind != CK_NullToPointer &&
722-
Kind != CK_NullToMemberPointer)
721+
if (Context.hasAnyFunctionEffects() && !isCast(CCK) &&
722+
Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer)
723723
diagnoseFunctionEffectConversion(Ty, E->getType(), E->getBeginLoc());
724724

725725
QualType ExprTy = Context.getCanonicalType(E->getType());

clang/lib/Sema/SemaDecl.cpp

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3813,45 +3813,47 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
38133813
return true;
38143814
}
38153815

3816-
const auto OldFX = Old->getFunctionEffects();
3817-
const auto NewFX = New->getFunctionEffects();
38183816
QualType OldQTypeForComparison = OldQType;
3819-
if (OldFX != NewFX) {
3820-
const auto Diffs = FunctionEffectDifferences(OldFX, NewFX);
3821-
for (const auto &Diff : Diffs) {
3822-
if (Diff.shouldDiagnoseRedeclaration(*Old, OldFX, *New, NewFX)) {
3823-
Diag(New->getLocation(),
3824-
diag::warn_mismatched_func_effect_redeclaration)
3825-
<< Diff.effectName();
3826-
Diag(Old->getLocation(), diag::note_previous_declaration);
3817+
if (Context.hasAnyFunctionEffects()) {
3818+
const auto OldFX = Old->getFunctionEffects();
3819+
const auto NewFX = New->getFunctionEffects();
3820+
if (OldFX != NewFX) {
3821+
const auto Diffs = FunctionEffectDifferences(OldFX, NewFX);
3822+
for (const auto &Diff : Diffs) {
3823+
if (Diff.shouldDiagnoseRedeclaration(*Old, OldFX, *New, NewFX)) {
3824+
Diag(New->getLocation(),
3825+
diag::warn_mismatched_func_effect_redeclaration)
3826+
<< Diff.effectName();
3827+
Diag(Old->getLocation(), diag::note_previous_declaration);
3828+
}
38273829
}
3828-
}
3829-
// Following a warning, we could skip merging effects from the previous
3830-
// declaration, but that would trigger an additional "conflicting types"
3831-
// error.
3832-
if (const auto *NewFPT = NewQType->getAs<FunctionProtoType>()) {
3833-
FunctionEffectSet::Conflicts MergeErrs;
3834-
FunctionEffectSet MergedFX =
3835-
FunctionEffectSet::getUnion(OldFX, NewFX, MergeErrs);
3836-
if (!MergeErrs.empty())
3837-
diagnoseFunctionEffectMergeConflicts(MergeErrs, New->getLocation(),
3838-
Old->getLocation());
3839-
3840-
FunctionProtoType::ExtProtoInfo EPI = NewFPT->getExtProtoInfo();
3841-
EPI.FunctionEffects = FunctionEffectsRef(MergedFX);
3842-
QualType ModQT = Context.getFunctionType(NewFPT->getReturnType(),
3843-
NewFPT->getParamTypes(), EPI);
3844-
3845-
New->setType(ModQT);
3846-
NewQType = New->getType();
3847-
3848-
// Revise OldQTForComparison to include the merged effects,
3849-
// so as not to fail due to differences later.
3850-
if (const auto *OldFPT = OldQType->getAs<FunctionProtoType>()) {
3851-
EPI = OldFPT->getExtProtoInfo();
3830+
// Following a warning, we could skip merging effects from the previous
3831+
// declaration, but that would trigger an additional "conflicting types"
3832+
// error.
3833+
if (const auto *NewFPT = NewQType->getAs<FunctionProtoType>()) {
3834+
FunctionEffectSet::Conflicts MergeErrs;
3835+
FunctionEffectSet MergedFX =
3836+
FunctionEffectSet::getUnion(OldFX, NewFX, MergeErrs);
3837+
if (!MergeErrs.empty())
3838+
diagnoseFunctionEffectMergeConflicts(MergeErrs, New->getLocation(),
3839+
Old->getLocation());
3840+
3841+
FunctionProtoType::ExtProtoInfo EPI = NewFPT->getExtProtoInfo();
38523842
EPI.FunctionEffects = FunctionEffectsRef(MergedFX);
3853-
OldQTypeForComparison = Context.getFunctionType(
3854-
OldFPT->getReturnType(), OldFPT->getParamTypes(), EPI);
3843+
QualType ModQT = Context.getFunctionType(NewFPT->getReturnType(),
3844+
NewFPT->getParamTypes(), EPI);
3845+
3846+
New->setType(ModQT);
3847+
NewQType = New->getType();
3848+
3849+
// Revise OldQTForComparison to include the merged effects,
3850+
// so as not to fail due to differences later.
3851+
if (const auto *OldFPT = OldQType->getAs<FunctionProtoType>()) {
3852+
EPI = OldFPT->getExtProtoInfo();
3853+
EPI.FunctionEffects = FunctionEffectsRef(MergedFX);
3854+
OldQTypeForComparison = Context.getFunctionType(
3855+
OldFPT->getReturnType(), OldFPT->getParamTypes(), EPI);
3856+
}
38553857
}
38563858
}
38573859
}

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18100,38 +18100,40 @@ bool Sema::CheckOverridingFunctionAttributes(CXXMethodDecl *New,
1810018100
}
1810118101

1810218102
// Virtual overrides: check for matching effects.
18103-
const auto OldFX = Old->getFunctionEffects();
18104-
const auto NewFXOrig = New->getFunctionEffects();
18105-
18106-
if (OldFX != NewFXOrig) {
18107-
FunctionEffectSet NewFX(NewFXOrig);
18108-
const auto Diffs = FunctionEffectDifferences(OldFX, NewFX);
18109-
FunctionEffectSet::Conflicts Errs;
18110-
for (const auto &Diff : Diffs) {
18111-
switch (Diff.shouldDiagnoseMethodOverride(*Old, OldFX, *New, NewFX)) {
18112-
case FunctionEffectDiff::OverrideResult::NoAction:
18113-
break;
18114-
case FunctionEffectDiff::OverrideResult::Warn:
18115-
Diag(New->getLocation(), diag::warn_mismatched_func_effect_override)
18116-
<< Diff.effectName();
18117-
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
18118-
<< Old->getReturnTypeSourceRange();
18119-
break;
18120-
case FunctionEffectDiff::OverrideResult::Merge: {
18121-
NewFX.insert(Diff.Old, Errs);
18122-
const auto *NewFT = New->getType()->castAs<FunctionProtoType>();
18123-
FunctionProtoType::ExtProtoInfo EPI = NewFT->getExtProtoInfo();
18124-
EPI.FunctionEffects = FunctionEffectsRef(NewFX);
18125-
QualType ModQT = Context.getFunctionType(NewFT->getReturnType(),
18126-
NewFT->getParamTypes(), EPI);
18127-
New->setType(ModQT);
18128-
break;
18129-
}
18103+
if (Context.hasAnyFunctionEffects()) {
18104+
const auto OldFX = Old->getFunctionEffects();
18105+
const auto NewFXOrig = New->getFunctionEffects();
18106+
18107+
if (OldFX != NewFXOrig) {
18108+
FunctionEffectSet NewFX(NewFXOrig);
18109+
const auto Diffs = FunctionEffectDifferences(OldFX, NewFX);
18110+
FunctionEffectSet::Conflicts Errs;
18111+
for (const auto &Diff : Diffs) {
18112+
switch (Diff.shouldDiagnoseMethodOverride(*Old, OldFX, *New, NewFX)) {
18113+
case FunctionEffectDiff::OverrideResult::NoAction:
18114+
break;
18115+
case FunctionEffectDiff::OverrideResult::Warn:
18116+
Diag(New->getLocation(), diag::warn_mismatched_func_effect_override)
18117+
<< Diff.effectName();
18118+
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
18119+
<< Old->getReturnTypeSourceRange();
18120+
break;
18121+
case FunctionEffectDiff::OverrideResult::Merge: {
18122+
NewFX.insert(Diff.Old, Errs);
18123+
const auto *NewFT = New->getType()->castAs<FunctionProtoType>();
18124+
FunctionProtoType::ExtProtoInfo EPI = NewFT->getExtProtoInfo();
18125+
EPI.FunctionEffects = FunctionEffectsRef(NewFX);
18126+
QualType ModQT = Context.getFunctionType(NewFT->getReturnType(),
18127+
NewFT->getParamTypes(), EPI);
18128+
New->setType(ModQT);
18129+
break;
18130+
}
18131+
}
1813018132
}
18133+
if (!Errs.empty())
18134+
diagnoseFunctionEffectMergeConflicts(Errs, New->getLocation(),
18135+
Old->getLocation());
1813118136
}
18132-
if (!Errs.empty())
18133-
diagnoseFunctionEffectMergeConflicts(Errs, New->getLocation(),
18134-
Old->getLocation());
1813518137
}
1813618138

1813718139
CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();

clang/lib/Sema/SemaOverload.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,7 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
18631863
// we need to not alter FromFn, or else even an innocuous cast
18641864
// like dropping effects will fail. In C++ however we do want to
18651865
// alter FromFn (because of the way PerformImplicitConversion works).
1866-
if (getLangOpts().CPlusPlus) {
1866+
if (Context.hasAnyFunctionEffects() && getLangOpts().CPlusPlus) {
18671867
FromFPT = cast<FunctionProtoType>(FromFn); // in case FromFn changed above
18681868

18691869
// Transparently add/drop effects; here we are concerned with

0 commit comments

Comments
 (0)