Lots of fixes and optimizations to structs. Now there are no unnecessary intermediary types.

This commit is contained in:
Christoffer Lerno
2020-04-16 17:52:48 +02:00
committed by Christoffer Lerno
parent ff31bd17c0
commit 6117a1be7c
17 changed files with 1298 additions and 113 deletions

View File

@@ -79,14 +79,14 @@ add_executable(c3c
src/utils/stringutils.c
src/compiler/dwarf.h
src/compiler/llvm_codegen_stmt.c
src/compiler/llvm_codegen_internal.h
src/compiler/llvm_codegen_expr.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_module.c
src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_function.c
src/build/builder.c
src/utils/toml.c src/build/project.c src/build/build_internal.h src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c src/compiler/number.c)
src/utils/toml.c src/build/project.c
src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c src/compiler/number.c)
target_compile_options(c3c PRIVATE -Wimplicit-int -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)

View File

@@ -64,7 +64,7 @@ enum EnumTestOverflowAfter
/*
error Error
{
BLURB,
@@ -75,7 +75,7 @@ error OtherError
{
FOO_BAR
}
*/
enum Inf
{
A,
@@ -119,6 +119,8 @@ union SimpleUnion
func void testUnion()
{
int wdw = 123;
wdw = 222;
SimpleUnion s;
s.a = 1;
s.f = 1.0;
@@ -143,7 +145,7 @@ func TestStruct2 structTest(int i)
func void enumInferenceTest()
{
OtherError e = OtherError.FOO_BAR;
// OtherError e = OtherError.FOO_BAR;
Inf x = Inf.A;
x = BooInf.B;
x = A;
@@ -175,10 +177,11 @@ func int jumptest()
LABELX:
return 2;
}
/*
func int borok() throws
{
return 1;
}
}*/
func void testNoReturn()
{
int i = 0;
@@ -198,13 +201,13 @@ func int testReturnWithOtherAtEnd()
if (i == 10) i++;
i = i + 2;
}
/*
func int testReturnWithError() throws Error
{
int i = 0;
throw Error.NO_SUCH_FILE;
i = i + 1;
}
}*/
func int testReturnWithConditional()
{
@@ -218,7 +221,7 @@ func int testReturnWithConditional()
return 2;
}
}
/*
func int testReturnWithCondThrow() throws Error
{
int i = 0;
@@ -231,7 +234,7 @@ func int testReturnWithCondThrow() throws Error
throw Error.NO_SUCH_FILE;
}
}
*/
func int testReturnSwitch()
{
int i = 0;
@@ -246,6 +249,7 @@ func int testReturnSwitch()
}
}
/*
func int barok() throws Error, OtherError
{
if (true)
@@ -254,7 +258,7 @@ func int barok() throws Error, OtherError
}
return 100;
}
*/
struct SimpleStruct
{
@@ -302,24 +306,19 @@ struct AnonStruct
int x;
}
func AnonStruct sendAnonStruct()
{
AnonStruct foo = Foo { a = 1 };
foo.b2 = 123;
return foo;
}
func void testAnonStruct2()
{
AnonStruct s = { b2 = 3, b1 = 7, xx.b = 1 };
AnonStruct foo;
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
s.xx.b = 100;
s.xx.c = 99;
s.b1 = 3;
s.b2 = 5;
s.c2 = 7;
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
sendAnonStruct();
}
func void testAnonStruct()
{
AnonStruct s = { b2 = 3, b1 = 7, xx.b = 1 };
@@ -346,6 +345,10 @@ func void testAnonStruct()
printf("a = %d, b = %d, c = %d (2), b1 = %d, c1 = %d, b2 = %d, c2 = %d, x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
s = sendAnonStruct();
printf("Got it sent: a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
}
func int boba(int y, int j)
{
@@ -587,6 +590,25 @@ struct WithArray
{
int[4] x;
}
/*
error Err
{
TEST_ERR1
}
*/
/*
func int testThrow(int x) throws Err
{
if (x < 0) throw Err.TEST_ERR1;
return x * x;
}
*/
func void testErrors()
{
//int x = try testThrow(20) else 0;
int x = 0;
printf("Value was %d, expected 400.\n", x);
}
func void testArray()
{
@@ -648,6 +670,7 @@ JUMP:
func int main(int x)
{
printf("Helo!\n");
testErrors();
testDefault(y = 99);
testPointers(2, 3);
testDefer();

View File

@@ -0,0 +1,839 @@
module bar;
typedef int as Bob;
struct Test
{
int a;
}
struct Test2
{
Test t;
int b;
}
union Test3
{
long eo;
Test t;
int b;
}
struct Teob
{
int x;
double y;
int xy;
int oekfeo;
}
enum EnumWithData : ushort (int a, char[] x, long b = 4)
{
// Currently the args are ignored TODO!
TEST1(42, "hello", 328) = 3,
TEST2(12, "world")
}
/*
enum EnumTestNoOverflowAfterULong : ulong
{
VALUE = 0xFFFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFF,
VALUE_EXCEED
}
enum EnumTestOverflowAfterULong : ulong
{
VALUE = 0xFFFF_FFFF_FFFF_FFFF,
VALUE_EXCEED
}
enum EnumTestOverflowAfter
{
VALUE = 0x80000000 - 1,
VALUE_EXCEED
}*/
/*
error Error
{
BLURB,
NO_SUCH_FILE,
}
error OtherError
{
FOO_BAR
}
*/
enum Inf
{
A,
B,
C = 10000
}
enum Inf2 : byte
{
A,
B,
C = 129,
}
typedef Inf as BooInf;
struct TestStruct
{
int a;
}
struct TestStruct2
{
TestStruct a;
char xx;
TestStruct b;
int c;
}
union TestUnion
{
int a;
double f;
TestStruct2 e;
}
union SimpleUnion
{
int a;
double f;
}
func void testUnion()
{
SimpleUnion s;
s.a = 1;
s.f = 1.0;
s = { 1 };
int x = 2;
s = { (x = 2) };
s = { f = 1.0 };
TestUnion tu = { e = TestStruct2 { c = 1 } };
tu.e = TestStruct2 { c = 1 };
}
func TestStruct2 structTest(int i)
{
TestStruct foo = { i };
TestStruct foo2 = { a = i };
TestStruct foo3 = TestStruct { i };
TestStruct2 bar = { c = 2 };
int x = 3 * i;
TestStruct2 bar2 = { b.a = x, a.a = x + 1 };
return bar2;
}
func void enumInferenceTest()
{
// OtherError e = OtherError.FOO_BAR;
Inf x = Inf.A;
x = BooInf.B;
x = A;
int x1 = 0;
bool y = x1 == x1;
Inf2 z = C;
if (z == Inf2.A) return;
if (z == 1) return;
z = 2;
switch (z)
{
case Inf2.A:
x1++;
return;
case B:
return;
case 111:
x1 += 1;
return;
default:
return;
}
}
func int jumptest()
{
if (1) goto LABELX;
return 1;
LABELX:
return 2;
}
/*
func int borok() throws
{
return 1;
}*/
func void testNoReturn()
{
int i = 0;
i = -i;
}
func int testReturn()
{
int i = 0;
return i;
}
func int testReturnWithOtherAtEnd()
{
int i = 0;
return i;
if (i == 10) i++;
i = i + 2;
}
/*
func int testReturnWithError() throws Error
{
int i = 0;
throw Error.NO_SUCH_FILE;
i = i + 1;
}*/
func int testReturnWithConditional()
{
int i = 0;
if (i > 0)
{
return 1;
}
else
{
return 2;
}
}
/*
func int testReturnWithCondThrow() throws Error
{
int i = 0;
if (i > 0)
{
throw Error.NO_SUCH_FILE;
}
else
{
throw Error.NO_SUCH_FILE;
}
}
*/
func int testReturnSwitch()
{
int i = 0;
switch (i)
{
case 1:
return 2;
case 2:
return 3;
default:
return 4;
}
}
/*
func int barok() throws Error, OtherError
{
if (true)
{
throw Error.NO_SUCH_FILE;
}
return 100;
}
*/
struct SimpleStruct
{
int a;
int b;
double c;
double d;
char z1;
char z2;
}
func void testSimpleStruct(int x)
{
SimpleStruct snoinit;
SimpleStruct sinit = { b = 1, d = 3.0, z1 = 1 };
sinit.a = 1;
sinit.b = 2;
printf("a = %d, b = %d (1), c = %f, d = %f (3.0), z1 = %d (1), z2 = %d\n", sinit.a, sinit.b, sinit.c, sinit.d, cast(sinit.z1, int), cast(sinit.z2, int));
snoinit.b = 1;
snoinit.a = 100;
snoinit.d = 3.0;
snoinit.c = 2.0;
snoinit.z1 = 1;
snoinit.z2 = 2;
printf("b = %d (1), d = %f (3.0), z1 = %d (1)\n", snoinit.b, snoinit.d, snoinit.z1);
}
struct AnonStruct
{
int a;
struct xx
{
int b;
int c;
}
struct
{
int b1;
int c1;
}
union
{
int b2;
int c2;
}
int x;
}
func AnonStruct sendAnonStruct()
{
AnonStruct foo = { };
foo.b2 = 123;
return foo;
}
func void testAnonStruct2()
{
sendAnonStruct();
}
func void testAnonStruct()
{
AnonStruct s = { b2 = 3, b1 = 7, xx.b = 1 };
AnonStruct foo;
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
s.xx.b = 100;
s.xx.c = 99;
s.b1 = 3;
s.b2 = 5;
s.c2 = 7;
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
s = { xx = { c = 2 }};
printf("a = %d, b = %d, c = %d (2), b1 = %d, c1 = %d, b2 = %d, c2 = %d, x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
s.xx.c = 3;
s.x = 1212;
s.a = 29183;
s = AnonStruct { xx = { c = 2 }};
printf("a = %d, b = %d, c = %d (2), b1 = %d, c1 = %d, b2 = %d, c2 = %d, x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
// s = sendAnonStruct();
printf("Got it sent: a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
}
func int boba(int y, int j)
{
// hello();
//$e = type(Teob);
//Teob xbd = type(Teob);
//Teob xb = { 1, 1.0, 100, 1000 };
//Test2 tee = { { 3 }, 4 };
//Test3 xc = { eo = 1, t.a = 1 };
// throw Error.NO_SUCH_FILE;
for (int i = 0; i < 10; i++)
{
}
for (int i = 0, int foo = 0; i < 10; i++)
{
}
for (int i = 0, j = 1; i < 10; i++, j++)
{
}
Test2 bar;
bar.b = 1;
//int w = y ? y : j;
int x = y * 2;
int z = j;
while (j > 10)
{
z--;
x = x + z * 2;
}
return x;
}
func int test(int x = 100)
{
x = x + 1;
x = x +% 1;
x += 1;
x +%= 1;
Test3 foekf;
Test oef;
Test2 foek;
int i = x;
Bob foo = x;
Bob fe = 0;
fe++;
switch (fe + 1)
{
case 1:
i = i + 1;
next;
case 3:
case 2:
i = i + 2;
case 5:
default:
i = i * 100;
case 7:
}
i++;
int y = i--;
return y;
}
func int* elvis(int *x, int *y)
{
return x ?: y;
}
func int test3()
{
if (test() < 0) return -1;
return 5;
}
typedef func void() as FEok;
typedef func void(int) as Foo;
//typedef int as Foo;
extern func void printf(char *hello, ...);
macro hello()
{
printf("Hello world!\n");
}
func void bob()
{
byte a = 2;
short b = 3;
int c = 4;
bool eok = true;
long deee = (eok ? a : b) + c;
}
func int if_test(int x)
{
switch (x)
{
case 1:
x += 1;
if (x < 10)
{
defer x += 5;
if (x < 7)
{
defer x += 100;
next;
}
x += 99;
}
next;
default:
x += 2;
break;
}
return 1;
}
func int yyyy(int x)
{
defer printf("A");
if (x > 0) return 2;
defer printf("B");
printf("C");
return 1;
}
func void zzzz()
{
int x = 0;
defer
{
x += 1;
printf("A");
}
defer
{
x += 2;
printf("B");
}
printf("C");
x += 3;
}
func int jumpback(int x)
{
{
defer x += 1;
{
defer x += 2;
LABELX:
x += 3;
}
}
if (x < 100) goto LABELX;
return x + 1;
}
func void test_expr_block(int x)
{
int a = ({
if (x > 0) return x * 2;
if (x == 0) return 100;
return -x;
});
//printf("The result was %d\n", a);
}
func int expr_block()
{
int fok = ({ return ({ return 10; }); });
int y = 2;
int x = ({
if (y < 10) return 10;
return 2;
});
/* ({
return 3;
});*/
return x;
}
func int xxxx(int x)
{
{
x += 10;
defer printf("XXX");
if (x < 100) goto LABELD;
defer printf("EODfe");
}
{
defer printf("Defer says hello!\n");
LABELD:
x--;
}
if (x > 0) goto LABELD;
return 1;
}
func int testPointers(int x, int j = 0, double foo = 3.2)
{
1 ? 1 : 2;
int y = 0;
int* z = &y;
int d = *(z + y);
isize e = z - &y;
int* eff = &y + 1;
short x1 = 2;
float f = x1 +% x1 + 1.0;
float f2 = x1 -% x1 + 1.0;
usize ef = z - &y > 0 ? 1 : z - &y;
z - &y > 0 ? 1 : z - &y;
return 1;
}
func void testDefault(int x = 2, int y = 100, int z = -100)
{
printf("x = %d, y = %d, z = %d\n", x, y, z);
}
func int testReturnDefer()
{
int i = 0;
i++;
defer ++i;
return i;
}
struct WithArray
{
int[4] x;
}
/*
error Err
{
TEST_ERR1
}
*/
/*
func int testThrow(int x) throws Err
{
if (x < 0) throw Err.TEST_ERR1;
return x * x;
}
*/
func void testErrors()
{
//int x = try testThrow(20) else 0;
int x = 0;
printf("Value was %d, expected 400.\n", x);
}
func void testArray()
{
int[4] zebra = { [2] = 1 };
int[4] deok = { 1, 2, 3, 4 };
WithArray boo;
boo.x[0] = 2;
printf("boo.x[0] = %d\n", boo.x[0]);
printf("boo.x[2] = %d\n", boo.x[2]);
int[4] x;
x[1] = 1;
x[0] = 3;
int y = x[1];
int z = 1;
int* b = &z;
printf("b: %d\n", *b);
*b = 3;
printf("b: %d\n", *b);
printf("z: %d\n", z);
for (int i = 0; i < 4; i++)
{
printf("x[%d] = %d\n", i, x[i]);
}
}
func void testDefer()
{
printf("1 == %d\n", testReturnDefer());
printf("1");
defer printf("8\n");
printf("2");
{
printf("3");
defer printf("5");
printf("4");
}
int i = 0;
goto JUMP;
defer printf("ERROR");
int r = 0;
JUMP:
defer printf("-JUMPDEFER-");
if (i++ < 2) goto JUMP;
switch (int boo = 2)
{
case 0:
printf("\n0\n");
case 2:
defer printf("*CaseDefer*");
printf("-Case2-");
default:
break;
}
defer printf("7");
printf("6");
}
func int main(int x)
{
printf("Helo!\n");
testErrors();
testDefault(y = 99);
testPointers(2, 3);
testDefer();
testArray();
testAnonStruct();
testSimpleStruct(0);
int efd = 9;
uint fefoek = 1;
printf("Helo: %d\n", efd + cast(fefoek, int));
//long fefoek = -fefoek;
int okfe = 1;
return 1;
switch (int bobe = okfe > 0 ? 1 : 0)
{
case 0:
defer printf("case0-\n");
case 1:
printf("case 1\n");
defer printf("case1-\n");
if (efd < 10)
{
{
defer printf("ef < 10\n");
if (efd < 7)
{
defer printf("ef < 7\n");
next;
}
}
}
next;
case 1000 >> 2:
printf("case 1000 >> 2\n");
case (1 << 200) >> 197:
printf("case 1 << 3\n");
default:
printf("default\n");
}
int aa = x++;
int bb = x--;
int cc = ++x;
for (int ok = 0; ok < 10; ok++)
{
printf("ok");
}
printf("\n");
for (int ok = 0, int ko = 0, ok = 2; ok + ko < 10; ok++, ko++)
{
printf(":okko");
}
printf("\n");
while (int ok = 0; int j = ok++, ok < 10)
{
printf("foo");
}
printf("\n");
x = 3;
if (int odk = x, x > 0)
{
printf("helo\n");
}
Test baok = { 1 };
Test2 efe;
efe.t.a = 3;
if (efe.t.a > 2) printf("Works!\n");
int ef = 3;
int *eff = &ef;
eff[0] = 4;
byte *ex = cast(eff, byte*);
ex[0] = 5;
if (eff[0] == 5) printf("Works-5!\n");
ex[1] = 5;
if (eff[0] == 5 + 5 * 256) printf("Works-5*256!\n");
if (ef == 4) printf("Works5!\n");
if (ef == 4) printf("Works1!\n");
ef = 0;
byte a = 2;
short b = 3;
int c = 4;
bool eok = true;
long deee = (eok ? a : b) + (eok ? b : c);
int i = 0;
JUMP:
i = i + 1;
//@hello();
printf("Hello worldABC" "D" "E\u2701\n");
float f = 3.0;
float* pf = &f;
switch (i)
{
case 0:
printf("c0\n");
case 1:
printf("c1\n");
case 2:
printf("c2\n");
case 3:
printf("c3\n");
default:
printf("default\n");
}
if (*pf > i) goto JUMP;
goto EX;
YEF:
return 4;
EX:
printf("EX\n");
goto YEF;
return 1;
}
func void test2(int* x, int y, int z)
{
*(&(&x)[0]);
float cheat = cast(x, int);
x++;
z = 0;
z ? y : z;
x += 1;
y += z;
x -= 1;
y -= z;
y *= 2;
y /= 2;
y /= *x;
y |= 2;
y ^= 2;
y &= 2;
z ^ y;
z | y;
int g = z & y;
g <<= 2;
g <<= z;
g >>= 2;
g >>= z;
int fz = 100;
y && z;
y || z;
y >> z;
z << y;
~z;
!z;
-z;
int i = 3;
uint ui = 2;
int j = 129;
float f = 23.2;
f = f + 1.0;
f = f - 1.0;
f = f * 2.0;
f = f / 3.0;
i = i * 2;
ui = ui * 2;
i = i / 2;
ui = ui / 2;
i = i + 1;
ui = ui + 1;
i = i - 1;
ui = ui - 1;
x + 1;
int j1 = x[0];
j1 = *x;
}

View File

@@ -180,15 +180,6 @@ Type* type_get_unsigned(Type *type)
*/
bool func_return_value_as_out(FunctionSignature *func_sig)
{
Type *return_type = func_sig->rtype->type->canonical;
if (return_type->type_kind == TYPE_VOID) return false;
if (func_has_error_return(func_sig)) return true;
// TODO improve
return type_size(return_type) > 8 * 4;
}
BinaryOp binary_op[TOKEN_LAST + 1] = {

View File

@@ -294,13 +294,20 @@ typedef struct
TypeInfo *type_info;
} EnumDecl;
typedef enum
{
ERROR_RETURN_NONE = 0,
ERROR_RETURN_PARAM = 1,
ERROR_RETURN_RETURN = 2,
} ErrorReturn;
typedef struct _FunctionSignature
{
CallConvention convention : 4;
bool variadic : 1;
bool has_default : 1;
bool throw_any : 1;
bool return_param : 1;
ErrorReturn error_return : 3;
TypeInfo *rtype;
Decl** params;
Decl** throws;
@@ -941,7 +948,7 @@ extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
extern Type *type_compint, *type_compfloat;
extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
extern Type *type_typeid, *type_error;
extern Type *type_typeid, *type_error, *type_error_union;
extern const char *main_name;
@@ -1095,11 +1102,6 @@ void fprint_decl(FILE *file, Decl *dec);
void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent);
void fprint_expr_recursive(FILE *file, Expr *expr, int indent);
bool func_return_value_as_out(FunctionSignature *func_sig);
static inline bool func_has_error_return(FunctionSignature *func_sig)
{
return func_sig->throws || func_sig->throw_any;
}
#pragma mark --- Lexer functions
@@ -1190,7 +1192,7 @@ bool type_is_subtype(Type *type, Type *possible_subtype);
Type *type_find_common_ancestor(Type *left, Type *right);
const char *type_to_error_string(Type *type);
size_t type_size(Type *canonical);
size_t type_abi_alignment(Type *canonical);
unsigned int type_abi_alignment(Type *canonical);
void type_append_signature_name(Type *type, char *dst, size_t *offset);
Type *type_find_max_type(Type *type, Type *other);
@@ -1336,8 +1338,6 @@ static inline const char* struct_union_name_from_token(TokenType type)
return type == TOKEN_STRUCT ? "struct" : "union";
}
#define llvm_type(type) gencontext_get_llvm_type(context, type)
#define DEBUG_TYPE(type) gencontext_get_debug_type(context, type)
void advance(Context *context);

View File

@@ -568,4 +568,25 @@ typedef enum
typedef enum
{
CALL_CONVENTION_NORMAL = 0,
} CallConvention;
} CallConvention;
typedef enum
{
CALL_X86_STD,
CALL_X86_FAST,
CALL_X86_THIS,
CALL_X86_VECTOR,
CALL_X86_PASCAL,
CALL_WIN64,
CALL_X64_SYSV,
CALL_X86_REG,
CALL_AAPCS,
CALL_AAPCS_VFP,
CALL_INTEL_OCL_BICC,
CALL_SPIR_FUNCTION,
CALL_OPENCL_KERNEL,
CALL_PRESERVE_MOST,
CALL_PRESERVE_ALL,
CALL_AARCH64_VECTOR,
} CallABI;

View File

@@ -5,11 +5,35 @@
#include "llvm_codegen_internal.h"
static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context)
{
char *message = LLVMGetDiagInfoDescription(ref);
LLVMDiagnosticSeverity severity = LLVMGetDiagInfoSeverity(ref);
const char *severerity_name = "unknown";
switch (severity)
{
case LLVMDSError:
error_exit("LLVM error generating code for %s: %s", ((GenContext *)context)->ast_context->module->name, message);
break;
case LLVMDSWarning:
severerity_name = "warning";
break;
case LLVMDSRemark:
severerity_name = "remark";
break;
case LLVMDSNote:
severerity_name = "note";
break;
}
DEBUG_LOG("LLVM message [%s]: %s ", severerity_name, message);
LLVMDisposeMessage(message);
}
static void gencontext_init(GenContext *context, Context *ast_context)
{
memset(context, 0, sizeof(GenContext));
context->context = LLVMContextCreate();
LLVMContextSetDiagnosticHandler(context->context, &diagnostics_handler, context);
context->ast_context = ast_context;
}
@@ -18,6 +42,23 @@ static void gencontext_destroy(GenContext *context)
LLVMContextDispose(context->context);
}
LLVMValueRef gencontext_emit_memclear_size_align(GenContext *context, LLVMValueRef ref, uint64_t size, unsigned int align, bool bitcast)
{
LLVMValueRef target = bitcast ? LLVMBuildBitCast(context->builder, ref, llvm_type(type_get_ptr(type_byte)), "") : ref;
return LLVMBuildMemSet(context->builder, target, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), size, false), align);
}
LLVMValueRef gencontext_emit_memclear(GenContext *context, LLVMValueRef ref, Type *type)
{
Type *canonical = type->canonical;
// TODO avoid bitcast on those that do not need them.
return gencontext_emit_memclear_size_align(context, ref, type_size(canonical),
type_abi_alignment(canonical), true);
}
static LLVMValueRef gencontext_emit_null_constant(GenContext *context, Type *type)
{
@@ -162,6 +203,11 @@ static inline unsigned lookup_intrinsic(const char *name)
return LLVMLookupIntrinsicID(name, strlen(name));
}
static inline unsigned lookup_attribute(const char *name)
{
return LLVMGetEnumAttributeKindForName(name, strlen(name));
}
static bool intrinsics_setup = false;
unsigned ssub_overflow_intrinsic_id;
unsigned usub_overflow_intrinsic_id;
@@ -171,6 +217,15 @@ unsigned smul_overflow_intrinsic_id;
unsigned umul_overflow_intrinsic_id;
unsigned trap_intrinsic_id;
unsigned noinline_attribute;
unsigned alwaysinline_attribute;
unsigned inlinehint_attribute;
unsigned noreturn_attribute;
unsigned nounwind_attribute;
unsigned writeonly_attribute;
unsigned readonly_attribute;
unsigned optnone_attribute;
void llvm_codegen_setup()
{
assert(intrinsics_setup == false);
@@ -182,6 +237,15 @@ void llvm_codegen_setup()
umul_overflow_intrinsic_id = lookup_intrinsic("llvm.umul.with.overflow");
trap_intrinsic_id = lookup_intrinsic("llvm.trap");
noinline_attribute = lookup_attribute("noinline");
alwaysinline_attribute = lookup_attribute("alwaysinline");
inlinehint_attribute = lookup_attribute("inlinehint");
noreturn_attribute = lookup_attribute("noreturn");
nounwind_attribute = lookup_attribute("nounwind");
writeonly_attribute = lookup_attribute("writeonly");
readonly_attribute = lookup_attribute("readonly");
optnone_attribute = lookup_attribute("optnone");
intrinsics_setup = true;
}
@@ -251,3 +315,9 @@ void llvm_codegen(Context *context)
gencontext_end_module(&gen_context);
gencontext_destroy(&gen_context);
}
void gencontext_add_attribute(GenContext context, unsigned attribute_id, LLVMValueRef value_to_add_attribute_to)
{
LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context.context, attribute_id, 0);
LLVMAddAttributeAtIndex(value_to_add_attribute_to, -1, llvm_attr);
}

View File

@@ -308,18 +308,19 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
* Improve: Direct assign in the case where this is assigning to a variable.
* Improve: Create constant initializer for the constant case and do a memcopy
*/
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr, LLVMValueRef optional_ref)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef ref = gencontext_emit_alloca(context, type, "literal");
LLVMValueRef ref = optional_ref ?: gencontext_emit_alloca(context, type, "literal");
Type *canonical = expr->type->canonical;
if (expr->expr_initializer.init_type != INITIALIZER_NORMAL)
{
gencontext_emit_memclear(context, ref, canonical);
}
if (expr->expr_initializer.init_type == INITIALIZER_ZERO)
{
LLVMBuildMemSet(context->builder,
ref,
LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
expr->type->decl->strukt.abi_alignment);
return LLVMBuildLoad2(context->builder, type, ref, "");
}
@@ -346,12 +347,6 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
return LLVMBuildLoad2(context->builder, type, ref, "");
}
// Clear the temp.
LLVMBuildMemSet(context->builder, ref, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment);
VECEACH(elements, i)
{
Expr *element = elements[i];
@@ -814,6 +809,28 @@ LLVMValueRef gencontext_emit_post_unary_expr(GenContext *context, Expr *expr)
return gencontext_emit_post_inc_dec(context, expr->post_expr.expr, expr->post_expr.operator == POSTUNARYOP_INC ? 1 : -1, false);
}
LLVMValueRef gencontext_emit_try_expr(GenContext *context, Expr *expr)
{
if (expr->try_expr.else_expr)
{
LLVMBasicBlockRef catch_block = gencontext_create_free_block(context, "catchblock");
LLVMBasicBlockRef after_catch = gencontext_create_free_block(context, "aftercatch");
LLVMValueRef res = gencontext_emit_alloca(context, llvm_type(expr->try_expr.else_expr->type), "catch");
gencontext_push_catch(context, NULL, catch_block);
LLVMValueRef normal_res = gencontext_emit_expr(context, expr->try_expr.expr);
gencontext_pop_catch(context);
LLVMBuildStore(context->builder, normal_res, res);
gencontext_emit_br(context, after_catch);
gencontext_emit_block(context, catch_block);
LLVMValueRef catch_value = gencontext_emit_expr(context, expr->try_expr.else_expr);
LLVMBuildStore(context->builder, catch_value, res);
gencontext_emit_br(context, after_catch);
gencontext_emit_block(context, after_catch);
return LLVMBuildLoad2(context->builder, llvm_type(expr->try_expr.else_expr->type), res, "");
}
TODO
}
static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
{
BinaryOp binary_op = expr->binary_expr.operator;
@@ -829,9 +846,7 @@ static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
if (binary_op == BINARYOP_ASSIGN)
{
LLVMValueRef addr = gencontext_emit_address(context, expr->binary_expr.left);
LLVMValueRef value = gencontext_emit_expr(context, expr->binary_expr.right);
LLVMBuildStore(context->builder, value, addr);
return value;
return gencontext_emit_assign_expr(context, addr, expr->binary_expr.right);
}
return gencontext_emit_binary(context, expr, NULL, binary_op);
}
@@ -939,22 +954,79 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
}
}
static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRef value)
{
LLVMBasicBlockRef after_block = gencontext_create_free_block(context, "");
size_t catch_index = context->catch_stack_index;
while (catch_index > 0)
{
catch_index--;
// TODO check error
Catch *current_catch = &context->catch_stack[catch_index];
if (!current_catch->decl)
{
gencontext_emit_cond_br(context, value, current_catch->catch_block, after_block);
gencontext_emit_block(context, after_block);
return;
}
}
TODO
}
LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
{
size_t args = vec_size(expr->call_expr.arguments);
Decl *function_decl = expr->call_expr.function->identifier_expr.decl;
FunctionSignature *signature = &function_decl->func.function_signature;
LLVMValueRef return_param = NULL;
LLVMValueRef error_param = NULL;
if (signature->return_param)
{
return_param = gencontext_emit_alloca(context, llvm_type(signature->rtype->type), "returnparam");
args++;
}
if (signature->error_return == ERROR_RETURN_PARAM)
{
error_param = gencontext_emit_alloca(context, llvm_type(type_error_union), "errorparam");
args++;
}
LLVMValueRef *values = args ? malloc_arena(args * sizeof(LLVMValueRef)) : NULL;
unsigned param_index = 0;
if (return_param)
{
values[param_index++] = return_param;
}
if (error_param)
{
values[param_index++] = error_param;
}
VECEACH(expr->call_expr.arguments, i)
{
values[i] = gencontext_emit_expr(context, expr->call_expr.arguments[i]);
values[param_index++] = gencontext_emit_expr(context, expr->call_expr.arguments[i]);
}
Decl *function = expr->call_expr.function->identifier_expr.decl;
LLVMValueRef func = function->func.backend_value;
LLVMTypeRef func_type = llvm_type(function->type);
// TODO fix throws and return optimization
LLVMValueRef call = LLVMBuildCall2(context->builder, func_type, func, values, args, "call");
if (signature->error_return)
{
if (error_param)
{
LLVMValueRef maybe_error = LLVMBuildLoad2(context->builder, llvm_type(type_error_union), error_param, "");
TODO // Incorrect, must get subset if this is 128 bits
gencontext_emit_throw_branch(context, maybe_error);
}
else
{
gencontext_emit_throw_branch(context, call);
}
}
// If we used a return param, then load that info here.
if (return_param)
{
call = LLVMBuildLoad2(context->builder, llvm_type(signature->rtype->type), return_param, "");
}
/*
if (function->func.function_signature.convention)
{
@@ -1016,6 +1088,20 @@ LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrin
return LLVMBuildCall2(context->builder, type, decl, values, arg_count, "");
}
LLVMValueRef gencontext_emit_assign_expr(GenContext *context, LLVMValueRef ref, Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_INITIALIZER_LIST:
return gencontext_emit_initializer_list_expr(context, expr, ref);
default:
break;
}
LLVMValueRef value = gencontext_emit_expr(context, expr);
LLVMBuildStore(context->builder, value, ref);
return value;
}
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{
@@ -1042,10 +1128,11 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
return gencontext_emit_ternary_expr(context, expr);
case EXPR_POST_UNARY:
return gencontext_emit_post_unary_expr(context, expr);
case EXPR_TRY:
return gencontext_emit_try_expr(context, expr);
case EXPR_TYPE:
case EXPR_SIZEOF:
case EXPR_TYPE_ACCESS:
case EXPR_TRY:
case EXPR_MACRO_EXPR:
// These are folded in the semantic analysis step.
UNREACHABLE
@@ -1058,7 +1145,7 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
case EXPR_GROUP:
return gencontext_emit_expr(context, expr->group_expr);
case EXPR_INITIALIZER_LIST:
return gencontext_emit_initializer_list_expr(context, expr);
return gencontext_emit_initializer_list_expr(context, expr, NULL);
case EXPR_EXPRESSION_LIST:
return gencontext_emit_expression_list_expr(context, expr);
case EXPR_CAST:

View File

@@ -84,7 +84,7 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
void gencontext_emit_implicit_return(GenContext *context)
{
if (func_has_error_return(&context->cur_func_decl->func.function_signature))
if (context->cur_func_decl->func.function_signature.error_return == ERROR_RETURN_RETURN)
{
LLVMBuildRet(context->builder, LLVMConstInt(llvm_type(type_ulong), 0, false));
}
@@ -115,22 +115,27 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
LLVMValueRef alloca_point = LLVMBuildAlloca(context->builder, LLVMInt32TypeInContext(context->context), "alloca_point");
context->alloca_point = alloca_point;
unsigned return_parameter = func_return_value_as_out(&decl->func.function_signature) ? 1 : 0;
if (return_parameter)
FunctionSignature *signature = &decl->func.function_signature;
int arg = 0;
if (signature->return_param)
{
context->return_out = gencontext_emit_alloca(context, llvm_type(decl->func.function_signature.rtype->type), "retval");
LLVMBuildStore(context->builder, LLVMGetParam(context->function, 0), context->return_out);
context->return_out = LLVMGetParam(context->function, arg++);
}
else
{
context->return_out = NULL;
}
if (signature->error_return == ERROR_RETURN_PARAM)
{
context->error_out = gencontext_emit_alloca(context, llvm_type(type_error_union), "errorval");
LLVMBuildStore(context->builder, LLVMGetParam(context->function, arg++), context->error_out);
}
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
VECEACH(decl->func.function_signature.params, i)
{
gencontext_emit_parameter(context, decl->func.function_signature.params[i], i + return_parameter);
gencontext_emit_parameter(context, decl->func.function_signature.params[i], arg++);
}
VECEACH(decl->func.labels, i)
@@ -179,6 +184,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
decl->func.backend_value = LLVMAddFunction(context->module, decl->external_name,
llvm_type(decl->type));
// Specify appropriate storage class, visibility and call convention
// extern functions (linkedited in separately):
/*

View File

@@ -27,6 +27,12 @@ typedef struct
LLVMBasicBlockRef next_block;
} BreakContinue;
typedef struct
{
Decl *decl;
LLVMBasicBlockRef catch_block;
} Catch;
typedef struct
{
LLVMDIBuilderRef builder;
@@ -39,6 +45,7 @@ typedef struct
} DebugContext;
#define BREAK_STACK_MAX 256
#define CATCH_STACK_MAX 256
typedef struct
{
@@ -60,9 +67,12 @@ typedef struct
Ast **defer_stack;
DebugContext debug;
Context *ast_context;
Catch catch_stack[CATCH_STACK_MAX];
size_t catch_stack_index;
BreakContinue break_continue_stack[BREAK_STACK_MAX];
size_t break_continue_stack_index;
LLVMValueRef return_out;
LLVMValueRef error_out;
LLVMBasicBlockRef expr_block_exit;
bool current_block_is_target : 1;
bool did_call_stack_save : 1;
@@ -76,21 +86,46 @@ extern unsigned smul_overflow_intrinsic_id;
extern unsigned umul_overflow_intrinsic_id;
extern unsigned trap_intrinsic_id;
// No function inlining
extern unsigned noinline_attribute;
// Force inlining
extern unsigned alwaysinline_attribute;
// "Inline possibly"
extern unsigned inlinehint_attribute;
// No function return
extern unsigned noreturn_attribute;
// No exceptions
extern unsigned nounwind_attribute;
// Argument (no writes through the pointer) or function (no writes)
extern unsigned writeonly_attribute;
// Argument (no reads through the pointer) or function (no reads)
extern unsigned readonly_attribute;
// Disable optimization.
extern unsigned optnone_attribute;
void gencontext_begin_module(GenContext *context);
void gencontext_end_module(GenContext *context);
void gencontext_add_attribute(GenContext context, unsigned attribute_id, LLVMValueRef value_to_add_attribute_to);
void gencontext_emit_stmt(GenContext *context, Ast *ast);
void gencontext_push_catch(GenContext *context, Decl *error_type, LLVMBasicBlockRef catch_block);
void gencontext_pop_catch(GenContext *context);
LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrinsic_id, LLVMTypeRef *types,
LLVMValueRef *values, unsigned arg_count);
void gencontext_emit_panic_on_true(GenContext *context, LLVMValueRef value, const char *panic_name);
void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end);
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr);
LLVMValueRef gencontext_emit_ast_expr(GenContext *context, Ast *expr);
LLVMValueRef gencontext_emit_assign_expr(GenContext *context, LLVMValueRef ref, Expr *expr);
LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type);
void gencontext_emit_debug_location(GenContext *context, SourceRange location);
LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type);
LLVMValueRef gencontext_emit_alloca(GenContext *context, LLVMTypeRef type, const char *name);
void gencontext_emit_compound_stmt(GenContext *context, Ast *ast);
void gencontext_emit_block(GenContext *context, LLVMBasicBlockRef next_block);
LLVMValueRef gencontext_emit_memclear_size_align(GenContext *context, LLVMValueRef ref, uint64_t size, unsigned align, bool bitcast);
LLVMValueRef gencontext_emit_memclear(GenContext *context, LLVMValueRef ref, Type *type);
void gencontext_emit_br(GenContext *context, LLVMBasicBlockRef next_block);
bool gencontext_check_block_branch_emit(GenContext *context);
void gencontext_emit_cond_br(GenContext *context, LLVMValueRef value, LLVMBasicBlockRef thenBlock, LLVMBasicBlockRef elseBlock);
@@ -98,20 +133,86 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context
{
return LLVMCreateBasicBlockInContext(context->context, name);
}
void gencontext_emit_function_body(GenContext *context, Decl *decl);
void gencontext_emit_implicit_return(GenContext *context);
void gencontext_emit_function_decl(GenContext *context, Decl *decl);
void gencontext_emit_extern_decl(GenContext *context, Decl *decl);
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr);
#define LLVMTYPE(type) type->backend_type
static inline LLVMValueRef gencontext_load_expr(GenContext *context, LLVMValueRef value)
{
return LLVMBuildLoad(context->builder, value, "");
}
LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type);
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *type, Type *target_type);
static inline bool gencontext_func_pass_return_by_param(GenContext *context, Type *first_param_type) { return false; };
static inline bool gencontext_func_pass_param_by_reference(GenContext *context, Type *param_type) { return false; }
static inline bool gencontext_use_debug(GenContext *context)
{
return context && context->debug.builder != NULL;
}
static inline bool call_supports_variadic(CallABI abi)
{
switch (abi)
{
case CALL_X86_STD:
case CALL_X86_REG:
case CALL_X86_THIS:
case CALL_X86_FAST:
case CALL_X86_PASCAL:
case CALL_X86_VECTOR:
case CALL_SPIR_FUNCTION:
case CALL_OPENCL_KERNEL:
return false;
default:
return true;
}
}
static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi)
{
switch (abi)
{
case CALL_X86_STD:
return LLVMX86StdcallCallConv;
case CALL_X86_FAST:
return LLVMX86FastcallCallConv;
case CALL_X86_PASCAL:
return LLVMCCallConv;
case CALL_X86_REG:
return LLVMX86RegCallCallConv;
case CALL_X86_THIS:
return LLVMX86ThisCallCallConv;
case CALL_X86_VECTOR:
return LLVMX86VectorCallCallConv;
case CALL_WIN64:
return LLVMWin64CallConv;
case CALL_X64_SYSV:
return LLVMX8664SysVCallConv;
case CALL_AAPCS:
return LLVMARMAAPCSCallConv;
case CALL_AAPCS_VFP:
return LLVMARMAAPCSVFPCallConv;
case CALL_INTEL_OCL_BICC:
return LLVMIntelOCLBICallConv;
case CALL_AARCH64_VECTOR:
TODO
case CALL_SPIR_FUNCTION:
return LLVMSPIRFUNCCallConv;
case CALL_OPENCL_KERNEL:
TODO // Target dependent.
case CALL_PRESERVE_ALL:
return LLVMPreserveAllCallConv;
case CALL_PRESERVE_MOST:
return LLVMPreserveMostCallConv;
default:
return LLVMCCallConv;
}
}
#define llvm_type(type) gencontext_get_llvm_type(context, type)
#define DEBUG_TYPE(type) gencontext_get_debug_type(context, type)

View File

@@ -42,18 +42,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
*/
if (decl->var.init_expr)
{
Expr *expr = decl->var.init_expr;
// Quick path for empty initializer list
if (expr->expr_kind == EXPR_INITIALIZER_LIST && expr->expr_initializer.init_type == INITIALIZER_ZERO)
{
LLVMBuildMemSet(context->builder, decl->var.backend_ref, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
expr->type->decl->strukt.abi_alignment);
return decl->var.backend_ref;
}
LLVMValueRef value = gencontext_emit_expr(context, decl->var.init_expr);
LLVMBuildStore(context->builder, value, decl->var.backend_ref);
gencontext_emit_assign_expr(context, decl->var.backend_ref, decl->var.init_expr);
return decl->var.backend_ref;
}
return decl->var.backend_ref;
@@ -207,10 +196,25 @@ void gencontext_emit_if(GenContext *context, Ast *ast)
}
void gencontext_push_catch(GenContext *context, Decl *error_type, LLVMBasicBlockRef catch_block)
{
size_t index = context->catch_stack_index++;
if (index == CATCH_STACK_MAX - 1)
{
error_exit("Exhausted catch stack - exceeded %d entries.", CATCH_STACK_MAX);
}
context->catch_stack[index].decl = error_type;
context->catch_stack[index].catch_block = catch_block;
}
static void
gencontext_push_break_continue(GenContext *context, LLVMBasicBlockRef break_block, LLVMBasicBlockRef continue_block,
LLVMBasicBlockRef next_block)
void gencontext_pop_catch(GenContext *context)
{
assert(context->catch_stack_index > 0);
context->catch_stack_index--;
}
static void gencontext_push_break_continue(GenContext *context, LLVMBasicBlockRef break_block,
LLVMBasicBlockRef continue_block, LLVMBasicBlockRef next_block)
{
size_t index = context->break_continue_stack_index++;
if (index == BREAK_STACK_MAX - 1)
@@ -622,7 +626,9 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
gencontext_emit_scoped_stmt(context, ast);
break;
case AST_EXPR_STMT:
{
gencontext_emit_expr(context, ast->expr_stmt);
}
break;
case AST_DECLARE_STMT:
gencontext_emit_decl(context, ast);

View File

@@ -123,31 +123,37 @@ LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type)
{
LLVMTypeRef *params = NULL;
FunctionSignature *signature = type->func.signature;
bool return_parameter = func_return_value_as_out(signature);
bool return_error = func_has_error_return(signature);
unsigned parameters = vec_size(signature->params) + return_parameter;
unsigned parameters = vec_size(signature->params);
if (signature->return_param) parameters++;
if (signature->error_return == ERROR_RETURN_PARAM) parameters++;
if (parameters)
{
params = malloc_arena(sizeof(LLVMTypeRef) * parameters);
if (return_parameter)
unsigned index = 0;
if (signature->return_param)
{
params[0] = llvm_get_type(context, signature->rtype->type);
params[index++] = llvm_get_type(context, type_get_ptr(signature->rtype->type));
}
if (signature->error_return == ERROR_RETURN_PARAM)
{
params[index++] = llvm_get_type(context, type_get_ptr(type_error_union));
}
VECEACH(signature->params, i)
{
params[i + return_parameter] = llvm_get_type(context, signature->params[i]->type->canonical);
params[index++] = llvm_get_type(context, signature->params[i]->type->canonical);
}
}
LLVMTypeRef ret_type;
if (return_error)
if (signature->error_return == ERROR_RETURN_RETURN)
{
ret_type = llvm_get_type(context, type_ulong);
}
else
{
ret_type = return_parameter ? llvm_get_type(context, type_void) : llvm_get_type(context, type->func.signature->rtype->type);
ret_type = signature->return_param ? llvm_get_type(context, type_void) : llvm_get_type(context, type->func.signature->rtype->type);
}
return LLVMFunctionType( ret_type, params, parameters, signature->variadic);
LLVMTypeRef functype = LLVMFunctionType(ret_type, params, parameters, signature->variadic);
return functype;
}

View File

@@ -272,6 +272,32 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
type_append_signature_name(err_decl->type, buffer, &buffer_write_offset);
}
}
unsigned error_types = vec_size(signature->throws);
if (signature->throw_any || error_types > 1)
{
signature->error_return = ERROR_RETURN_PARAM;
}
else if (error_types == 1)
{
signature->error_return = ERROR_RETURN_RETURN;
}
else
{
signature->error_return = ERROR_RETURN_NONE;
}
Type *return_type = signature->rtype->type->canonical;
signature->return_param = false;
if (return_type->type_kind != TYPE_VOID)
{
// TODO fix this number with ABI compatibility
if (signature->error_return == ERROR_RETURN_RETURN || type_size(return_type) > 8 * 2)
{
signature->return_param = true;
}
}
if (!all_ok) return NULL;
TokenType type = TOKEN_INVALID_TOKEN;
signature->mangled_signature = symtab_add(buffer, buffer_write_offset, fnv1a(buffer, buffer_write_offset), &type);

View File

@@ -247,7 +247,11 @@ static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr
unsigned error_params = signature->throw_any || signature->throws;
if (error_params)
{
TODO
if (context->try_nesting == 0)
{
SEMA_ERROR(expr, "Function '%s' throws errors, this call must be prefixed 'try'.", decl->name);
return false;
}
}
unsigned func_param_count = vec_size(func_params);
unsigned num_args = vec_size(args);
@@ -2185,14 +2189,16 @@ static inline bool sema_expr_analyse_post_unary(Context *context, Type *to, Expr
static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr)
{
if (!sema_analyse_expr(context, to, expr->try_expr.expr)) return false;
context->try_nesting++;
bool success = sema_analyse_expr(context, to, expr->try_expr.expr);
context->try_nesting--;
if (!success) return false;
expr->type = expr->try_expr.expr->type;
if (expr->try_expr.else_expr)
{
if (!sema_analyse_expr(context, to, expr->try_expr.else_expr)) return false;
}
// Check errors!
TODO
// TODO Check errors!
return true;
}

View File

@@ -754,8 +754,9 @@ static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
SEMA_ERROR(throw_value, "Only 'error' types can be thrown, this is a '%s'.", type->name);
return false;
}
if (!context->try_nesting && !func_has_error_return(&context->active_function_for_analysis->func.function_signature))
if (!context->try_nesting && !context->active_function_for_analysis->func.function_signature.error_return)
{
// TODO check error type
SEMA_ERROR(statement, "This 'throw' is not handled, please add a 'throws %s' clause to the function signature or use try-catch.", type->name);
return false;
}

View File

@@ -102,13 +102,14 @@ void target_setup()
build_target.alloca_address_space = 0;
LLVMTypeRef byte_type = LLVMIntType(8);
LLVMTypeRef short_type = LLVMIntType(16);
LLVMTypeRef int_type = LLVMIntType(32);
LLVMTypeRef long_type = LLVMIntType(64);
LLVMTypeRef float_type = LLVMFloatType();
LLVMTypeRef double_type = LLVMDoubleType();
LLVMTypeRef quad_type = LLVMFP128Type();
LLVMContextRef context = LLVMContextCreate();
LLVMTypeRef byte_type = LLVMIntTypeInContext(context, 8);
LLVMTypeRef short_type = LLVMIntTypeInContext(context, 16);
LLVMTypeRef int_type = LLVMIntTypeInContext(context, 32);
LLVMTypeRef long_type = LLVMIntTypeInContext(context, 64);
LLVMTypeRef float_type = LLVMFloatTypeInContext(context);
LLVMTypeRef double_type = LLVMDoubleTypeInContext(context);
LLVMTypeRef quad_type = LLVMFP128TypeInContext(context);
LLVMTypeRef pointer_type = LLVMPointerType(int_type, 0);
build_target.align_byte = LLVMABIAlignmentOfType(build_target.llvm_data_layout, byte_type);
build_target.align_short = LLVMABIAlignmentOfType(build_target.llvm_data_layout, short_type);

View File

@@ -11,7 +11,7 @@ static Type t_usz, t_isz;
static Type t_cus, t_cui, t_cul, t_cull;
static Type t_cs, t_ci, t_cl, t_cll;
static Type t_voidstar, t_typeid;
static Type t_err;
static Type t_err, t_error_union;
Type *type_bool = &t_u1;
Type *type_void = &t_u0;
@@ -20,6 +20,7 @@ Type *type_voidptr = &t_voidstar;
Type *type_float = &t_f32;
Type *type_double = &t_f64;
Type *type_error = &t_err;
Type *type_error_union = &t_error_union;
Type *type_typeid = &t_typeid;
Type *type_char = &t_i8;
Type *type_short = &t_i16;
@@ -225,7 +226,7 @@ size_t type_size(Type *canonical)
UNREACHABLE
}
size_t type_abi_alignment(Type *canonical)
unsigned int type_abi_alignment(Type *canonical)
{
assert(canonical && canonical->canonical == canonical);
switch (canonical->type_kind)