-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang] Optimize some getBeginLoc
implementations
#141058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang-modules @llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesThe bulk of the changes are in We cache Begin/End source locs in the trailing objects, in the space left by making the offset to the trailing objects static. Fixes #140876 Patch is 27.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/141058.diff 10 Files Affected:
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e9c3c16c87598..2a1b5a838d794 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1344,7 +1344,13 @@ class DeclRefExpr final
SourceLocation getLocation() const { return DeclRefExprBits.Loc; }
void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY;
+
+ SourceLocation getBeginLoc() const {
+ if (hasQualifier())
+ return getQualifierLoc().getBeginLoc();
+ return DeclRefExprBits.Loc;
+ }
+
SourceLocation getEndLoc() const LLVM_READONLY;
/// Determine whether this declaration reference was preceded by a
@@ -2901,34 +2907,44 @@ class CallExpr : public Expr {
//
// * An optional of type FPOptionsOverride.
//
- // Note that we store the offset in bytes from the this pointer to the start
- // of the trailing objects. It would be perfectly possible to compute it
- // based on the dynamic kind of the CallExpr. However 1.) we have plenty of
- // space in the bit-fields of Stmt. 2.) It was benchmarked to be faster to
- // compute this once and then load the offset from the bit-fields of Stmt,
- // instead of re-computing the offset each time the trailing objects are
- // accessed.
+ // CallExpr subclasses are asssumed to be 32 bytes or less, and CallExpr
+ // itself is 24 bytes. To avoid having to recompute or store the offset of the
+ // trailing objects, we put it at 32 bytes (such that it is suitable for all
+ // subclasses) We use the 8 bytes gap left for instances of CallExpr to store
+ // the begin and end source locations. Caching the begin source location in
+ // particular as a significant impact on perf as getBeginLoc is assumed to be
+ // cheap.
+ // The layourt is as follow:
+ // CallExpr | Begin | End | Trailing Objects
+ // CXXMemberCallExpr | Trailing Objects
+ // A bit in CallExprBitfields indicates if source locations are presents.
+protected:
+ static constexpr unsigned offsetToTrailingObjects = 32;
+ template <typename T>
+ static constexpr unsigned
+ sizeToAllocateForCallExprSubclass(unsigned SizeOfTrailingObjects) {
+ static_assert(sizeof(T) <= CallExpr::offsetToTrailingObjects);
+ return SizeOfTrailingObjects + CallExpr::offsetToTrailingObjects;
+ }
+
+private:
/// Return a pointer to the start of the trailing array of "Stmt *".
Stmt **getTrailingStmts() {
return reinterpret_cast<Stmt **>(reinterpret_cast<char *>(this) +
- CallExprBits.OffsetToTrailingObjects);
+ offsetToTrailingObjects);
}
Stmt *const *getTrailingStmts() const {
return const_cast<CallExpr *>(this)->getTrailingStmts();
}
- /// Map a statement class to the appropriate offset in bytes from the
- /// this pointer to the trailing objects.
- static unsigned offsetToTrailingObjects(StmtClass SC);
-
unsigned getSizeOfTrailingStmts() const {
return (1 + getNumPreArgs() + getNumArgs()) * sizeof(Stmt *);
}
size_t getOffsetOfTrailingFPFeatures() const {
assert(hasStoredFPFeatures());
- return CallExprBits.OffsetToTrailingObjects + getSizeOfTrailingStmts();
+ return offsetToTrailingObjects + getSizeOfTrailingStmts();
}
public:
@@ -2975,14 +2991,14 @@ class CallExpr : public Expr {
FPOptionsOverride *getTrailingFPFeatures() {
assert(hasStoredFPFeatures());
return reinterpret_cast<FPOptionsOverride *>(
- reinterpret_cast<char *>(this) + CallExprBits.OffsetToTrailingObjects +
+ reinterpret_cast<char *>(this) + offsetToTrailingObjects +
getSizeOfTrailingStmts());
}
const FPOptionsOverride *getTrailingFPFeatures() const {
assert(hasStoredFPFeatures());
return reinterpret_cast<const FPOptionsOverride *>(
- reinterpret_cast<const char *>(this) +
- CallExprBits.OffsetToTrailingObjects + getSizeOfTrailingStmts());
+ reinterpret_cast<const char *>(this) + offsetToTrailingObjects +
+ getSizeOfTrailingStmts());
}
public:
@@ -3028,6 +3044,19 @@ class CallExpr : public Expr {
bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; }
+ bool usesMemberSyntax() const {
+ return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax;
+ }
+ void setUsesMemberSyntax(bool V = true) {
+ CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = V;
+ // Because the source location may be different for explicit
+ // member, we reset the cached values.
+ if (CallExprBits.HasTrailingSourceLocs) {
+ CallExprBits.HasTrailingSourceLocs = false;
+ updateTrailingSourceLocs();
+ }
+ }
+
bool isCoroElideSafe() const { return CallExprBits.IsCoroElideSafe; }
void setCoroElideSafe(bool V = true) { CallExprBits.IsCoroElideSafe = V; }
@@ -3187,9 +3216,59 @@ class CallExpr : public Expr {
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceLocation getBeginLoc() const LLVM_READONLY;
- SourceLocation getEndLoc() const LLVM_READONLY;
+ template <unsigned N> SourceLocation getTrailingSourceLoc() const {
+ static_assert(N <= 1);
+ assert(CallExprBits.HasTrailingSourceLocs && "No trailing source loc");
+ static_assert(sizeof(CallExpr) <=
+ offsetToTrailingObjects + 2 * sizeof(SourceLocation));
+ return *reinterpret_cast<const SourceLocation *>(
+ reinterpret_cast<const char *>(this) + sizeof(CallExpr) +
+ sizeof(SourceLocation) * N);
+ }
+
+ SourceLocation getBeginLoc() const {
+ if (CallExprBits.HasTrailingSourceLocs)
+ return getTrailingSourceLoc<0>();
+
+ if (usesMemberSyntax()) {
+ if (auto FirstArgLoc = getArg(0)->getBeginLoc(); FirstArgLoc.isValid()) {
+ return FirstArgLoc;
+ }
+ }
+ return getCallee()->getBeginLoc();
+ }
+
+ SourceLocation getEndLoc() const {
+ if (CallExprBits.HasTrailingSourceLocs)
+ return getTrailingSourceLoc<0>();
+
+ SourceLocation end = getRParenLoc();
+ if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1))
+ end = getArg(getNumArgs() - 1)->getEndLoc();
+ return end;
+ }
+
+private:
+ bool hasTrailingSourceLoc() const {
+ return CallExprBits.HasTrailingSourceLocs;
+ }
+ void updateTrailingSourceLocs() {
+ assert(!CallExprBits.HasTrailingSourceLocs &&
+ "Trailing source loc already set?");
+ assert(getStmtClass() == CallExprClass &&
+ "Calling setTrailingSourceLocs on a subclass of CallExpr");
+ static_assert(sizeof(CallExpr) <=
+ offsetToTrailingObjects + 2 * sizeof(SourceLocation));
+
+ SourceLocation *Locs = reinterpret_cast<SourceLocation *>(
+ reinterpret_cast<char *>(this) + sizeof(CallExpr));
+ new (Locs) SourceLocation(getBeginLoc());
+ new (Locs + 1) SourceLocation(getEndLoc());
+ CallExprBits.HasTrailingSourceLocs = true;
+ }
+
+public:
/// Return true if this is a call to __assume() or __builtin_assume() with
/// a non-value-dependent constant parameter evaluating as false.
bool isBuiltinAssumeFalse(const ASTContext &Ctx) const;
diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h
index d7da3272d0943..952c79753d10a 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -283,7 +283,9 @@ class NestedNameSpecifierLoc {
/// For example, if this instance refers to a nested-name-specifier
/// \c \::std::vector<int>::, the returned source range would cover
/// from the initial '::' to the last '::'.
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(getBeginLoc(), getEndLoc());
+ }
/// Retrieve the source range covering just the last part of
/// this nested-name-specifier, not including the prefix.
@@ -296,14 +298,18 @@ class NestedNameSpecifierLoc {
/// Retrieve the location of the beginning of this
/// nested-name-specifier.
SourceLocation getBeginLoc() const {
- return getSourceRange().getBegin();
+ if (!Qualifier)
+ return SourceLocation();
+
+ NestedNameSpecifierLoc First = *this;
+ while (NestedNameSpecifierLoc Prefix = First.getPrefix())
+ First = Prefix;
+ return First.getLocalSourceRange().getBegin();
}
/// Retrieve the location of the end of this
/// nested-name-specifier.
- SourceLocation getEndLoc() const {
- return getSourceRange().getEnd();
- }
+ SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); }
/// Retrieve the location of the beginning of this
/// component of the nested-name-specifier.
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 336eb6d3df7e1..e233f04b2405d 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -563,17 +563,21 @@ class alignas(void *) Stmt {
unsigned HasFPFeatures : 1;
/// True if the call expression is a must-elide call to a coroutine.
+ LLVM_PREFERRED_TYPE(bool)
unsigned IsCoroElideSafe : 1;
- /// Padding used to align OffsetToTrailingObjects to a byte multiple.
- unsigned : 24 - 4 - NumExprBits;
+ /// Tracks When CallExpr is used to represent an explicit object
+ /// member function, in order to adjust the begin location.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ExplicitObjectMemFunUsingMemberSyntax : 1;
- /// The offset in bytes from the this pointer to the start of the
- /// trailing objects belonging to CallExpr. Intentionally byte sized
- /// for faster access.
- unsigned OffsetToTrailingObjects : 8;
+ /// Indicates that SourceLocations are cached as
+ /// Trailing objects. See the definition of CallExpr.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasTrailingSourceLocs : 1;
};
- enum { NumCallExprBits = 32 };
+
+ enum { NumCallExprBits = 25 };
class MemberExprBitfields {
friend class ASTStmtReader;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index fe874ccd7b60f..7f768665b3157 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -547,11 +547,6 @@ void DeclRefExpr::setDecl(ValueDecl *NewD) {
setDependence(computeDependence(this, NewD->getASTContext()));
}
-SourceLocation DeclRefExpr::getBeginLoc() const {
- if (hasQualifier())
- return getQualifierLoc().getBeginLoc();
- return getNameInfo().getBeginLoc();
-}
SourceLocation DeclRefExpr::getEndLoc() const {
if (hasExplicitTemplateArgs())
return getRAngleLoc();
@@ -1455,6 +1450,23 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
+static unsigned SizeOfCallExprInstance(Expr::StmtClass SC) {
+ switch (SC) {
+ case Expr::CallExprClass:
+ return sizeof(CallExpr);
+ case Expr::CXXOperatorCallExprClass:
+ return sizeof(CXXOperatorCallExpr);
+ case Expr::CXXMemberCallExprClass:
+ return sizeof(CXXMemberCallExpr);
+ case Expr::UserDefinedLiteralClass:
+ return sizeof(UserDefinedLiteral);
+ case Expr::CUDAKernelCallExprClass:
+ return sizeof(CUDAKernelCallExpr);
+ default:
+ llvm_unreachable("unexpected class deriving from CallExpr!");
+ }
+}
+
CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
SourceLocation RParenLoc, FPOptionsOverride FPFeatures,
@@ -1464,11 +1476,8 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
unsigned NumPreArgs = PreArgs.size();
CallExprBits.NumPreArgs = NumPreArgs;
assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!");
-
- unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC);
- CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects;
- assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) &&
- "OffsetToTrailingObjects overflow!");
+ assert(SizeOfCallExprInstance(SC) <= offsetToTrailingObjects &&
+ "This CallExpr subclass is too big or unsupported");
CallExprBits.UsesADL = static_cast<bool>(UsesADL);
@@ -1484,6 +1493,9 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
CallExprBits.IsCoroElideSafe = false;
+ CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false;
+ CallExprBits.HasTrailingSourceLocs = false;
+
if (hasStoredFPFeatures())
setStoredFPFeatures(FPFeatures);
}
@@ -1493,13 +1505,10 @@ CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs,
: Expr(SC, Empty), NumArgs(NumArgs) {
CallExprBits.NumPreArgs = NumPreArgs;
assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!");
-
- unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC);
- CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects;
- assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) &&
- "OffsetToTrailingObjects overflow!");
CallExprBits.HasFPFeatures = HasFPFeatures;
CallExprBits.IsCoroElideSafe = false;
+ CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false;
+ CallExprBits.HasTrailingSourceLocs = false;
}
CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn,
@@ -1510,41 +1519,41 @@ CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn,
unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(
/*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage());
- void *Mem =
- Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr));
- return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
- RParenLoc, FPFeatures, MinNumArgs, UsesADL);
+ void *Mem = Ctx.Allocate(
+ sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects),
+ alignof(CallExpr));
+ CallExpr *E =
+ new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
+ RParenLoc, FPFeatures, MinNumArgs, UsesADL);
+ E->updateTrailingSourceLocs();
+ return E;
}
CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
bool HasFPFeatures, EmptyShell Empty) {
unsigned SizeOfTrailingObjects =
CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures);
- void *Mem =
- Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr));
+ void *Mem = Ctx.Allocate(
+ sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects),
+ alignof(CallExpr));
return new (Mem)
CallExpr(CallExprClass, /*NumPreArgs=*/0, NumArgs, HasFPFeatures, Empty);
}
-unsigned CallExpr::offsetToTrailingObjects(StmtClass SC) {
- switch (SC) {
- case CallExprClass:
- return sizeof(CallExpr);
- case CXXOperatorCallExprClass:
- return sizeof(CXXOperatorCallExpr);
- case CXXMemberCallExprClass:
- return sizeof(CXXMemberCallExpr);
- case UserDefinedLiteralClass:
- return sizeof(UserDefinedLiteral);
- case CUDAKernelCallExprClass:
- return sizeof(CUDAKernelCallExpr);
- default:
- llvm_unreachable("unexpected class deriving from CallExpr!");
- }
-}
-
Decl *Expr::getReferencedDeclOfCallee() {
- Expr *CEE = IgnoreParenImpCasts();
+
+ // Optimize for the common case first
+ // (simple function or member function call)
+ // then try more exotic possibilities
+ Expr *CEE = IgnoreImpCasts();
+
+ if (auto *DRE = dyn_cast<DeclRefExpr>(CEE))
+ return DRE->getDecl();
+
+ if (auto *ME = dyn_cast<MemberExpr>(CEE))
+ return ME->getMemberDecl();
+
+ CEE = CEE->IgnoreParens();
while (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(CEE))
CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
@@ -1638,43 +1647,6 @@ CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
return {nullptr, nullptr};
}
-SourceLocation CallExpr::getBeginLoc() const {
- if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
- return OCE->getBeginLoc();
-
- // A non-dependent call to a member function with an explicit object parameter
- // is modelled with the object expression being the first argument, e.g. in
- // `o.f(x)`, the callee will be just `f`, and `o` will be the first argument.
- // Since the first argument is written before the callee, the expression's
- // begin location should come from the first argument.
- // This does not apply to dependent calls, which are modelled with `o.f`
- // being the callee.
- if (!isTypeDependent()) {
- if (const auto *Method =
- dyn_cast_if_present<const CXXMethodDecl>(getCalleeDecl());
- Method && Method->isExplicitObjectMemberFunction()) {
- if (auto FirstArgLoc = getArg(0)->getBeginLoc(); FirstArgLoc.isValid()) {
- return FirstArgLoc;
- }
- }
- }
-
- SourceLocation begin = getCallee()->getBeginLoc();
- if (begin.isInvalid() && getNumArgs() > 0 && getArg(0))
- begin = getArg(0)->getBeginLoc();
- return begin;
-}
-
-SourceLocation CallExpr::getEndLoc() const {
- if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
- return OCE->getEndLoc();
-
- SourceLocation end = getRParenLoc();
- if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1))
- end = getArg(getNumArgs() - 1)->getEndLoc();
- return end;
-}
-
OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 00bddce3a1ee2..5c712e146e5a8 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -619,8 +619,10 @@ CXXOperatorCallExpr::Create(const ASTContext &Ctx,
unsigned NumArgs = Args.size();
unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(
/*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage());
- void *Mem = Ctx.Allocate(sizeof(CXXOperatorCallExpr) + SizeOfTrailingObjects,
- alignof(CXXOperatorCallExpr));
+ void *Mem =
+ Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXOperatorCallExpr>(
+ SizeOfTrailingObjects),
+ alignof(CXXOperatorCallExpr));
return new (Mem) CXXOperatorCallExpr(OpKind, Fn, Args, Ty, VK, OperatorLoc,
FPFeatures, UsesADL);
}
@@ -632,8 +634,10 @@ CXXOperatorCallExpr *CXXOperatorCallExpr::CreateEmpty(const ASTContext &Ctx,
// Allocate storage for the trailing objects of CallExpr.
unsigned SizeOfTrailingObjects =
CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures);
- void *Mem = Ctx.Allocate(sizeof(CXXOperatorCallExpr) + SizeOfTrailingObjects,
- alignof(CXXOperatorCallExpr));
+ void *Mem =
+ Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXOperatorCallExpr>(
+ SizeOfTrailingObjects),
+ alignof(CXXOperatorCallExpr));
return new (Mem) CXXOperatorCallExpr(NumArgs, HasFPFeatures, Empty);
}
@@ -684,7 +688,8 @@ CXXMemberCallExpr *CXXMemberCallExpr::Create(const ASTContext &Ctx, Expr *Fn,
unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(
/*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage());
- void *Mem = Ctx.Allocate(sizeof(CXXMemberCallExpr) + SizeOfTrailingObjects,
+ void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXMemberCallExpr>(
+ SizeOfTrailingObjects),
alignof(CXXMemberCallExpr));
return new (Mem)
CXXMemberCallExpr(Fn, Args, Ty, VK, RP, FPFeatures, MinNumArgs);
@@ -697,7 +702,8 @@ CXXMemberCallExpr *CXXMemberCallExpr::CreateEmpty(const ASTContext &Ctx,
// Allocate storage for the trailing objects of CallExpr.
unsigned SizeOfTrailingObjects =
CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures);
- void *Mem = Ctx.Allocate(sizeof(CXXMemberCallExpr) + SizeOfTrailingObjects,
+ void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for working on this!
// CallExpr subclasses are asssumed to be 32 bytes or less, and CallExpr | ||
// itself is 24 bytes. To avoid having to recompute or store the offset of the | ||
// trailing objects, we put it at 32 bytes (such that it is suitable for all | ||
// subclasses) We use the 8 bytes gap left for instances of CallExpr to store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works today, but we keep talking about moving to 64-bit source locations (and that's getting more important thanks to modules), what's the idea for in that situation? Grow the size of CallExpr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have 4 bytes left now. But yeah, if we need more space, we would need a different strategy
clang/include/clang/AST/Expr.h
Outdated
|
||
protected: | ||
static constexpr unsigned offsetToTrailingObjects = 32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static constexpr unsigned offsetToTrailingObjects = 32; | |
static constexpr unsigned OffsetToTrailingObjects = 32; |
clang/include/clang/AST/Expr.h
Outdated
if (CallExprBits.HasTrailingSourceLocs) | ||
return getTrailingSourceLoc<0>(); | ||
|
||
SourceLocation end = getRParenLoc(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SourceLocation end = getRParenLoc(); | |
SourceLocation End = getRParenLoc(); |
clang/include/clang/AST/Expr.h
Outdated
offsetToTrailingObjects + 2 * sizeof(SourceLocation)); | ||
|
||
SourceLocation *Locs = reinterpret_cast<SourceLocation *>( | ||
reinterpret_cast<char *>(this) + sizeof(CallExpr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reinterpret_cast<SourceLocation *>(this + 1)
?
clang/lib/AST/Expr.cpp
Outdated
|
||
// Optimize for the common case first | ||
// (simple function or member function call) | ||
// then try more exotic possibilities |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// then try more exotic possibilities | |
// then try more exotic possibilities. |
if (auto *ME = dyn_cast<MemberExpr>(CEE)) | ||
return ME->getMemberDecl(); | ||
|
||
CEE = CEE->IgnoreParens(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Warning bells going off!
From IgnoreParenImpCasts()
:
/// Skip past any parentheses and implicit casts which might surround this
/// expression until reaching a fixed point.
/// FIXME: IgnoreParenImpCasts really ought to be equivalent to
/// IgnoreParens() + IgnoreImpCasts() until reaching a fixed point. However
/// this is currently not the case. Instead IgnoreParenImpCasts() skips:
Are we subtly changing behavior here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in so far as the tests pass (we already handle SubstNonTypeTemplateParmExpr, and MaterializeTemporaryExpr is a prvalue), so... it should be fine. If not, we will add more tests!
✅ With the latest revision this PR passed the C/C++ code formatter. |
clang/include/clang/AST/Expr.h
Outdated
// The layourt is as follow: | ||
// CallExpr | Begin | 4 bytes left | Trailing Objects | ||
// CXXMemberCallExpr | Trailing Objects | ||
// A bit in CallExprBitfields indicates if source locations are presents. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// A bit in CallExprBitfields indicates if source locations are presents. | |
// A bit in CallExprBitfields indicates if source locations are present. |
clang/include/clang/AST/Expr.h
Outdated
SourceLocation getEndLoc() const LLVM_READONLY; | ||
SourceLocation getBeginLoc() const { | ||
if (CallExprBits.HasTrailingSourceLoc) { | ||
assert(CallExprBits.HasTrailingSourceLoc && "No trailing source loc"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of this assert? Right after you just did the same thing in the 'if' above?
clang/include/clang/AST/Expr.h
Outdated
reinterpret_cast<const char *>(this) + sizeof(CallExpr)); | ||
} | ||
|
||
if (usesMemberSyntax()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no curleys on single liners?
// then try more exotic possibilities | ||
Expr *CEE = IgnoreImpCasts(); | ||
|
||
if (auto *DRE = dyn_cast<DeclRefExpr>(CEE)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find myself wondering if this function would benefit SEVERELY from a llvm::typeSwitch
.
if (!Qualifier) | ||
return SourceLocation(); | ||
|
||
NestedNameSpecifierLoc First = *this; | ||
while (NestedNameSpecifierLoc Prefix = First.getPrefix()) | ||
First = Prefix; | ||
return First.getLocalSourceRange().getBegin(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see the differences of changes on these functions... Are they related?
The bulk of the changes are in
CallExpr
We cache Begin/End source locs in the trailing objects, in the space left by making the offset to the trailing objects static.
We also set a flag to indicate that we are calling an explicit object member function, further reducing the cost of getBeginLoc.
Fixes #140876