Optimized and improved aggregate initialization. Compound literal updated to Foo({ 1, 2 })-style. ".name = x" style initialization for named arguments and designated initializers. Added runtime messages on panics. subarrays convert implictly to pointers. len/len() functions. Fix taking slice of pointer. Vararg fixes

Consistent length typedef.

First stab at initializers.

Change compound literal to Foo({ 1, 2 }) style.

Fixed up some tests.

Optimize the zero struct codegen.

Optimize union empty initializer.

Fix issues with unions. Added alignment to globals. Added some union tests.

Use puts to emit error messages during runtime. Fixup of int[] -> int* style conversions.

Fix implicit conversion of int[3]* -> int*

Fix int[] size. Use () to invoke the length of a subarray. Fix taking a slice of a pointer. Limit the number of members in a struct.

Fixes to vararg using debug and cleanups to slices.
This commit is contained in:
Christoffer Lerno
2020-12-09 00:41:23 +01:00
parent 6a5a0f2b94
commit 4da36dfed9
44 changed files with 1854 additions and 650 deletions

View File

@@ -5,12 +5,14 @@ struct Test
int x;
}
Test foo = {};
extern func void blorg(Test t);
func Test creator()
{
blorg(Test {} );
return Test {};
blorg(Test({}));
return Test({});
}
// #expect: literal_load.ll

View File

@@ -0,0 +1,25 @@
module test;
func void test()
{
int[3] x;
int *y = &x;
int[] z = &x;
}
// #expect: array_casts.ll
%"int[]" = type { i32*, i64 }
%x = alloca [3 x i32], align 4
%y = alloca i32*, align 8
%z = alloca %"int[]", align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 12, i1 false)
%ptrptr = bitcast [3 x i32]* %x to i32*
store i32* %ptrptr, i32** %y, align 8
%1 = bitcast [3 x i32]* %x to i32*
%2 = insertvalue %"int[]" undef, i32* %1, 0
%3 = insertvalue %"int[]" %2, i64 3, 1
store %"int[]" %3, %"int[]"* %z, align 8

View File

@@ -0,0 +1,12 @@
func void test()
{
int[3] x;
double *y = &x; // #error: Cannot implicitly cast 'int[3]*' to 'double*
}
func void test2()
{
int[3] x;
double[] z = &x; // #error: Cannot cast 'int[3]*' to 'double[]'
}

View File

@@ -29,11 +29,12 @@ struct ExtraSimple
func void testSimple()
{
ExtraSimple a = { c.j = 3.3 };
ExtraSimple a = { .c.j = 3.3 };
a.c.j = 3.4;
printf("a = %d, c.e = %f, c.f = %f, c.j = %f, g = %d, o0 = %f, r = %d, s = %d\n", a.a, a.c.e, a.c.f, a.c.j, a.g, a.o0, a.r, a.s);
}
// TODO these may be wrong.
// #expect: pointer_access.ll
%pointer_access.ExtraSimple = type { i32, i32, %pointer_access.c, %pointer_access.anon, %pointer_access.anon.0, i32 }
@@ -45,39 +46,32 @@ func void testSimple()
entry:
%a = alloca %pointer_access.ExtraSimple, align 8
%literal = alloca %pointer_access.ExtraSimple, align 8
%0 = bitcast %pointer_access.ExtraSimple* %literal to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 72, i1 false)
%c = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %literal, i32 0, i32 2
%double = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c, i32 0, i32 4
store double 3.300000e+00, double* %double
%1 = bitcast %pointer_access.ExtraSimple* %a to i8*
%2 = bitcast %pointer_access.ExtraSimple* %literal to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 72, i1 false)
%c1 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%j = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c1, i32 0, i32 4
%0 = bitcast %pointer_access.ExtraSimple* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast (%pointer_access.ExtraSimple* @0 to i8*), i32 72, i1 false)
%c = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%j = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c, i32 0, i32 4
store double 3.400000e+00, double* %j, align 8
%a2 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0
%3 = load i32, i32* %a2, align 4
%a1 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0
%1 = load i32, i32* %a1, align 4
%c2 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%e = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c2, i32 0, i32 0
%2 = load double, double* %e, align 8
%c3 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%e = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c3, i32 0, i32 0
%4 = load double, double* %e, align 8
%f = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c3, i32 0, i32 3
%3 = load double, double* %f, align 8
%c4 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%f = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c4, i32 0, i32 3
%5 = load double, double* %f, align 8
%c5 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
%j6 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c5, i32 0, i32 4
%6 = load double, double* %j6, align 8
%j5 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %c4, i32 0, i32 4
%4 = load double, double* %j5, align 8
%g = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 5
%7 = load i32, i32* %g, align 4
%5 = load i32, i32* %g, align 4
%anon = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 4
%o0 = bitcast %pointer_access.anon.0* %anon to double*
%8 = load double, double* %o0, align 8
%6 = load double, double* %o0, align 8
%anon6 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
%r = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %anon6, i32 0, i32 0
%7 = load i32, i32* %r, align 4
%anon7 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
%r = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %anon7, i32 0, i32 0
%9 = load i32, i32* %r, align 4
%anon8 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
%s = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %anon8, i32 0, i32 1
%10 = load i32, i32* %s, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @0, i32 0, i32 0), i32 %3, double %4, double %5, double %6, i32 %7, double %8, i32 %9, i32 %10)
%s = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %anon7, i32 0, i32 1
%8 = load i32, i32* %s, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @1, i32 0, i32 0), i32 %1, double %2, double %3, double %4, i32 %5, double %6, i32 %7, i32 %8)
ret void

View File

@@ -0,0 +1,38 @@
module test;
extern func void printf(char* c, ...);
func void test()
{
printf("%d\n", true);
printf("%d\n", 123);
printf("%f\n", 12.3);
char x1 = -123;
bool b = false;
float z1 = 12.3;
printf("%d\n", b);
printf("%d\n", x1);
printf("%f\n", z1);
}
// #expect: varargs.ll
%x1 = alloca i8, align 1
%b = alloca i8, align 1
%z1 = alloca float, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 1)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0), i32 123)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @2, i32 0, i32 0), double 1.230000e+01)
store i8 -123, i8* %x1, align 1
store i8 0, i8* %b, align 1
store float 0x40289999A0000000, float* %z1, align 4
%0 = load i8, i8* %b, align 1
%1 = trunc i8 %0 to i1
%boolsi = zext i1 %1 to i32
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @3, i32 0, i32 0), i32 %boolsi)
%2 = load i8, i8* %x1, align 1
%sisiext = sext i8 %2 to i32
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @4, i32 0, i32 0), i32 %sisiext)
%3 = load float, float* %z1, align 4
%fpfpext = fpext float %3 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0), double %fpfpext)

View File

@@ -50,7 +50,7 @@ func void tester()
p.uu.e = 8;
Point *p2 = &p;
p2.bb.b = 3;
p = { a = 1, bb.b = 3, e = 2 };
p = { .a = 1, .bb.b = 3, .e = 2 };
Point* pp = &p;
pp.a = 20;
@@ -82,6 +82,6 @@ struct Struct
func void myfunc()
{
Struct s;
s.b = 10; // #error: There is no element or method 'Struct.b'
s.b = 10; // #error: There is no field or method 'Struct.b'
}

View File

@@ -20,5 +20,5 @@ func void test1()
entry:
%p = alloca %test.Point, align 4
%0 = bitcast %test.Point* %p to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%test.Point* @0 to i8*), i32 8, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 8 bitcast (%test.Point* @0 to i8*), i32 8, i1 false)

View File

@@ -0,0 +1,39 @@
struct StructA
{
int a;
}
struct StructB
{
struct b
{
int a;
}
}
func void test()
{
StructA a = {};
StructA a2;
StructB b = {};
StructB b2;
StructB b3 = { .b = { } };
}
// #expect: struct_codegen_empty.ll
%a = alloca %struct_codegen_empty.StructA, align 4
%a2 = alloca %struct_codegen_empty.StructA, align 4
%b = alloca %struct_codegen_empty.StructB, align 4
%b2 = alloca %struct_codegen_empty.StructB, align 4
%b3 = alloca %struct_codegen_empty.StructB, align 4
%0 = bitcast %struct_codegen_empty.StructA* %a to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
%1 = bitcast %struct_codegen_empty.StructA* %a2 to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false)
%2 = bitcast %struct_codegen_empty.StructB* %b to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false)
%3 = bitcast %struct_codegen_empty.StructB* %b2 to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false)
%4 = bitcast %struct_codegen_empty.StructB* %b3 to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %4, i8 0, i64 4, i1 false)

View File

@@ -22,7 +22,7 @@ func void test3()
func void test4()
{
int[3] x = { 1, 2, 3 };
int[] z = x[..^0];
int[] z = x[..^1];
z = x[..^-1]; // #error: Negative numbers are not allowed when indexing from the end.
}
@@ -63,4 +63,10 @@ func void test10()
int[] w = x[0..]; // #error: Omitting end index is not allowed for pointers.
int[] z = x[^2..]; // #error: Indexing from the end is not allowed for pointers.
int[] y = x[..^2]; // #error: Indexing from the end is not allowed for pointers.
}
}
func void test11()
{
int[3] x = { 1, 2, 3 };
int[] z = x[..^0]; // #error: Array end index out of bounds, was 3, exceeding array length 3
}

View File

@@ -13,5 +13,5 @@ func void test()
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 1
%2 = insertvalue %"int[]" undef, i32* %offset, 0
%3 = insertvalue %"int[]" %2, i64 1, 1
%3 = insertvalue %"int[]" %2, i64 2, 1
store %"int[]" %3, %"int[]"* %y, align 8

View File

@@ -14,6 +14,6 @@ func void test()
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 1
%2 = insertvalue %"int[]" undef, i32* %offset, 0
%3 = insertvalue %"int[]" %2, i64 1, 1
%3 = insertvalue %"int[]" %2, i64 2, 1
store %"int[]" %3, %"int[]"* %y, align 8

View File

@@ -1,7 +1,7 @@
func void test()
{
int[3] x = { 1, 2, 3 };
int[] y = x[^2..2];
int[] y = x[^2..1];
}
// #expect: slice_offset_neg_start.ll

View File

@@ -2,9 +2,9 @@ func void test()
{
int[6] feok2 = { 1, 8, 100, 293, 23982, 34};
int[] feok = &feok2;
int[] flok = feok2[3..6];
int[] flok = feok2[3..5];
int[] flak = flok[1..2];
flok = feok2[..6];
flok = feok2[..5];
flok = feok2[..^2];
flok = feok2[..];
flok = feok2[^3..];

View File

@@ -0,0 +1,20 @@
module test;
union Foo
{
int a;
double b;
}
Foo f = { .a = 23 };
Foo g = { .b = 2.3 };
Foo h = { .a = 23, .b = 2.3 };
Foo i = { .b = 2.3, .a = 23 };
// #expect: union_codegen_const.ll
@f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8
@g = protected global %test.Foo { double 2.300000e+00 }, align 8
@h = protected global %test.Foo { double 2.300000e+00 }, align 8
@i = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8

View File

@@ -0,0 +1,45 @@
union UnionA
{
int a;
}
union UnionB
{
struct b
{
int a;
}
int c;
double d;
}
func void test()
{
UnionA a = {};
UnionA a2;
UnionB b = {};
UnionB b2;
UnionB b3 = { .b = {} };
UnionB b4 = { .b.a = 23, .c = 4, .d = 0.4, .b = {} };
}
// #expect: union_codegen_empty.ll
%a = alloca %union_codegen_empty.UnionA, align 4
%a2 = alloca %union_codegen_empty.UnionA, align 4
%b = alloca %union_codegen_empty.UnionB, align 8
%b2 = alloca %union_codegen_empty.UnionB, align 8
%b3 = alloca %union_codegen_empty.UnionB, align 8
%b4 = alloca %union_codegen_empty.UnionB, align 8
%0 = bitcast %union_codegen_empty.UnionA* %a to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
%1 = bitcast %union_codegen_empty.UnionA* %a2 to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false)
%2 = bitcast %union_codegen_empty.UnionB* %b to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
%3 = bitcast %union_codegen_empty.UnionB* %b2 to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
%4 = bitcast %union_codegen_empty.UnionB* %b3 to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 8, i1 false)
%5 = bitcast %union_codegen_empty.UnionB* %b4 to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 8, i1 false)

View File

@@ -0,0 +1,30 @@
module test;
union UnionB
{
struct b
{
int a;
}
int c;
double d;
}
extern func int bar();
func void test()
{
UnionB b = { .c = bar(), .b = {} };
}
// #expect: union_codegen_overwrite_call.ll
entry:
%b = alloca %test.UnionB, align 8
%1 = bitcast %test.UnionB* %b to i32*
%2 = call i32 @bar()
store i32 %2, i32* %1, align 4
%3 = bitcast %test.UnionB* %b to %test.b*
%4 = bitcast %test.b* %3 to i8*
call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 4, i1 false)
ret void