Hi rsmith,

Instead of creating a copy on the stack just stash them in a private
constant global. This saves both the copying overhead and the stack
space, and gives the optimizer more room to constant fold.

This tries to make array temporaries more similar to regular arrays,
they can't use the same logic because a temporary has no VarDecl to be
bound to so we roll our own version here.

The original use case for this optimization was code like
  for (int i : {1, 2, 3, 4, 5, 6, 7, 8, 10})
    foo(i);
where without this patch (assuming that the loop is not unrolled) we
would alloca an array on the stack, copy the 10 values over and
iterate on that. With this patch we put the array in .text use it
directly. Apart from that case this helps on virtually any passing of
a constant std::initializer_list as a function argument.

http://reviews.llvm.org/D8034

Files:
  lib/CodeGen/CGExpr.cpp
  test/CodeGenCXX/compound-literals.cpp
  test/CodeGenCXX/cxx0x-initializer-array.cpp
  test/CodeGenCXX/cxx0x-initializer-references.cpp
  test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -301,6 +301,22 @@
   switch (M->getStorageDuration()) {
   case SD_FullExpression:
   case SD_Automatic:
+    // If we have a constant temporary array try to promote it into a constant
+    // global under the same rules a normal constant array would've been
+    // promoted. This is easier on the optimizer and generally emits fewer
+    // instructions.
+    if (M->getType()->isArrayType() &&
+        CGF.CGM.isTypeConstant(M->getType(), true))
+      if (llvm::Constant *Init =
+              CGF.CGM.EmitConstantExpr(Inner, M->getType(), &CGF)) {
+        assert(Inner->isConstantInitializer(CGF.getContext(), false));
+        auto *GV = new llvm::GlobalVariable(
+            CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+            llvm::GlobalValue::PrivateLinkage, Init, ".initializer_list");
+        GV->setAlignment(
+            CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity());
+        return GV;
+      }
     return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
 
   case SD_Thread:
Index: test/CodeGenCXX/compound-literals.cpp
===================================================================
--- test/CodeGenCXX/compound-literals.cpp
+++ test/CodeGenCXX/compound-literals.cpp
@@ -28,7 +28,7 @@
 
 // CHECK-LABEL: define i32 @_Z1gv()
 int g() {
-  // CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]]
+  // CHECK: store [2 x i32]* @.initializer_list, [2 x i32]** [[V:%[a-z0-9.]+]]
   const int (&v)[2] = (int [2]) {1,2};
 
   // CHECK: [[A:%[a-z0-9.]+]] = load [2 x i32]*, [2 x i32]** [[V]]
Index: test/CodeGenCXX/cxx0x-initializer-array.cpp
===================================================================
--- test/CodeGenCXX/cxx0x-initializer-array.cpp
+++ test/CodeGenCXX/cxx0x-initializer-array.cpp
@@ -44,7 +44,7 @@
 
   // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEv
   void g() {
-    // CHECK: store i32 -1,
+    // CHECK: call void @_ZN22ValueInitArrayOfMemPtr1fERA3_KMNS_1SEi([3 x i32]* dereferenceable(12) @.initializer_list)
     f(a{});
   }
 }
Index: test/CodeGenCXX/cxx0x-initializer-references.cpp
===================================================================
--- test/CodeGenCXX/cxx0x-initializer-references.cpp
+++ test/CodeGenCXX/cxx0x-initializer-references.cpp
@@ -43,13 +43,7 @@
     // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
     const A &ra1{1, 2};
 
-    // CHECK-NEXT: getelementptr inbounds [3 x i32], [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0
-    // CHECK-NEXT: store i32 1
-    // CHECK-NEXT: getelementptr inbounds i32, i32* %{{.*}}, i{{32|64}} 1
-    // CHECK-NEXT: store i32 2
-    // CHECK-NEXT: getelementptr inbounds i32, i32* %{{.*}}, i{{32|64}} 1
-    // CHECK-NEXT: store i32 3
-    // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
+    // CHECK-NEXT: store [3 x i32]* @.initializer_list, [3 x i32]** %{{.*}}, align
     const int (&arrayRef)[] = {1, 2, 3};
 
     // CHECK-NEXT: ret
Index: test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
===================================================================
--- test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -64,14 +64,20 @@
 // CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
 // CHECK: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
 
+// CHECK: @.initializer_list = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+// CHECK: @.initializer_list2 = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+
 // CHECK: @_ZN15partly_constant1kE = global i32 0, align 4
 // CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
 // CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8
 // CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8
 // CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4
 // CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4
 // CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
 
+// CHECK: @.initializer_list8 = private constant [2 x i32] [i32 42, i32 43], align 4
+// CHECK: @.initializer_list9 = private constant [3 x %"class.ConstExpr::C"] [%"class.ConstExpr::C" { i32 1 }, %"class.ConstExpr::C" { i32 2 }, %"class.ConstExpr::C" { i32 3 }], align 4
+
 // CHECK: appending global
 
 
@@ -220,10 +226,8 @@
 
 // CHECK-LABEL: define void @_ZN8haslist1C2Ev
 haslist1::haslist1()
-// CHECK: alloca [3 x i32]
-// CHECK: store i32 1
-// CHECK: store i32 2
-// CHECK: store i32 3
+// CHECK-NOT: alloca [3 x i32]
+// CHECK: store i32* getelementptr inbounds ([3 x i32]* @.initializer_list, i64 0, i64 0)
 // CHECK: store i{{32|64}} 3
   : il{1, 2, 3}
 {
@@ -246,12 +250,8 @@
 
 void fn10() {
   // CHECK-LABEL: define void @_Z4fn10v
-  // CHECK: alloca [3 x i32]
   // CHECK: call noalias i8* @_Znw{{[jm]}}
-  // CHECK: store i32 1
-  // CHECK: store i32 2
-  // CHECK: store i32 3
-  // CHECK: store i32*
+  // CHECK: store i32* getelementptr inbounds ([3 x i32]* @.initializer_list2, i64 0, i64 0)
   // CHECK: store i{{32|64}} 3
   (void) new std::initializer_list<int> {1, 2, 3};
 }
@@ -462,6 +462,22 @@
   template<int x> void f() { new MyClass({42, 43}); }
   template void f<0>();
   // CHECK-LABEL: define {{.*}} @_ZN7PR204451fILi0EEEvv(
+  // CHECK: store i32* getelementptr inbounds ([2 x i32]* @.initializer_list8, i64 0, i64 0)
   // CHECK: call void @_ZN7PR204456vectorC1ESt16initializer_listIiE(
   // CHECK: call void @_ZN7PR204457MyClassC1ERKNS_6vectorE(
 }
+
+namespace ConstExpr {
+  class C {
+    int x;
+  public:
+    constexpr C(int x) : x(x) {}
+  };
+  void f(std::initializer_list<C>);
+  void g() {
+// CHECK-LABEL: _ZN9ConstExpr1gEv
+// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"]* @.initializer_list9, i64 0, i64 0)
+// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
+    f({C(1), C(2), C(3)});
+  }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to