diff --git a/gen/arrays.cpp b/gen/arrays.cpp index a21b8e43d4..476f79f58d 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -496,16 +496,37 @@ Expression *indexArrayLiteral(ArrayLiteralExp *ale, unsigned idx) { //////////////////////////////////////////////////////////////////////////////// -bool isConstLiteral(ArrayLiteralExp *ale) { - // FIXME: This is overly pessemistic, isConst() always returns 0 e.g. for - // StructLiteralExps. Thus, we waste optimization potential (GitHub #506). - for (size_t i = 0; i < ale->elements->dim; ++i) { - // We have to check specifically for '1', as SymOffExp is classified as - // '2' and the address of a local variable is not an LLVM constant. - if (indexArrayLiteral(ale, i)->isConst() != 1) { - return false; +bool isConstLiteral(Expression *e) { + // We have to check the return value of isConst specifically for '1', + // as SymOffExp is classified as '2' and the address of a local variable is + // not an LLVM constant. + // + // Examine the ArrayLiteralExps and the StructLiteralExps element by element + // as isConst always returns 0 on those. + switch (e->op) { + case TOKarrayliteral: { + auto ale = static_cast(e); + for (auto el : *ale->elements) { + if (!isConstLiteral(el ? el : ale->basis)) + return false; } + } break; + + case TOKstructliteral: { + auto sle = static_cast(e); + if (sle->sd->isNested()) + return false; + for (auto el : *sle->elements) { + if (el && !isConstLiteral(el)) + return false; + } + } break; + + default: + if (e->isConst() != 1) + return false; } + return true; } diff --git a/gen/arrays.h b/gen/arrays.h index ef89fb52d6..3aa939b02e 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -42,7 +42,7 @@ LLConstant *DtoConstSlice(LLConstant *dim, LLConstant *ptr, Expression *indexArrayLiteral(ArrayLiteralExp *ale, unsigned idx); /// Returns whether the array literal can be evaluated to a (LLVM) constant. -bool isConstLiteral(ArrayLiteralExp *ale); +bool isConstLiteral(Expression *e); /// Returns the constant for the given array literal expression. llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale); diff --git a/tests/codegen/const_struct.d b/tests/codegen/const_struct.d new file mode 100644 index 0000000000..cf23628b6c --- /dev/null +++ b/tests/codegen/const_struct.d @@ -0,0 +1,27 @@ +// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll +// RUN: %ldc -run %s + +struct S0 { uint x; } +struct S1 { S0 y; this(this) { y.x = 1; } } +struct S2 { S1[3] z; } + +struct C0 { int *x; } + +void testNested() { + int x; + // The 'x' here is accessed via the nested context pointer + struct N1 { ~this() { ++x; } } + struct N0 { N1[3] x; } + { N0 n; } + assert(x == 3); +} + +// CHECK: @.immutablearray = internal constant [1 x { [3 x { { i32 } }] }] [{ [3 x { { i32 } }] } { [3 x { { i32 } }] [{ { i32 } } { { i32 } { i32 42 } }, { { i32 } } { { i32 } { i32 43 } }, { { i32 } } { { i32 } { i32 44 } }] }] ; [#uses = 1] +void main () { + // CHECK: store %const_struct.S2* bitcast ([1 x { [3 x { { i32 } }] }]* @.immutablearray to %const_struct.S2*), %const_struct.S2** %2 + immutable S2[] xyz = [ { [ { { 42 } }, { { 43 } }, { { 44 } } ] } ]; + // CHECK: %.gc_mem = call {{{.*}}} @_d_newarrayU(%object.TypeInfo* bitcast (%"typeid(immutable(C0[]))"* @{{.*}} to %object.TypeInfo*), i{{32|64}} 3) + immutable C0[] zyx = [ { new int(42) }, { null }, { null } ]; + + testNested(); +} diff --git a/tests/codegen/in_place_construct.d b/tests/codegen/in_place_construct.d index e40d1ec8ae..23fb9445e7 100644 --- a/tests/codegen/in_place_construct.d +++ b/tests/codegen/in_place_construct.d @@ -108,16 +108,9 @@ struct Container { S s; } void hierarchyOfLiterals() { // CHECK: %sa = alloca [1 x %in_place_construct.Container] - // CHECK: %1 = getelementptr inbounds {{.*}}[1 x %in_place_construct.Container]* %sa, i32 0, i32 0 - // CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.Container* %1, i32 0, i32 0 - // CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 0 - // CHECK: store i64 11, i64* %3 - // CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 1 - // CHECK: store i64 12, i64* %4 - // CHECK: %5 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 2 - // CHECK: store i64 13, i64* %5 - // CHECK: %6 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 3 - // CHECK: store i64 14, i64* %6 + // CHECK: %1 = bitcast [1 x %in_place_construct.Container]* %sa to [1 x { { i64, i64, i64, i64 } }]* + // CHECK: store [{{.*}}]* %1 + // CHECK: ret void Container[1] sa = [ Container(S(11, 12, 13, 14)) ]; }