[cfe-commits] r63061 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/Ownership.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaExprObjC.cpp

Douglas Gregor dgregor at apple.com
Mon Jan 26 14:44:13 PST 2009


Author: dgregor
Date: Mon Jan 26 16:44:13 2009
New Revision: 63061

URL: http://llvm.org/viewvc/llvm-project?rev=63061&view=rev
Log:
Some micro-optimizations for DISABLE_SMART_POINTERS:
  - When it's safe, ActionResult uses the low bit of the pointer for
  the "invalid" flag rather than a separate "bool" value. This keeps
  GCC from generating some truly awful code, for a > 3x speedup in the
  result-passing microbenchmark.
  - When DISABLE_SMART_POINTERS is defined, store an ActionResult
  within ASTOwningResult rather than an ASTOwningPtr. Brings the
  performance benefits of the above to smart pointers with
  DISABLE_SMART_POINTERS defined.

Sadly, these micro-benchmark performance improvements don't seem to
make much of a difference on Cocoa.h right now. However, they're
harmless and might help with future optimizations.


Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Ownership.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprObjC.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Jan 26 16:44:13 2009
@@ -38,6 +38,14 @@
   class Preprocessor;
   class Token;
 
+  // We can re-use the low bit of expression, statement, base, and
+  // member-initializer pointers for the "invalid" flag of
+  // ActionResult.
+  template<> struct IsResultPtrLowBitFree<0> { static const bool value = true; };
+  template<> struct IsResultPtrLowBitFree<1> { static const bool value = true; };
+  template<> struct IsResultPtrLowBitFree<3> { static const bool value = true; };
+  template<> struct IsResultPtrLowBitFree<4> { static const bool value = true; };
+
 /// Action - As the parser reads the input file and recognizes the productions
 /// of the grammar, it invokes methods on this class to turn the parsed input
 /// into something useful: e.g. a parse tree.

Modified: cfe/trunk/include/clang/Parse/Ownership.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Ownership.h?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Ownership.h (original)
+++ cfe/trunk/include/clang/Parse/Ownership.h Mon Jan 26 16:44:13 2009
@@ -110,6 +110,14 @@
   // Basic
   class DiagnosticBuilder;
 
+  // Determines whether the low bit of the result pointer for the
+  // given UID is always zero. If so, ActionResult will use that bit
+  // for it's "invalid" flag.
+  template<unsigned UID>
+  struct IsResultPtrLowBitFree {
+    static const bool value = false;
+  };
+
   /// ActionBase - A small part split from Action because of the horrible
   /// definition order dependencies between Action and the smart pointers.
   class ActionBase {
@@ -127,19 +135,65 @@
     /// ActionResult - This structure is used while parsing/acting on
     /// expressions, stmts, etc.  It encapsulates both the object returned by
     /// the action, plus a sense of whether or not it is valid.
-    template<unsigned UID>
-    struct ActionResult {
+    /// When CompressInvalid is true, the "invalid" flag will be
+    /// stored in the low bit of the Val pointer. 
+    template<unsigned UID, 
+             bool CompressInvalid = IsResultPtrLowBitFree<UID>::value>
+    class ActionResult {
       void *Val;
-      bool isInvalid;
+      bool Invalid;
 
-      ActionResult(bool Invalid = false) : Val(0), isInvalid(Invalid) {}
+    public:
+      ActionResult(bool Invalid = false) : Val(0), Invalid(Invalid) {}
       template<typename ActualExprTy>
-      ActionResult(ActualExprTy *val) : Val(val), isInvalid(false) {}
-      ActionResult(const DiagnosticBuilder &) : Val(0), isInvalid(true) {}
+      ActionResult(ActualExprTy *val) : Val(val), Invalid(false) {}
+      ActionResult(const DiagnosticBuilder &) : Val(0), Invalid(true) {}
+
+      void *get() const { return Val; }
+      void set(void *V) { Val = V; }
+      bool isInvalid() const { return Invalid; }
 
       const ActionResult &operator=(void *RHS) {
         Val = RHS;
-        isInvalid = false;
+        Invalid = false;
+        return *this;
+      }
+    };
+
+    // This ActionResult partial specialization places the "invalid"
+    // flag into the low bit of the pointer.
+    template<unsigned UID>
+    class ActionResult<UID, true> {
+      // A pointer whose low bit is 1 if this result is invalid, 0
+      // otherwise.
+      uintptr_t PtrWithInvalid;
+
+    public:
+      ActionResult(bool Invalid = false) 
+        : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { }
+
+      template<typename ActualExprTy>
+      ActionResult(ActualExprTy *val) 
+        : PtrWithInvalid(reinterpret_cast<uintptr_t>(val)) {
+        assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+      }
+
+      ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { }
+
+      void *get() const { 
+        return reinterpret_cast<void *>(PtrWithInvalid & ~0x01); 
+      }
+
+      void set(void *V) { 
+        PtrWithInvalid = reinterpret_cast<uintptr_t>(V);
+        assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+      }
+
+      bool isInvalid() const { return PtrWithInvalid & 0x01; }
+
+      const ActionResult &operator=(void *RHS) {
+        PtrWithInvalid = reinterpret_cast<uintptr_t>(RHS);
+        assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
         return *this;
       }
     };
@@ -167,7 +221,7 @@
     static const unsigned UID = 1;
   };
   template <> struct DestroyerToUID<&ActionBase::DeleteTemplateArg> {
-    static const unsigned UID = 1;
+    static const unsigned UID = 5; // FIXME
   };
 
   /// ASTOwningResult - A moveable smart pointer for AST nodes that also
@@ -311,18 +365,22 @@
 #endif
   };
 
+  // Important: There are two different implementations of
+  // ASTOwningResult below, depending on whether
+  // DISABLE_SMART_POINTERS is defined. If you make changes that
+  // affect the interface, be sure to compile and test both ways!
+
+#if !defined(DISABLE_SMART_POINTERS)
   template <ASTDestroyer Destroyer>
   class ASTOwningResult
   {
     ASTOwningPtr<Destroyer> Ptr;
     bool Invalid;
 
-#if !defined(DISABLE_SMART_POINTERS)
     friend class moving::ASTResultMover<Destroyer>;
 
     ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT
     ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT
-#endif
 
   public:
     typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
@@ -332,8 +390,7 @@
     ASTOwningResult(ActionBase &actions, void *node)
       : Ptr(actions, node), Invalid(false) {}
     ASTOwningResult(ActionBase &actions, const DumbResult &res)
-      : Ptr(actions, res.Val), Invalid(res.isInvalid) {}
-#if !defined(DISABLE_SMART_POINTERS)
+      : Ptr(actions, res.get()), Invalid(res.isInvalid()) {}
     /// Move from another owning result
     ASTOwningResult(moving::ASTResultMover<Destroyer> mover)
       : Ptr(moving::ASTPtrMover<Destroyer>(mover->Ptr)),
@@ -341,13 +398,7 @@
     /// Move from an owning pointer
     ASTOwningResult(moving::ASTPtrMover<Destroyer> mover)
       : Ptr(mover), Invalid(false) {}
-#else
-    // Normal copying semantics are defined implicitly.
-    // The fake movers need this:
-    explicit ASTOwningResult(void *ptr) : Ptr(ptr), Invalid(false) {}
-#endif
 
-#if !defined(DISABLE_SMART_POINTERS)
     /// Move assignment from another owning result
     ASTOwningResult & operator =(moving::ASTResultMover<Destroyer> mover) {
       Ptr = move(mover->Ptr);
@@ -361,7 +412,6 @@
       Invalid = false;
       return *this;
     }
-#endif
 
     /// Assignment from a raw pointer. Takes ownership - beware!
     ASTOwningResult & operator =(void *raw)
@@ -373,8 +423,8 @@
 
     /// Assignment from an ActionResult. Takes ownership - beware!
     ASTOwningResult & operator =(const DumbResult &res) {
-      Ptr = res.Val;
-      Invalid = res.isInvalid;
+      Ptr = res.get();
+      Invalid = res.isInvalid();
       return *this;
     }
 
@@ -404,7 +454,6 @@
       return Ptr.take();
     }
 
-#if !defined(DISABLE_SMART_POINTERS)
     /// Move hook
     operator moving::ASTResultMover<Destroyer>() {
       return moving::ASTResultMover<Destroyer>(*this);
@@ -414,8 +463,60 @@
     moving::ASTPtrMover<Destroyer> ptr_move() {
       return moving::ASTPtrMover<Destroyer>(Ptr);
     }
-#endif
   };
+#else
+  template <ASTDestroyer Destroyer>
+  class ASTOwningResult
+  {
+  public:
+    typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
+
+  private:
+    DumbResult Result;
+
+  public:
+    explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
+      : Result(invalid) { }
+    ASTOwningResult(ActionBase &actions, void *node) : Result(node) { }
+    ASTOwningResult(ActionBase &actions, const DumbResult &res) : Result(res) { }
+    // Normal copying semantics are defined implicitly.
+    // The fake movers need this:
+    explicit ASTOwningResult(void *ptr) : Result(ptr) { }
+
+    /// Assignment from a raw pointer. Takes ownership - beware!
+    ASTOwningResult & operator =(void *raw)
+    {
+      Result = raw;
+      return *this;
+    }
+
+    /// Assignment from an ActionResult. Takes ownership - beware!
+    ASTOwningResult & operator =(const DumbResult &res) {
+      Result = res;
+      return *this;
+    }
+
+    /// Access to the raw pointer.
+    void * get() const { return Result.get(); }
+
+    bool isInvalid() const { return Result.isInvalid(); }
+
+    /// Does this point to a usable AST node? To be usable, the node must be
+    /// valid and non-null.
+    bool isUsable() const { return !Result.isInvalid() && get(); }
+
+    /// Take outside ownership of the raw pointer.
+    void * take() {
+      return Result.get();
+    }
+
+    /// Alias for interface familiarity with unique_ptr.
+    void * release() { return take(); }
+
+    /// Pass ownership to a classical ActionResult.
+    DumbResult result() { return Result; }
+  };
+#endif
 
   template <ASTDestroyer Destroyer>
   class ASTMultiPtr

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jan 26 16:44:13 2009
@@ -37,7 +37,7 @@
   Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
   ParseDeclarator(DeclaratorInfo);
   
-  return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
+  return Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
 }
 
 /// ParseAttributes - Parse a non-empty attributes list.

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jan 26 16:44:13 2009
@@ -393,13 +393,13 @@
   while (true) {
     // Parse a base-specifier.
     BaseResult Result = ParseBaseSpecifier(ClassDecl);
-    if (Result.isInvalid) {
+    if (Result.isInvalid()) {
       // Skip the rest of this base specifier, up until the comma or
       // opening brace.
       SkipUntil(tok::comma, tok::l_brace, true, true);
     } else {
       // Add this to our array of base specifiers.
-      BaseInfo.push_back(Result.Val);
+      BaseInfo.push_back(Result.get());
     }
 
     // If the next token is a comma, consume it and keep reading
@@ -835,8 +835,8 @@
   
   do {
     MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
-    if (!MemInit.isInvalid)
-      MemInitializers.push_back(MemInit.Val);
+    if (!MemInit.isInvalid())
+      MemInitializers.push_back(MemInit.get());
 
     if (Tok.is(tok::comma))
       ConsumeToken();

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Jan 26 16:44:13 2009
@@ -333,7 +333,7 @@
 Parser::OwningExprResult
 Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
   Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
-  TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
+  TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
 
   assert(Tok.is(tok::l_paren) && "Expected '('!");
   SourceLocation LParenLoc = ConsumeParen();
@@ -629,10 +629,10 @@
 
   // Finish up the type.
   Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
-  if (Result.isInvalid)
+  if (Result.isInvalid())
     return 0;
   else
-    return Result.Val;
+    return Result.get();
 }
 
 /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Jan 26 16:44:13 2009
@@ -252,9 +252,9 @@
 
   OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); }
   OwningExprResult Owned(ExprResult R) {
-    if (R.isInvalid)
+    if (R.isInvalid())
       return ExprError();
-    return OwningExprResult(*this, R.Val);
+    return OwningExprResult(*this, R.get());
   }
   OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); }
 

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=63061&r1=63060&r2=63061&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jan 26 16:44:13 2009
@@ -202,7 +202,7 @@
         superTy = Context.getPointerType(superTy);
         ExprResult ReceiverExpr = new ObjCSuperExpr(SourceLocation(), superTy);
         // We are really in an instance method, redirect.
-        return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac,
+        return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, rbrac,
                                     Args, NumArgs);
       }
       // We are sending a message to 'super' within a class method. Do nothing,
@@ -216,7 +216,7 @@
         ExprResult ReceiverExpr = new DeclRefExpr(VD, VD->getType(), 
                                                   receiverLoc);
         // We are really in an instance method, redirect.
-        return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac,
+        return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, rbrac,
                                     Args, NumArgs);
       }
       return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;





More information about the cfe-commits mailing list