Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -301,6 +301,23 @@ 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, ".reftmp"); + GV->setAlignment( + CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity()); + GV->setComdat(CGF.CurFn->getComdat()); + return GV; + } return CGF.CreateMemTemp(Inner->getType(), "ref.tmp"); case SD_Thread: @@ -370,8 +387,9 @@ // Create and initialize the reference temporary. llvm::Value *Object = createReferenceTemporary(*this, M, E); if (auto *Var = dyn_cast(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: 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]* @.reftmp, [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) @.reftmp) f(a{}); } } Index: test/CodeGenCXX/cxx0x-initializer-references.cpp =================================================================== --- test/CodeGenCXX/cxx0x-initializer-references.cpp +++ test/CodeGenCXX/cxx0x-initializer-references.cpp @@ -36,20 +36,10 @@ } void reference_to_aggregate() { - // 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: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align + // CHECK: store %"struct.reference::A"* @.reftmp, %"struct.reference::A"** %{{.*}}, 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]* @.reftmp1, [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,6 +64,9 @@ // CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer // CHECK: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer +// CHECK: @.reftmp = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +// CHECK: @.reftmp2 = 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 @@ -72,6 +75,9 @@ // 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: @.reftmp8 = private constant [2 x i32] [i32 42, i32 43], comdat($_ZN7PR204451fILi0EEEvv), align 4 +// CHECK: @.reftmp9 = 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]* @.reftmp, 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]* @.reftmp2, i64 0, i64 0) // CHECK: store i{{32|64}} 3 (void) new std::initializer_list {1, 2, 3}; } @@ -462,6 +462,22 @@ template void f() { new MyClass({42, 43}); } template void f<0>(); // CHECK-LABEL: define {{.*}} @_ZN7PR204451fILi0EEEvv( + // CHECK: store i32* getelementptr inbounds ([2 x i32]* @.reftmp8, 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); + void g() { +// CHECK-LABEL: _ZN9ConstExpr1gEv +// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"]* @.reftmp9, i64 0, i64 0) +// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE + f({C(1), C(2), C(3)}); + } +}