r183082 - 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).

Richard Smith richard-llvm at metafoo.co.uk
Sat Jun 1 17:09:52 PDT 2013


Author: rsmith
Date: Sat Jun  1 19:09:52 2013
New Revision: 183082

URL: http://llvm.org/viewvc/llvm-project?rev=183082&view=rev
Log:
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).

Modified:
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp
    cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=183082&r1=183081&r2=183082&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sat Jun  1 19:09:52 2013
@@ -840,19 +840,19 @@ CodeGenFunction::EmitAutoVarAlloca(const
     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(co
     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(co
     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();

Modified: cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp?rev=183082&r1=183081&r2=183082&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp Sat Jun  1 19:09:52 2013
@@ -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,

Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=183082&r1=183081&r2=183082&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Sat Jun  1 19:09:52 2013
@@ -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;})); }





More information about the cfe-commits mailing list