PR12848: When emitting a local variable declared 'constexpr', always initialize it with a store or a memcpy, not by emitting the initializer expression. This is not required for correctness, but more closely aligns with people's expectations, and is cheap (since we've already evaluated the initializer).

llvm-svn: 183082
This commit is contained in:
Richard Smith 2013-06-02 00:09:52 +00:00
parent 0bb474fdb2
commit 2bcde3a74c
3 changed files with 54 additions and 9 deletions

View File

@ -840,19 +840,19 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
bool NRVO = getLangOpts().ElideConstructors &&
D.isNRVOVariable();
// If this value is a POD array or struct with a statically
// determinable constant initializer, there are optimizations we can do.
// If this value is an array or struct with a statically determinable
// constant initializer, there are optimizations we can do.
//
// TODO: We should constant-evaluate the initializer of any variable,
// as long as it is initialized by a constant expression. Currently,
// isConstantInitializer produces wrong answers for structs with
// reference or bitfield members, and a few other cases, and checking
// for POD-ness protects us from some of these.
if (D.getInit() &&
(Ty->isArrayType() || Ty->isRecordType()) &&
(Ty.isPODType(getContext()) ||
getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)) {
if (D.getInit() && (Ty->isArrayType() || Ty->isRecordType()) &&
(D.isConstexpr() ||
((Ty.isPODType(getContext()) ||
getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)))) {
// If the variable's a const type, and it's neither an NRVO
// candidate nor a __block variable and has no mutable members,
@ -1080,7 +1080,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
llvm::Constant *constant = 0;
if (emission.IsConstantAggregate) {
if (emission.IsConstantAggregate || D.isConstexpr()) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = CGM.EmitConstantInit(D, this);
}
@ -1091,6 +1091,13 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
return EmitExprAsInit(Init, &D, lv, capturedByInit);
}
if (!emission.IsConstantAggregate) {
// For simple scalar/complex initialization, store the value directly.
LValue lv = MakeAddrLValue(Loc, type, alignment);
lv.setNonGC(true);
return EmitStoreThroughLValue(RValue::get(constant), lv, true);
}
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
bool isVolatile = type.isVolatileQualified();

View File

@ -46,7 +46,7 @@ namespace test_complex_int {
void test() {
constexpr _Complex int x = 500;
takeABlock(^{ takeItByValue(x); });
// CHECK: store i32 500,
// CHECK: store { i32, i32 } { i32 500, i32 0 },
// CHECK: store i32 500,
// CHECK-NEXT: store i32 0,

View File

@ -330,6 +330,10 @@ namespace PR13273 {
extern const S s {};
}
// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102
// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103
// Constant initialization tests go before this point,
// dynamic initialization tests go after.
@ -356,6 +360,40 @@ namespace PR13273 {
// CHECK-NOT: }
// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev
// PR12848: Don't emit dynamic initializers for local constexpr variables.
namespace LocalVarInit {
constexpr int f(int n) { return n; }
struct Agg { int k; };
struct Ctor { constexpr Ctor(int n) : k(n) {} int k; };
struct Mutable { constexpr Mutable(int n) : k(n) {} mutable int k; };
// CHECK: define {{.*}} @_ZN12LocalVarInit6scalarEv
// CHECK-NOT: call
// CHECK: store i32 100,
// CHECK-NOT: call
// CHECK: ret i32 100
int scalar() { constexpr int a = { f(100) }; return a; }
// CHECK: define {{.*}} @_ZN12LocalVarInit3aggEv
// CHECK-NOT: call
// CHECK: ret i32 101
int agg() { constexpr Agg a = { f(101) }; return a.k; }
// CHECK: define {{.*}} @_ZN12LocalVarInit4ctorEv
// CHECK-NOT: call
// CHECK: ret i32 102
int ctor() { constexpr Ctor a = { f(102) }; return a.k; }
// CHECK: define {{.*}} @_ZN12LocalVarInit8mutable_Ev
// CHECK-NOT: call
// CHECK: call {{.*}}memcpy{{.*}} @_ZZN12LocalVarInit8mutable_EvE1a
// CHECK-NOT: call
// Can't fold return value due to 'mutable'.
// CHECK-NOT: ret i32 103
// CHECK: }
int mutable_() { constexpr Mutable a = { f(103) }; return a.k; }
}
namespace CrossFuncLabelDiff {
// Make sure we refuse to constant-fold the variable b.
constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }