mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 17:11:44 +03:00

There's no <Type>_init type for aggregates (structs and classes) anymore, effectively eliminating a *lot* of named LLVM types, some bitcasts as well as replacements of globals etc. To get there, it was even required to use the regular type for compatible literals too, otherwise structs embedded as fields in other aggregates had an anonymous type (well, the LLVM constant for the field initializer had) and so the container initializer wasn't compatible with the regular type anymore. What was also necessary was a fix wrt. static arrays of bools (LLVM constant of type `[N x i1]` vs. `[N x i8]` for regular type). I also had to change the initializer for `char[2][3] x = 0xff` from `[6 x i8]` to `[3 x [2 x i8]]`, i.e., NOT flattening multi-dimensional inits from a scalar. So only literals with overlapping (union) fields and an explicit initializer initializing dominated non-alias union fields should still have a mismatching anonymous type - i.e., very, very few cases.
121 lines
4.5 KiB
D
121 lines
4.5 KiB
D
// Tests in-place construction of variables.
|
|
|
|
// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
|
|
|
|
// 256 bits, returned via sret:
|
|
struct S
|
|
{
|
|
long a, b, c, d;
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S
|
|
S returnLiteral()
|
|
{
|
|
// make sure the literal is emitted directly into the sret pointee
|
|
// CHECK: %1 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 0
|
|
// CHECK: store i64 1, i64* %1
|
|
// CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 1
|
|
// CHECK: store i64 2, i64* %2
|
|
// CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 2
|
|
// CHECK: store i64 3, i64* %3
|
|
// CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 3
|
|
// CHECK: store i64 4, i64* %4
|
|
return S(1, 2, 3, 4);
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct12returnRValueFZS18in_place_construct1S
|
|
S returnRValue()
|
|
{
|
|
// make sure the sret pointer is forwarded
|
|
// CHECK: call {{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S
|
|
// CHECK-SAME: %in_place_construct.S* {{.*}} %.sret_arg
|
|
return returnLiteral();
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct10returnNRVOFZS18in_place_construct1S
|
|
S returnNRVO()
|
|
{
|
|
// make sure NRVO zero-initializes the sret pointee directly
|
|
// CHECK: %1 = bitcast %in_place_construct.S* %.sret_arg to i8*
|
|
// CHECK: call void @llvm.memset.{{.*}}(i8* %1, i8 0,
|
|
const S r;
|
|
return r;
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct15withOutContractFZS18in_place_construct1S
|
|
S withOutContract()
|
|
out { assert(__result.a == 0); }
|
|
body
|
|
{
|
|
// make sure NRVO zero-initializes the sret pointee directly
|
|
// CHECK: %1 = bitcast %in_place_construct.S* %.sret_arg to i8*
|
|
// CHECK: call void @llvm.memset.{{.*}}(i8* %1, i8 0,
|
|
const S r;
|
|
return r;
|
|
|
|
// make sure `__result` inside the out contract is just an alias to the sret pointee
|
|
// CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 0
|
|
// CHECK: %3 = load {{.*}}i64* %2
|
|
// CHECK: %4 = icmp eq i64 %3, 0
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct7structsFZv
|
|
void structs()
|
|
{
|
|
// CHECK: %literal = alloca %in_place_construct.S
|
|
// CHECK: %a = alloca %in_place_construct.S
|
|
// CHECK: %b = alloca %in_place_construct.S
|
|
// CHECK: %c = alloca %in_place_construct.S
|
|
|
|
// make sure the literal is emitted directly into the lvalue
|
|
// CHECK: %1 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 0
|
|
// CHECK: store i64 5, i64* %1
|
|
// CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 1
|
|
// CHECK: store i64 6, i64* %2
|
|
// CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 2
|
|
// CHECK: store i64 7, i64* %3
|
|
// CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 3
|
|
// CHECK: store i64 8, i64* %4
|
|
const literal = S(5, 6, 7, 8);
|
|
|
|
// make sure the variables are in-place constructed via sret
|
|
// CHECK: call {{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S
|
|
// CHECK-SAME: %in_place_construct.S* {{.*}} %a
|
|
const a = returnLiteral();
|
|
// CHECK: call {{.*}}_D18in_place_construct12returnRValueFZS18in_place_construct1S
|
|
// CHECK-SAME: %in_place_construct.S* {{.*}} %b
|
|
const b = returnRValue();
|
|
// CHECK: call {{.*}}_D18in_place_construct10returnNRVOFZS18in_place_construct1S
|
|
// CHECK-SAME: %in_place_construct.S* {{.*}} %c
|
|
const c = returnNRVO();
|
|
|
|
withOutContract();
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct12staticArraysFZv
|
|
void staticArrays()
|
|
{
|
|
// CHECK: %sa = alloca [2 x i32]
|
|
|
|
// make sure static array literals are in-place constructed too
|
|
// CHECK: store [2 x i32] [i32 1, i32 2], [2 x i32]* %sa
|
|
const(int[2]) sa = [ 1, 2 ];
|
|
}
|
|
|
|
struct Container { S s; }
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct19hierarchyOfLiteralsFZv
|
|
void hierarchyOfLiterals()
|
|
{
|
|
// CHECK: %sa = alloca [1 x %in_place_construct.Container]
|
|
// CHECK: store [1 x %in_place_construct.Container] [%in_place_construct.Container { %in_place_construct.S { i64 11, i64 12, i64 13, i64 14 } }], [1 x %in_place_construct.Container]* %sa
|
|
Container[1] sa = [ Container(S(11, 12, 13, 14)) ];
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} @{{.*}}_Dmain
|
|
void main()
|
|
{
|
|
structs();
|
|
staticArrays();
|
|
hierarchyOfLiterals();
|
|
}
|