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:
// 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);
// 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]]
// 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});
}
}
// 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
}
// 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
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;
}
// 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() {
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)});
+ }
+}