[llvm] r216192 - Use returns_nonnull in BumpPtrAllocator and MallocAllocator to avoid null-check in placement new

Hans Wennborg hans at hanshq.net
Thu Aug 21 10:10:01 PDT 2014


Author: hans
Date: Thu Aug 21 12:10:00 2014
New Revision: 216192

URL: http://llvm.org/viewvc/llvm-project?rev=216192&view=rev
Log:
Use returns_nonnull in BumpPtrAllocator and MallocAllocator to avoid null-check in placement new

In both Clang and LLVM, this is a common pattern:

  Size = sizeof(DeclRefExpr) + SomeExtraStuff;
  void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
  return new (Mem) DeclRefExpr(...);

The annoying thing is that because the default placement-new operator has a
nothrow specification, the compiler will insert a null check of Mem before
calling the DeclRefExpr constructor. This null check is redundant for us,
because we expect the allocation functions to never return null.

By annotating the allocator functions with returns_nonnull, we can optimize
away these checks. Compiling clang with a recent version of Clang and measuring
with:

  $ perf stat -r20 bin/clang.patch -fsyntax-only -w gcc.c && perf stat -r20 bin/clang.orig -fsyntax-only -w gcc.c

Shows a 2.4% speed-up (+- 0.8%).

The pattern occurs in LLVM too. Measuring with -O3 (and now using bzip2.c
instead, because it's smaller):

  $ perf stat -r20 bin/clang.patch -O3 -w bzip2.c  &&  perf stat -r20 bin/clang.orig -O3 -w bzip2.c

Shows 4.4 % speed-up (+- 1%).

If anyone knows of a similar attribute we can use for MSVC, or some other
technique to get rid off the null check there, please let me know.

Differential Revision: http://reviews.llvm.org/D4989

Modified:
    llvm/trunk/include/llvm/Support/Allocator.h
    llvm/trunk/include/llvm/Support/Compiler.h

Modified: llvm/trunk/include/llvm/Support/Allocator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Allocator.h?rev=216192&r1=216191&r2=216192&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Allocator.h (original)
+++ llvm/trunk/include/llvm/Support/Allocator.h Thu Aug 21 12:10:00 2014
@@ -90,7 +90,10 @@ class MallocAllocator : public Allocator
 public:
   void Reset() {}
 
-  void *Allocate(size_t Size, size_t /*Alignment*/) { return malloc(Size); }
+  LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size,
+                                                size_t /*Alignment*/) {
+    return malloc(Size);
+  }
 
   // Pull in base class overloads.
   using AllocatorBase<MallocAllocator>::Allocate;
@@ -200,7 +203,7 @@ public:
   }
 
   /// \brief Allocate space at the specified alignment.
-  void *Allocate(size_t Size, size_t Alignment) {
+  LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
     assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead.");
 
     // Keep track of how many bytes we've allocated.

Modified: llvm/trunk/include/llvm/Support/Compiler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Compiler.h?rev=216192&r1=216191&r2=216192&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Compiler.h (original)
+++ llvm/trunk/include/llvm/Support/Compiler.h Thu Aug 21 12:10:00 2014
@@ -236,6 +236,12 @@
 #define LLVM_ATTRIBUTE_NORETURN
 #endif
 
+#if __has_attribute(returns_nonnull) || __GNUC_PREREQ(4, 9)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
 /// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
 /// pedantic diagnostics.
 #ifdef __GNUC__





More information about the llvm-commits mailing list