]> granicus.if.org Git - clang/commitdiff
Reapply r231508 "CodeGen: Emit constant temporaries into read-only globals."
authorBenjamin Kramer <benny.kra@googlemail.com>
Sat, 7 Mar 2015 13:37:13 +0000 (13:37 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Sat, 7 Mar 2015 13:37:13 +0000 (13:37 +0000)
I disabled putting the new global into the same COMDAT as the function for now.
There's a fundamental problem when we inline references to the global but still
have the global in a COMDAT linked to the inlined function. Since this is only
an optimization there may be other versions of the COMDAT around that are
missing the new global and hell breaks loose at link time.

I hope the chromium build doesn't break this time :)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@231564 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 78e80a15836615314bc7c00a38386fcc8b4cfcd4..4a382007813d2868f7fdb5cd0b62321e67f21343 100644 (file)
@@ -301,6 +301,23 @@ createReferenceTemporary(CodeGenFunction &CGF,
   switch (M->getStorageDuration()) {
   case SD_FullExpression:
   case SD_Automatic:
+    // If we have a constant temporary array or record try to promote it into a
+    // constant global under the same rules a normal constant would've been
+    // promoted. This is easier on the optimizer and generally emits fewer
+    // instructions.
+    if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
+        (M->getType()->isArrayType() || M->getType()->isRecordType()) &&
+        CGF.CGM.isTypeConstant(M->getType(), true))
+      if (llvm::Constant *Init =
+              CGF.CGM.EmitConstantExpr(Inner, M->getType(), &CGF)) {
+        auto *GV = new llvm::GlobalVariable(
+            CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+            llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
+        GV->setAlignment(
+            CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity());
+        // FIXME: Should we put the new global into a COMDAT?
+        return GV;
+      }
     return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
 
   case SD_Thread:
@@ -370,8 +387,9 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
   // Create and initialize the reference temporary.
   llvm::Value *Object = createReferenceTemporary(*this, M, E);
   if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
-    // If the temporary is a global and has a constant initializer, we may
-    // have already initialized it.
+    // If the temporary is a global and has a constant initializer or is a
+    // constant temporary that we promoted to a global, we may have already
+    // initialized it.
     if (!Var->hasInitializer()) {
       Var->setInitializer(CGM.EmitNullConstant(E->getType()));
       EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
index 2b77d2490aac70e5246a6f5ca526d304311a81da..2bbeefbe934b536ac15ff147cf6d4032b2e07e74 100644 (file)
@@ -28,7 +28,7 @@ int f() {
 
 // 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]* @{{.*}}, [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 49bc86fadc781ce934abf186d7df3d6d693f724c..de10aee67f13edbcdc62cf9eb01b95313b4baaca 100644 (file)
@@ -42,10 +42,11 @@ namespace ValueInitArrayOfMemPtr {
     // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* bitcast ([3 x i32]* @[[THREE_NULL_MEMPTRS]] to i8*), i32 12, i32 4, i1 false)
   }
 
-  // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEv
-  void g() {
+  // Test dynamic initialization.
+  // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEMNS_1SEi
+  void g(p ptr) {
     // CHECK: store i32 -1,
-    f(a{});
+    f(a{ptr});
   }
 }
 
index 23d244bc5674269532349179e88bf9a44cf1cb13..d4a8f20f35730f6717d5bf0461312227735b439e 100644 (file)
@@ -35,22 +35,30 @@ namespace reference {
     // CHECK-NEXT: ret
   }
 
-  void reference_to_aggregate() {
+  void reference_to_aggregate(int i) {
     // CHECK: getelementptr {{.*}}, i32 0, i32 0
     // CHECK-NEXT: store i32 1
     // CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1
-    // CHECK-NEXT: store i32 2
+    // CHECK-NEXT: %[[I1:.*]] = load i32, i32*
+    // CHECK-NEXT: store i32 %[[I1]]
     // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
-    const A &ra1{1, 2};
+    const A &ra1{1, i};
 
     // 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: %[[I2:.*]] = load i32, i32*
+    // CHECK-NEXT: store i32 %[[I2]]
     // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
-    const int (&arrayRef)[] = {1, 2, 3};
+    const int (&arrayRef)[] = {1, 2, i};
+
+    // CHECK: store %{{.*}}* @{{.*}}, %{{.*}}** %{{.*}}, align
+    const A &constra1{1, 2};
+
+    // CHECK-NEXT: store [3 x i32]* @{{.*}}, [3 x i32]** %{{.*}}, align
+    const int (&constarrayRef)[] = {1, 2, 3};
 
     // CHECK-NEXT: ret
   }
index d68ba7c75371007b2d495e580247688bc4af6f73..a341842c3aba682061ba0511820e38f1e8d49805 100644 (file)
@@ -72,6 +72,9 @@ namespace thread_local_global_array {
 // 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: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4
+// CHECK: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
+
 // CHECK: appending global
 
 
@@ -215,17 +218,16 @@ void fn9() {
 
 struct haslist1 {
   std::initializer_list<int> il;
-  haslist1();
+  haslist1(int i);
 };
 
-// CHECK-LABEL: define void @_ZN8haslist1C2Ev
-haslist1::haslist1()
+// CHECK-LABEL: define void @_ZN8haslist1C2Ei
+haslist1::haslist1(int i)
 // CHECK: alloca [3 x i32]
-// CHECK: store i32 1
+// CHECK: store i32 %
 // CHECK: store i32 2
 // CHECK: store i32 3
-// CHECK: store i{{32|64}} 3
-  : il{1, 2, 3}
+  : il{i, 2, 3}
 {
   destroyme2 dm2;
 }
@@ -244,16 +246,15 @@ haslist2::haslist2()
   // CHECK: call void @_ZN10destroyme1D1Ev
 }
 
-void fn10() {
-  // CHECK-LABEL: define void @_Z4fn10v
+void fn10(int i) {
+  // CHECK-LABEL: define void @_Z4fn10i
   // CHECK: alloca [3 x i32]
   // CHECK: call noalias i8* @_Znw{{[jm]}}
-  // CHECK: store i32 1
+  // CHECK: store i32 %
   // CHECK: store i32 2
   // CHECK: store i32 3
   // CHECK: store i32*
-  // CHECK: store i{{32|64}} 3
-  (void) new std::initializer_list<int> {1, 2, 3};
+  (void) new std::initializer_list<int> {i, 2, 3};
 }
 
 void fn11() {
@@ -462,6 +463,22 @@ namespace PR20445 {
   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]* @[[REFTMP1]], 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"]* @[[REFTMP2]], i64 0, i64 0)
+// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
+    f({C(1), C(2), C(3)});
+  }
+}