From 2bcde3a74c5e4dccb70ccbeec9da7fb785130f66 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 2 Jun 2013 00:09:52 +0000 Subject: [PATCH] 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 --- clang/lib/CodeGen/CGDecl.cpp | 23 ++++++++----- clang/test/CodeGenCXX/blocks-cxx11.cpp | 2 +- clang/test/CodeGenCXX/const-init-cxx11.cpp | 38 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 9741f5878e0c..4b19b54df587 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -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(); diff --git a/clang/test/CodeGenCXX/blocks-cxx11.cpp b/clang/test/CodeGenCXX/blocks-cxx11.cpp index 3f0380abbd37..42d33ae8564e 100644 --- a/clang/test/CodeGenCXX/blocks-cxx11.cpp +++ b/clang/test/CodeGenCXX/blocks-cxx11.cpp @@ -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, diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp b/clang/test/CodeGenCXX/const-init-cxx11.cpp index 833adba8bae7..9e5b5ef091cf 100644 --- a/clang/test/CodeGenCXX/const-init-cxx11.cpp +++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp @@ -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;})); }