forked from OSchip/llvm-project
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:
parent
0bb474fdb2
commit
2bcde3a74c
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;})); }
|
||||
|
|
Loading…
Reference in New Issue