@@ -2907,22 +2907,27 @@ class CallExpr : public Expr {
29072907 //
29082908 // * An optional of type FPOptionsOverride.
29092909 //
2910- // Note that we store the offset in bytes from the this pointer to the start
2911- // of the trailing objects. It would be perfectly possible to compute it
2912- // based on the dynamic kind of the CallExpr. However 1.) we have plenty of
2913- // space in the bit-fields of Stmt. 2.) It was benchmarked to be faster to
2914- // compute this once and then load the offset from the bit-fields of Stmt,
2915- // instead of re-computing the offset each time the trailing objects are
2916- // accessed.
2910+ // CallExpr subclasses are asssumed to be 32 bytes or less, and CallExpr
2911+ // itself is 24 bytes. To avoid having to recompute or store the offset of the
2912+ // trailing objects, we put it at 32 bytes (such that it is suitable for all
2913+ // subclasses) We use the 8 bytes gap left for instances of CallExpr to store
2914+ // the begin and end source locations. Caching the begin source location in
2915+ // particular as a significant impact on perf as getBeginLoc is assumed to be
2916+ // cheap.
2917+ // The layourt is as follow:
2918+ // CallExpr | Begin | End | Trailing Objects
2919+ // CXXMemberCallExpr | Trailing Objects
2920+ // A bit in CallExprBitfields indicates if source locations are presents.
29172921
29182922protected:
29192923 static constexpr unsigned offsetToTrailingObjects = 32 ;
2920-
29212924 template <typename T>
2922- static constexpr unsigned sizeToAllocateForCallExprSubclass (unsigned SizeOfTrailingObjects) {
2925+ static constexpr unsigned
2926+ sizeToAllocateForCallExprSubclass (unsigned SizeOfTrailingObjects) {
29232927 static_assert (sizeof (T) <= CallExpr::offsetToTrailingObjects);
29242928 return SizeOfTrailingObjects + CallExpr::offsetToTrailingObjects;
29252929 }
2930+
29262931private:
29272932 // / Return a pointer to the start of the trailing array of "Stmt *".
29282933 Stmt **getTrailingStmts () {
@@ -2992,8 +2997,8 @@ class CallExpr : public Expr {
29922997 const FPOptionsOverride *getTrailingFPFeatures () const {
29932998 assert (hasStoredFPFeatures ());
29942999 return reinterpret_cast <const FPOptionsOverride *>(
2995- reinterpret_cast <const char *>(this ) +
2996- offsetToTrailingObjects + getSizeOfTrailingStmts ());
3000+ reinterpret_cast <const char *>(this ) + offsetToTrailingObjects +
3001+ getSizeOfTrailingStmts ());
29973002 }
29983003
29993004public:
@@ -3039,15 +3044,17 @@ class CallExpr : public Expr {
30393044
30403045 bool hasStoredFPFeatures () const { return CallExprBits.HasFPFeatures ; }
30413046
3042- bool usesMemberSyntax () const { return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax ; }
3047+ bool usesMemberSyntax () const {
3048+ return CallExprBits.ExplicitObjectMemFunUsingMemberSyntax ;
3049+ }
30433050 void setUsesMemberSyntax (bool V = true ) {
3044- CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = V;
3045- // Because the source location may be different for explicit
3046- // member, we reset the cached values.
3047- if (CallExprBits.HasTrailingSourceLoc ) {
3048- CallExprBits.HasTrailingSourceLoc = false ;
3049- setTrailingSourceLocs ();
3050- }
3051+ CallExprBits.ExplicitObjectMemFunUsingMemberSyntax = V;
3052+ // Because the source location may be different for explicit
3053+ // member, we reset the cached values.
3054+ if (CallExprBits.HasTrailingSourceLocs ) {
3055+ CallExprBits.HasTrailingSourceLocs = false ;
3056+ updateTrailingSourceLocs ();
3057+ }
30513058 }
30523059
30533060 bool isCoroElideSafe () const { return CallExprBits.IsCoroElideSafe ; }
@@ -3209,24 +3216,20 @@ class CallExpr : public Expr {
32093216 SourceLocation getRParenLoc () const { return RParenLoc; }
32103217 void setRParenLoc (SourceLocation L) { RParenLoc = L; }
32113218
3219+ template <unsigned N> SourceLocation getTrailingSourceLoc () const {
3220+ static_assert (N <= 1 );
3221+ assert (CallExprBits.HasTrailingSourceLocs && " No trailing source loc" );
3222+ static_assert (sizeof (CallExpr) <=
3223+ offsetToTrailingObjects + 2 * sizeof (SourceLocation));
3224+ return *reinterpret_cast <const SourceLocation *>(
3225+ reinterpret_cast <const char *>(this ) + sizeof (CallExpr) +
3226+ sizeof (SourceLocation) * N);
3227+ }
3228+
32123229 SourceLocation getBeginLoc () const {
3213- if (CallExprBits.HasTrailingSourceLoc ) {
3214- static_assert (sizeof (CallExpr) <= offsetToTrailingObjects + 2 * sizeof (SourceLocation));
3215- return *reinterpret_cast <const SourceLocation*>(reinterpret_cast <const char *>(this ) +
3216- sizeof (CallExpr));
3217- }
3230+ if (CallExprBits.HasTrailingSourceLocs )
3231+ return getTrailingSourceLoc<0 >();
32183232
3219- // if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
3220- // return OCE->getBeginLoc();
3221-
3222- // A non-dependent call to a member function with an explicit object parameter
3223- // is modelled with the object expression being the first argument, e.g. in
3224- // `o.f(x)`, the callee will be just `f`, and `o` will be the first argument.
3225- // Since the first argument is written before the callee, the expression's
3226- // begin location should come from the first argument.
3227- // This does not apply to dependent calls, which are modelled with `o.f`
3228- // being the callee.
3229- // Because this check is expennsive, we cache the result.
32303233 if (usesMemberSyntax ()) {
32313234 if (auto FirstArgLoc = getArg (0 )->getBeginLoc (); FirstArgLoc.isValid ()) {
32323235 return FirstArgLoc;
@@ -3236,36 +3239,36 @@ class CallExpr : public Expr {
32363239 }
32373240
32383241 SourceLocation getEndLoc () const {
3239- if (CallExprBits.HasTrailingSourceLoc ) {
3240- static_assert (sizeof (CallExpr) <= offsetToTrailingObjects + 2 * sizeof (SourceLocation));
3241- return *reinterpret_cast <const SourceLocation*>(reinterpret_cast <const char *>(this ) +
3242- sizeof (CallExpr) + sizeof (SourceLocation));
3243- }
3242+ if (CallExprBits.HasTrailingSourceLocs )
3243+ return getTrailingSourceLoc<0 >();
32443244
32453245 SourceLocation end = getRParenLoc ();
32463246 if (end.isInvalid () && getNumArgs () > 0 && getArg (getNumArgs () - 1 ))
32473247 end = getArg (getNumArgs () - 1 )->getEndLoc ();
32483248 return end;
32493249 }
32503250
3251-
32523251private:
3253- friend class ASTStmtReader ;
32543252 bool hasTrailingSourceLoc () const {
3255- return CallExprBits.HasTrailingSourceLoc ;
3253+ return CallExprBits.HasTrailingSourceLocs ;
32563254 }
3257- void setTrailingSourceLocs () {
3258- assert (!CallExprBits.HasTrailingSourceLoc );
3259- static_assert (sizeof (CallExpr) <= offsetToTrailingObjects + 2 * sizeof (SourceLocation));
3260- SourceLocation* Locs = reinterpret_cast <SourceLocation*>(reinterpret_cast <char *>(this ) +
3261- sizeof (CallExpr));
3262- new (Locs) SourceLocation (getBeginLoc ());
3263- new (Locs+1 ) SourceLocation (getEndLoc ());
3264- CallExprBits.HasTrailingSourceLoc = true ;
3255+
3256+ void updateTrailingSourceLocs () {
3257+ assert (!CallExprBits.HasTrailingSourceLocs &&
3258+ " Trailing source loc already set?" );
3259+ assert (getStmtClass () == CallExprClass &&
3260+ " Calling setTrailingSourceLocs on a subclass of CallExpr" );
3261+ static_assert (sizeof (CallExpr) <=
3262+ offsetToTrailingObjects + 2 * sizeof (SourceLocation));
3263+
3264+ SourceLocation *Locs = reinterpret_cast <SourceLocation *>(
3265+ reinterpret_cast <char *>(this ) + sizeof (CallExpr));
3266+ new (Locs) SourceLocation (getBeginLoc ());
3267+ new (Locs + 1 ) SourceLocation (getEndLoc ());
3268+ CallExprBits.HasTrailingSourceLocs = true ;
32653269 }
32663270
32673271public:
3268-
32693272 // / Return true if this is a call to __assume() or __builtin_assume() with
32703273 // / a non-value-dependent constant parameter evaluating as false.
32713274 bool isBuiltinAssumeFalse (const ASTContext &Ctx) const ;
0 commit comments