riccibruno created this revision.
riccibruno added a reviewer: rsmith.
riccibruno added a project: clang.
Herald added a reviewer: shafik.
Herald added a subscriber: cfe-commits.

The vast majority of `CharacterLiteral`s have a value which fits into 8 bits
(in the 2666 `CharacterLiteral`s in all of Boost, only 2 don't).
When possible, use the space in the bit-fields of `Stmt` to store the value
and otherwise store it in a trailing object.

This saves 1 pointer per `CharacterLiteral` when the value fits into 8 bits.

Note that in itself this do not save that much space, but this is part of
a larger effort to pack the statements/expressions classes.


Repository:
  rC Clang

https://reviews.llvm.org/D54324

Files:
  include/clang/AST/Expr.h
  include/clang/AST/Stmt.h
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Serialization/ASTReaderStmt.cpp

Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -636,8 +636,8 @@
 void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
   VisitExpr(E);
   E->setValue(Record.readInt());
-  E->setLocation(ReadSourceLocation());
-  E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record.readInt()));
+  E->CharacterLiteralBits.Loc = ReadSourceLocation();
+  E->CharacterLiteralBits.Kind = Record.readInt();
 }
 
 void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
@@ -2454,7 +2454,10 @@
       break;
 
     case EXPR_CHARACTER_LITERAL:
-      S = new (Context) CharacterLiteral(Empty);
+      S = CharacterLiteral::CreateEmpty(
+          Context,
+          /* IsSmallValue=*/CharacterLiteral::isSmallValue(
+              Record[ASTStmtReader::NumExprFields + 0]));
       break;
 
     case EXPR_PAREN:
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -6865,8 +6865,9 @@
     else
       Kind = CharacterLiteral::Ascii;
 
-    E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
-                                       Kind, T, Loc);
+    E = CharacterLiteral::Create(Context, Arg.getAsIntegral().getZExtValue(),
+                                 Kind, T, Loc);
+
   } else if (T->isBooleanType()) {
     E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
                                          T, Loc);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3139,8 +3139,8 @@
   else if (Literal.isUTF8())
     Kind = CharacterLiteral::UTF8;
 
-  Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
-                                             Tok.getLocation());
+  Expr *Lit = CharacterLiteral::Create(Context, Literal.getValue(), Kind, Ty,
+                                       Tok.getLocation());
 
   if (Literal.getUDSuffix().empty())
     return Lit;
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -815,6 +815,37 @@
   return S.str();
 }
 
+CharacterLiteral::CharacterLiteral(unsigned Value, CharacterKind Kind,
+                                   QualType Type, SourceLocation Loc)
+    : Expr(CharacterLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
+           false, false) {
+  CharacterLiteralBits.Kind = Kind;
+  CharacterLiteralBits.Loc = Loc;
+  CharacterLiteralBits.IsSmallValue = isSmallValue(Value);
+  setValue(Value);
+}
+
+CharacterLiteral::CharacterLiteral(EmptyShell Empty, bool IsSmallValue)
+    : Expr(CharacterLiteralClass, Empty) {
+  CharacterLiteralBits.IsSmallValue = IsSmallValue;
+}
+
+CharacterLiteral *CharacterLiteral::Create(const ASTContext &Ctx,
+                                           unsigned Value, CharacterKind Kind,
+                                           QualType Type, SourceLocation Loc) {
+  bool IsSmallValue = isSmallValue(Value);
+  void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned>(!IsSmallValue),
+                           alignof(CharacterLiteral));
+  return new (Mem) CharacterLiteral(Value, Kind, Type, Loc);
+}
+
+CharacterLiteral *CharacterLiteral::CreateEmpty(const ASTContext &Ctx,
+                                                bool IsSmallValue) {
+  void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned>(!IsSmallValue),
+                           alignof(CharacterLiteral));
+  return new (Mem) CharacterLiteral(EmptyShell(), IsSmallValue);
+}
+
 FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
                                  bool isexact, QualType Type, SourceLocation L)
   : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -6289,8 +6289,8 @@
   if (!ToLocationOrErr)
     return ToLocationOrErr.takeError();
 
-  return new (Importer.getToContext()) CharacterLiteral(
-      E->getValue(), E->getKind(), *ToTypeOrErr, *ToLocationOrErr);
+  return CharacterLiteral::Create(Importer.getToContext(), E->getValue(),
+                                  E->getKind(), *ToTypeOrErr, *ToLocationOrErr);
 }
 
 ExpectedStmt ASTNodeImporter::VisitStringLiteral(StringLiteral *E) {
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -361,11 +361,21 @@
   };
 
   class CharacterLiteralBitfields {
+    friend class ASTStmtReader;
     friend class CharacterLiteral;
 
     unsigned : NumExprBits;
 
     unsigned Kind : 3;
+
+    /// The vast majority of character literals have a value which fits into
+    /// 8 bits. In this case this value is stored here and IsSmallValue
+    /// is true. Otherwise, the value is stored as a trailing object and
+    /// IsSmallValue is false.
+    unsigned SmallValue : 8;
+    unsigned IsSmallValue : 1;
+
+    SourceLocation Loc;
   };
 
   enum APFloatSemantics {
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -1396,45 +1396,69 @@
   }
 };
 
-class CharacterLiteral : public Expr {
+class CharacterLiteral final
+    : public Expr,
+      private llvm::TrailingObjects<CharacterLiteral, unsigned> {
+  friend class ASTReader;
+  friend class ASTStmtReader;
+  friend TrailingObjects;
+
 public:
-  enum CharacterKind {
-    Ascii,
-    Wide,
-    UTF8,
-    UTF16,
-    UTF32
-  };
+  enum CharacterKind { Ascii, Wide, UTF8, UTF16, UTF32 };
 
 private:
-  unsigned Value;
-  SourceLocation Loc;
-public:
-  // type should be IntTy
-  CharacterLiteral(unsigned value, CharacterKind kind, QualType type,
-                   SourceLocation l)
-    : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
-           false, false),
-      Value(value), Loc(l) {
-    CharacterLiteralBits.Kind = kind;
+  // The vast majority of character literals have a value which fits into
+  // 8 bits. For this reason in the common case the value is stored inline
+  // in CharacterLiteralBits and isSmallValue() is true. Otherwise the
+  // value is stored in a trailing unsigned and isSmallValue() is false.
+  // Note that the kind of the character literal do not matter for this.
+  // It is therefore perfectly possible to have an UTF32 character literal
+  // with its value stored inline, as long as the value is <= MaxSmallValue.
+  enum { MaxSmallValue = 255 };
+  static bool isSmallValue(unsigned Val) { return Val <= MaxSmallValue; }
+
+  /// True if the value of this character literal is stored inline.
+  bool isSmallValue() const { return CharacterLiteralBits.IsSmallValue; }
+
+
+  void setValue(unsigned Val) {
+    if (isSmallValue()) {
+      assert(isSmallValue(Val) &&
+             "This value is too large to be stored in this CharacterLiteral!");
+      CharacterLiteralBits.SmallValue = Val;
+    } else
+      *getTrailingObjects<unsigned>() = Val;
   }
 
-  /// Construct an empty character literal.
-  CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
+  // Build a character literal.
+  CharacterLiteral(unsigned Value, CharacterKind Kind, QualType Type,
+                   SourceLocation Loc);
 
-  SourceLocation getLocation() const { return Loc; }
+  /// Build an empty character literal.
+  CharacterLiteral(EmptyShell Empty, bool IsSmallValue);
+
+public:
+  /// Create a character literal.
+  static CharacterLiteral *Create(const ASTContext &Ctx, unsigned Value,
+                                  CharacterKind Kind, QualType Type,
+                                  SourceLocation Loc);
+
+  /// Create a character literal, optionally with storage for a large value.
+  static CharacterLiteral *CreateEmpty(const ASTContext &Ctx,
+                                       bool IsSmallValue);
+
+  SourceLocation getLocation() const { return CharacterLiteralBits.Loc; }
   CharacterKind getKind() const {
     return static_cast<CharacterKind>(CharacterLiteralBits.Kind);
   }
 
-  SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
-  SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
-
-  unsigned getValue() const { return Value; }
+  SourceLocation getBeginLoc() const { return getLocation(); }
+  SourceLocation getEndLoc() const { return getLocation(); }
 
-  void setLocation(SourceLocation Location) { Loc = Location; }
-  void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; }
-  void setValue(unsigned Val) { Value = Val; }
+  unsigned getValue() const {
+    return isSmallValue() ? CharacterLiteralBits.SmallValue
+                          : *getTrailingObjects<unsigned>();
+  }
 
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == CharacterLiteralClass;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to