https://github.com/cor3ntin created https://github.com/llvm/llvm-project/pull/141058
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 >From 381c2219e346acfbf5b61e93fcc3233af6b7c3a7 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 21 May 2025 23:09:00 +0200 Subject: [PATCH 1/8] try optimize --- clang/lib/AST/Expr.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index fe874ccd7b60f..1906e46042cad 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1544,7 +1544,16 @@ unsigned CallExpr::offsetToTrailingObjects(StmtClass SC) { } 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(); while (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) CEE = NTTP->getReplacement()->IgnoreParenImpCasts(); >From 16077ed74794645452434c9ec761d642789e09ac Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 00:28:05 +0200 Subject: [PATCH 2/8] remove call to getCalleeDecl --- clang/include/clang/AST/Expr.h | 5 +++++ clang/include/clang/AST/Stmt.h | 5 +++-- clang/lib/AST/Expr.cpp | 21 ++++++++++----------- clang/lib/Sema/SemaOpenCL.cpp | 2 +- clang/lib/Sema/SemaOverload.cpp | 2 ++ clang/lib/Serialization/ASTReaderStmt.cpp | 2 ++ clang/lib/Serialization/ASTWriterStmt.cpp | 2 ++ 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index e9c3c16c87598..a8bfae2e7efda 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3028,6 +3028,9 @@ class CallExpr : public Expr { bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; } + bool usesMemberSyntax() const { return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax; } + void setUsesMemberSyntax(bool V = true) { CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = V; } + bool isCoroElideSafe() const { return CallExprBits.IsCoroElideSafe; } void setCoroElideSafe(bool V = true) { CallExprBits.IsCoroElideSafe = V; } @@ -3220,6 +3223,8 @@ class CallExpr : public Expr { } }; +static_assert(sizeof(CallExpr) == 24); + /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr final diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 336eb6d3df7e1..b3ad285ca73fd 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -563,10 +563,11 @@ 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; + 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 diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1906e46042cad..e6ccd0904eefd 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1484,6 +1484,8 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); CallExprBits.IsCoroElideSafe = false; + CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false; + if (hasStoredFPFeatures()) setStoredFPFeatures(FPFeatures); } @@ -1549,12 +1551,15 @@ Decl *Expr::getReferencedDeclOfCallee() { // (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(); @@ -1658,20 +1663,14 @@ SourceLocation CallExpr::getBeginLoc() const { // 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; - } + // Because this check is expennsive, we cache the result. + if (usesMemberSyntax()) { + 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; + return getCallee()->getBeginLoc(); } SourceLocation CallExpr::getEndLoc() const { diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp index 9f746fffd34d0..865c57ae7c158 100644 --- a/clang/lib/Sema/SemaOpenCL.cpp +++ b/clang/lib/Sema/SemaOpenCL.cpp @@ -542,7 +542,7 @@ bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call) { auto RT = Call->getArg(0)->getType(); if (!RT->isPointerType() || RT->getPointeeType().getAddressSpace() == LangAS::opencl_constant) { - Diag(Call->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) + Diag(Call->getArg(0)->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); return true; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 23304e12f8c31..69768dd3a7212 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14832,6 +14832,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CE = CallExpr::Create(Context, FnExpr.get(), MultiExprArg(&ObjectParam, 1), ResultType, VK, Exp.get()->getEndLoc(), CurFPFeatureOverrides()); + CE->setUsesMemberSyntax(true); } else { MemberExpr *ME = BuildMemberExpr(Exp.get(), /*IsArrow=*/false, SourceLocation(), @@ -16159,6 +16160,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, TheCall = CallExpr::Create(Context, FnExpr.get(), Args, ResultType, VK, RParenLoc, CurFPFeatureOverrides(), Proto->getNumParams()); + TheCall->setUsesMemberSyntax(true); } else { // Convert the object argument (for a non-static member function call). ExprResult ObjectArg = PerformImplicitObjectArgumentInitialization( diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 0ba0378754eb4..a4bb9f2da5547 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1036,6 +1036,8 @@ void ASTStmtReader::VisitCallExpr(CallExpr *E) { E->setADLCallKind( static_cast<CallExpr::ADLCallKind>(CurrentUnpackingBits->getNextBit())); bool HasFPFeatures = CurrentUnpackingBits->getNextBit(); + E->setCoroElideSafe(CurrentUnpackingBits->getNextBit()); + E->setUsesMemberSyntax(CurrentUnpackingBits->getNextBit()); assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!"); E->setRParenLoc(readSourceLocation()); E->setCallee(Record.readSubExpr()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index b9eabd5ddb64c..0401be33e8930 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -959,6 +959,8 @@ void ASTStmtWriter::VisitCallExpr(CallExpr *E) { CurrentPackingBits.updateBits(); CurrentPackingBits.addBit(static_cast<bool>(E->getADLCallKind())); CurrentPackingBits.addBit(E->hasStoredFPFeatures()); + CurrentPackingBits.addBit(E->isCoroElideSafe()); + CurrentPackingBits.addBit(E->usesMemberSyntax()); Record.AddSourceLocation(E->getRParenLoc()); Record.AddStmt(E->getCallee()); >From fb437b0a22f6e45ccec1ed20fa244afb998b4531 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 01:29:19 +0200 Subject: [PATCH 3/8] Optimize another getBeginLoc --- clang/include/clang/AST/Expr.h | 8 +++++++- clang/lib/AST/Expr.cpp | 5 ----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index a8bfae2e7efda..c45e9b7e3c47f 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 diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e6ccd0904eefd..7dbdb35148c5a 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(); >From dc33c5a616f03e4e568d1a7b424ca7f218786571 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 09:40:01 +0200 Subject: [PATCH 4/8] Try more optimizations --- clang/include/clang/AST/Expr.h | 44 +++++++++++++++++++++------- clang/include/clang/AST/Stmt.h | 8 ++--- clang/lib/AST/Expr.cpp | 53 ++-------------------------------- clang/lib/AST/ExprCXX.cpp | 16 +++++----- 4 files changed, 46 insertions(+), 75 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index c45e9b7e3c47f..b5fdd44f95939 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2915,26 +2915,31 @@ class CallExpr : public Expr { // instead of re-computing the offset each time the trailing objects are // accessed. +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: @@ -2981,14 +2986,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()); + offsetToTrailingObjects + getSizeOfTrailingStmts()); } public: @@ -3196,7 +3201,26 @@ class CallExpr : public Expr { SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation 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. + // Because this check is expennsive, we cache the result. + if (usesMemberSyntax()) { + if (auto FirstArgLoc = getArg(0)->getBeginLoc(); FirstArgLoc.isValid()) { + return FirstArgLoc; + } + } + return getCallee()->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY; /// Return true if this is a call to __assume() or __builtin_assume() with @@ -3229,8 +3253,6 @@ class CallExpr : public Expr { } }; -static_assert(sizeof(CallExpr) == 24); - /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr final diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index b3ad285ca73fd..3c2dc293b3a1e 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -568,13 +568,9 @@ class alignas(void *) Stmt { 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; }; - enum { NumCallExprBits = 32 }; + + enum { NumCallExprBits = 24 }; class MemberExprBitfields { friend class ASTStmtReader; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 7dbdb35148c5a..1696ea42a7fa3 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1460,11 +1460,6 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, CallExprBits.NumPreArgs = NumPreArgs; assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!"); - unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC); - CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects; - assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) && - "OffsetToTrailingObjects overflow!"); - CallExprBits.UsesADL = static_cast<bool>(UsesADL); setCallee(Fn); @@ -1490,11 +1485,6 @@ 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; } @@ -1508,7 +1498,8 @@ CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); void *Mem = - Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr)); + Ctx.Allocate(sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects), + alignof(CallExpr)); return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, RParenLoc, FPFeatures, MinNumArgs, UsesADL); } @@ -1518,28 +1509,11 @@ CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures); void *Mem = - Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr)); + 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() { // Optimize for the common case first @@ -1647,27 +1621,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. - // Because this check is expennsive, we cache the result. - if (usesMemberSyntax()) { - if (auto FirstArgLoc = getArg(0)->getBeginLoc(); FirstArgLoc.isValid()) { - return FirstArgLoc; - } - } - - return getCallee()->getBeginLoc(); -} - SourceLocation CallExpr::getEndLoc() const { if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this)) return OCE->getEndLoc(); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 00bddce3a1ee2..c10fae156bef8 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -619,7 +619,7 @@ 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, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXOperatorCallExpr>(SizeOfTrailingObjects), alignof(CXXOperatorCallExpr)); return new (Mem) CXXOperatorCallExpr(OpKind, Fn, Args, Ty, VK, OperatorLoc, FPFeatures, UsesADL); @@ -632,7 +632,7 @@ 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, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXOperatorCallExpr>(SizeOfTrailingObjects), alignof(CXXOperatorCallExpr)); return new (Mem) CXXOperatorCallExpr(NumArgs, HasFPFeatures, Empty); } @@ -684,7 +684,7 @@ 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 +697,7 @@ 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<CXXMemberCallExpr>(SizeOfTrailingObjects), alignof(CXXMemberCallExpr)); return new (Mem) CXXMemberCallExpr(NumArgs, HasFPFeatures, Empty); } @@ -958,7 +958,7 @@ UserDefinedLiteral *UserDefinedLiteral::Create(const ASTContext &Ctx, Expr *Fn, unsigned NumArgs = Args.size(); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); - void *Mem = Ctx.Allocate(sizeof(UserDefinedLiteral) + SizeOfTrailingObjects, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>(SizeOfTrailingObjects), alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(Fn, Args, Ty, VK, LitEndLoc, SuffixLoc, FPFeatures); @@ -971,7 +971,7 @@ UserDefinedLiteral *UserDefinedLiteral::CreateEmpty(const ASTContext &Ctx, // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPOptions); - void *Mem = Ctx.Allocate(sizeof(UserDefinedLiteral) + SizeOfTrailingObjects, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>(SizeOfTrailingObjects), alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(NumArgs, HasFPOptions, Empty); } @@ -1946,7 +1946,7 @@ CUDAKernelCallExpr::Create(const ASTContext &Ctx, Expr *Fn, CallExpr *Config, unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, FPFeatures.requiresTrailingStorage()); - void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>(SizeOfTrailingObjects), alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(Fn, Config, Args, Ty, VK, RP, FPFeatures, MinNumArgs); @@ -1959,7 +1959,7 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx, // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, HasFPFeatures); - void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects, + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>(SizeOfTrailingObjects), alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty); } >From 21cf4b443185bd3accf7b074c79d54f2277c8b5d Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 10:34:24 +0200 Subject: [PATCH 5/8] cache begin in callexpr --- clang/include/clang/AST/Expr.h | 23 +++++++++++++++++++++++ clang/include/clang/AST/Stmt.h | 5 ++++- clang/lib/AST/Expr.cpp | 8 +++++++- clang/lib/Serialization/ASTReaderStmt.cpp | 3 +++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index b5fdd44f95939..30717c3e2fb92 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3202,6 +3202,12 @@ class CallExpr : public Expr { void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const { + if(CallExprBits.HasTrailingSourceLoc) { + static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); + return *reinterpret_cast<const SourceLocation*>(reinterpret_cast<const char *>(this) + + sizeof(CallExpr)); + } + //if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this)) // return OCE->getBeginLoc(); @@ -3223,6 +3229,23 @@ class CallExpr : public Expr { SourceLocation getEndLoc() const LLVM_READONLY; +private: + friend class ASTStmtReader; + bool hasTrailingSourceLoc() const { + return CallExprBits.HasTrailingSourceLoc; + } + void setTrailingSourceLocs() { + assert(!CallExprBits.HasTrailingSourceLoc); + static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); + SourceLocation* Locs = reinterpret_cast<SourceLocation*>(reinterpret_cast<char *>(this) + + sizeof(CallExpr)); + Locs[0] = getBeginLoc(); + Locs[1] = getEndLoc(); + CallExprBits.HasTrailingSourceLoc = 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/Stmt.h b/clang/include/clang/AST/Stmt.h index 3c2dc293b3a1e..2889fedb4d221 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -568,9 +568,12 @@ class alignas(void *) Stmt { LLVM_PREFERRED_TYPE(bool) unsigned ExplicitObjectMemFunUsingMemberSyntax : 1; + + LLVM_PREFERRED_TYPE(bool) + unsigned HasTrailingSourceLoc : 1; }; - enum { NumCallExprBits = 24 }; + enum { NumCallExprBits = 25 }; class MemberExprBitfields { friend class ASTStmtReader; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1696ea42a7fa3..ace1221bbc439 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1475,6 +1475,7 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); CallExprBits.IsCoroElideSafe = false; CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false; + CallExprBits.HasTrailingSourceLoc = false; if (hasStoredFPFeatures()) setStoredFPFeatures(FPFeatures); @@ -1487,6 +1488,9 @@ CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!"); CallExprBits.HasFPFeatures = HasFPFeatures; CallExprBits.IsCoroElideSafe = false; + CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false; + CallExprBits.HasTrailingSourceLoc = false; + } CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, @@ -1500,8 +1504,10 @@ CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects), alignof(CallExpr)); - return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, + CallExpr* E = new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, RParenLoc, FPFeatures, MinNumArgs, UsesADL); + E->setTrailingSourceLocs(); + return E; } CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index a4bb9f2da5547..a07bc0854e25d 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1047,6 +1047,9 @@ void ASTStmtReader::VisitCallExpr(CallExpr *E) { if (HasFPFeatures) E->setStoredFPFeatures( FPOptionsOverride::getFromOpaqueInt(Record.readInt())); + + if(E->getStmtClass() == Stmt::CallExprClass) + E->setTrailingSourceLocs(); } void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { >From 7472299d253cdf8341846171be2e8b77f87aad74 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 12:36:32 +0200 Subject: [PATCH 6/8] revert changes to explicit object member functions --- clang/include/clang/AST/Expr.h | 18 +++++++++++++++--- clang/include/clang/AST/NestedNameSpecifier.h | 14 +++++++++++--- clang/lib/AST/Expr.cpp | 9 --------- clang/lib/AST/NestedNameSpecifier.cpp | 12 ------------ 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 30717c3e2fb92..24d8896fb996a 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3227,7 +3227,19 @@ class CallExpr : public Expr { return getCallee()->getBeginLoc(); } - SourceLocation getEndLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const { + if(CallExprBits.HasTrailingSourceLoc) { + static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); + return *reinterpret_cast<const SourceLocation*>(reinterpret_cast<const char *>(this) + + sizeof(CallExpr) + sizeof(SourceLocation)); + } + + SourceLocation end = getRParenLoc(); + if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1)) + end = getArg(getNumArgs() - 1)->getEndLoc(); + return end; + } + private: friend class ASTStmtReader; @@ -3239,8 +3251,8 @@ class CallExpr : public Expr { static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); SourceLocation* Locs = reinterpret_cast<SourceLocation*>(reinterpret_cast<char *>(this) + sizeof(CallExpr)); - Locs[0] = getBeginLoc(); - Locs[1] = getEndLoc(); + new (Locs) SourceLocation(getBeginLoc()); + new (Locs+1) SourceLocation(getEndLoc()); CallExprBits.HasTrailingSourceLoc = true; } diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index d7da3272d0943..83237b788ec18 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,13 +298,19 @@ 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(); + return getLocalSourceRange().getEnd(); } /// Retrieve the location of the beginning of this diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index ace1221bbc439..e1d2b2956a5a0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1627,15 +1627,6 @@ CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { return {nullptr, nullptr}; } -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, diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index bd0fe36d781da..db1ad89565189 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -407,18 +407,6 @@ static void *LoadPointer(void *Data, unsigned Offset) { return Result; } -SourceRange NestedNameSpecifierLoc::getSourceRange() const { - if (!Qualifier) - return SourceRange(); - - NestedNameSpecifierLoc First = *this; - while (NestedNameSpecifierLoc Prefix = First.getPrefix()) - First = Prefix; - - return SourceRange(First.getLocalSourceRange().getBegin(), - getLocalSourceRange().getEnd()); -} - SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { if (!Qualifier) return SourceRange(); >From 99d11a55c0222e8ed64aa35a068a3f08673baaba Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 13:33:23 +0200 Subject: [PATCH 7/8] reset the cache when setting deducing this functions --- clang/include/clang/AST/Expr.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 24d8896fb996a..0089c2d49a645 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3040,7 +3040,15 @@ class CallExpr : public Expr { bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; } bool usesMemberSyntax() const { return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax; } - void setUsesMemberSyntax(bool V = true) { CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = V; } + 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.HasTrailingSourceLoc) { + CallExprBits.HasTrailingSourceLoc = false; + setTrailingSourceLocs(); + } + } bool isCoroElideSafe() const { return CallExprBits.IsCoroElideSafe; } void setCoroElideSafe(bool V = true) { CallExprBits.IsCoroElideSafe = V; } >From fd4aaf504142aa733ff03c335f3ffcc2e9e889e7 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 22 May 2025 14:20:39 +0200 Subject: [PATCH 8/8] cleanups --- clang/include/clang/AST/Expr.h | 107 +++++++++--------- clang/include/clang/AST/NestedNameSpecifier.h | 4 +- clang/include/clang/AST/Stmt.h | 6 +- clang/lib/AST/Expr.cpp | 43 +++++-- clang/lib/AST/ExprCXX.cpp | 42 ++++--- clang/lib/Sema/SemaOpenCL.cpp | 3 +- clang/lib/Serialization/ASTReaderStmt.cpp | 4 +- 7 files changed, 124 insertions(+), 85 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 0089c2d49a645..2a1b5a838d794 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2907,22 +2907,27 @@ 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 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() { @@ -2992,8 +2997,8 @@ class CallExpr : public Expr { const FPOptionsOverride *getTrailingFPFeatures() const { assert(hasStoredFPFeatures()); return reinterpret_cast<const FPOptionsOverride *>( - reinterpret_cast<const char *>(this) + - offsetToTrailingObjects + getSizeOfTrailingStmts()); + reinterpret_cast<const char *>(this) + offsetToTrailingObjects + + getSizeOfTrailingStmts()); } public: @@ -3039,15 +3044,17 @@ class CallExpr : public Expr { bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; } - bool usesMemberSyntax() const { return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax; } + 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.HasTrailingSourceLoc) { - CallExprBits.HasTrailingSourceLoc = false; - setTrailingSourceLocs(); - } + 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; } @@ -3209,24 +3216,20 @@ class CallExpr : public Expr { SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + 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.HasTrailingSourceLoc) { - static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); - return *reinterpret_cast<const SourceLocation*>(reinterpret_cast<const char *>(this) + - sizeof(CallExpr)); - } + if (CallExprBits.HasTrailingSourceLocs) + return getTrailingSourceLoc<0>(); - //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. - // Because this check is expennsive, we cache the result. if (usesMemberSyntax()) { if (auto FirstArgLoc = getArg(0)->getBeginLoc(); FirstArgLoc.isValid()) { return FirstArgLoc; @@ -3236,11 +3239,8 @@ class CallExpr : public Expr { } SourceLocation getEndLoc() const { - if(CallExprBits.HasTrailingSourceLoc) { - static_assert(sizeof(CallExpr) <= offsetToTrailingObjects + 2 * sizeof(SourceLocation)); - return *reinterpret_cast<const SourceLocation*>(reinterpret_cast<const char *>(this) + - sizeof(CallExpr) + sizeof(SourceLocation)); - } + if (CallExprBits.HasTrailingSourceLocs) + return getTrailingSourceLoc<0>(); SourceLocation end = getRParenLoc(); if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1)) @@ -3248,24 +3248,27 @@ class CallExpr : public Expr { return end; } - private: - friend class ASTStmtReader; bool hasTrailingSourceLoc() const { - return CallExprBits.HasTrailingSourceLoc; + return CallExprBits.HasTrailingSourceLocs; } - void setTrailingSourceLocs() { - assert(!CallExprBits.HasTrailingSourceLoc); - 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.HasTrailingSourceLoc = true; + + 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 83237b788ec18..952c79753d10a 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -309,9 +309,7 @@ class NestedNameSpecifierLoc { /// Retrieve the location of the end of this /// nested-name-specifier. - SourceLocation getEndLoc() const { - return getLocalSourceRange().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 2889fedb4d221..e233f04b2405d 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -566,11 +566,15 @@ class alignas(void *) Stmt { LLVM_PREFERRED_TYPE(bool) unsigned IsCoroElideSafe : 1; + /// 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; + /// Indicates that SourceLocations are cached as + /// Trailing objects. See the definition of CallExpr. LLVM_PREFERRED_TYPE(bool) - unsigned HasTrailingSourceLoc : 1; + unsigned HasTrailingSourceLocs : 1; }; enum { NumCallExprBits = 25 }; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e1d2b2956a5a0..7f768665b3157 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1450,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, @@ -1459,6 +1476,8 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, unsigned NumPreArgs = PreArgs.size(); CallExprBits.NumPreArgs = NumPreArgs; assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!"); + assert(SizeOfCallExprInstance(SC) <= offsetToTrailingObjects && + "This CallExpr subclass is too big or unsupported"); CallExprBits.UsesADL = static_cast<bool>(UsesADL); @@ -1475,7 +1494,7 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); CallExprBits.IsCoroElideSafe = false; CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false; - CallExprBits.HasTrailingSourceLoc = false; + CallExprBits.HasTrailingSourceLocs = false; if (hasStoredFPFeatures()) setStoredFPFeatures(FPFeatures); @@ -1489,8 +1508,7 @@ CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, CallExprBits.HasFPFeatures = HasFPFeatures; CallExprBits.IsCoroElideSafe = false; CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = false; - CallExprBits.HasTrailingSourceLoc = false; - + CallExprBits.HasTrailingSourceLocs = false; } CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, @@ -1501,12 +1519,13 @@ 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(sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects), - alignof(CallExpr)); - CallExpr* E = new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, - RParenLoc, FPFeatures, MinNumArgs, UsesADL); - E->setTrailingSourceLocs(); + 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; } @@ -1514,8 +1533,9 @@ CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) { unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures); - void *Mem = - Ctx.Allocate(sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects), alignof(CallExpr)); + void *Mem = Ctx.Allocate( + sizeToAllocateForCallExprSubclass<CallExpr>(SizeOfTrailingObjects), + alignof(CallExpr)); return new (Mem) CallExpr(CallExprClass, /*NumPreArgs=*/0, NumArgs, HasFPFeatures, Empty); } @@ -1627,7 +1647,6 @@ CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { return {nullptr, nullptr}; } - 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 c10fae156bef8..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(sizeToAllocateForCallExprSubclass<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(sizeToAllocateForCallExprSubclass<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(sizeToAllocateForCallExprSubclass<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(sizeToAllocateForCallExprSubclass<CXXMemberCallExpr>(SizeOfTrailingObjects), + void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CXXMemberCallExpr>( + SizeOfTrailingObjects), alignof(CXXMemberCallExpr)); return new (Mem) CXXMemberCallExpr(NumArgs, HasFPFeatures, Empty); } @@ -958,8 +964,10 @@ UserDefinedLiteral *UserDefinedLiteral::Create(const ASTContext &Ctx, Expr *Fn, unsigned NumArgs = Args.size(); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); - void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>(SizeOfTrailingObjects), - alignof(UserDefinedLiteral)); + void *Mem = + Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>( + SizeOfTrailingObjects), + alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(Fn, Args, Ty, VK, LitEndLoc, SuffixLoc, FPFeatures); } @@ -971,8 +979,10 @@ UserDefinedLiteral *UserDefinedLiteral::CreateEmpty(const ASTContext &Ctx, // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPOptions); - void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>(SizeOfTrailingObjects), - alignof(UserDefinedLiteral)); + void *Mem = + Ctx.Allocate(sizeToAllocateForCallExprSubclass<UserDefinedLiteral>( + SizeOfTrailingObjects), + alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(NumArgs, HasFPOptions, Empty); } @@ -1946,8 +1956,10 @@ CUDAKernelCallExpr::Create(const ASTContext &Ctx, Expr *Fn, CallExpr *Config, unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, FPFeatures.requiresTrailingStorage()); - void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>(SizeOfTrailingObjects), - alignof(CUDAKernelCallExpr)); + void *Mem = + Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>( + SizeOfTrailingObjects), + alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(Fn, Config, Args, Ty, VK, RP, FPFeatures, MinNumArgs); } @@ -1959,8 +1971,10 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx, // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, HasFPFeatures); - void *Mem = Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>(SizeOfTrailingObjects), - alignof(CUDAKernelCallExpr)); + void *Mem = + Ctx.Allocate(sizeToAllocateForCallExprSubclass<CUDAKernelCallExpr>( + SizeOfTrailingObjects), + alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty); } diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp index 865c57ae7c158..f11a40e3964ff 100644 --- a/clang/lib/Sema/SemaOpenCL.cpp +++ b/clang/lib/Sema/SemaOpenCL.cpp @@ -542,7 +542,8 @@ bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call) { auto RT = Call->getArg(0)->getType(); if (!RT->isPointerType() || RT->getPointeeType().getAddressSpace() == LangAS::opencl_constant) { - Diag(Call->getArg(0)->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) + Diag(Call->getArg(0)->getBeginLoc(), + diag::err_opencl_builtin_to_addr_invalid_arg) << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); return true; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index a07bc0854e25d..5827799d91e1b 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1048,8 +1048,8 @@ void ASTStmtReader::VisitCallExpr(CallExpr *E) { E->setStoredFPFeatures( FPOptionsOverride::getFromOpaqueInt(Record.readInt())); - if(E->getStmtClass() == Stmt::CallExprClass) - E->setTrailingSourceLocs(); + if (E->getStmtClass() == Stmt::CallExprClass) + E->updateTrailingSourceLocs(); } void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits