Merge pull request #21 from c3lang/develop

Enum, unions, struct and traps on overflow added.
This commit is contained in:
Christoffer Lerno
2020-04-09 13:49:00 +02:00
committed by GitHub
33 changed files with 1268 additions and 460 deletions

72
missing.txt Normal file
View File

@@ -0,0 +1,72 @@
Things missing:
* Attributes
- All types: @noreflect, @deprecated
- Struct: @packed, @aligned, @opaque
- Enums: @distinct, @noreflect
- Unions: @packed, @aligned, @opaque
- Functions: @inline, @reflect, @noreturn, @section, @unused, @used, @interrupt, @naked, @convention()
- Calls: @noinline, @inline
- Variables, parameters: @unused
- Constants, globals: @unused, @used, @section
- Labels: @unused
* Designated initializer
- Array initializer
- Array range initializer { [1..2] = 2 }
* Initializers
- Array initializers
- Union initializers
- Initializers with anonymous members
* Asserts
- assert, $assert
- @unreachable
* Types
- Vararrays
- Strings
- Array
- Slice
- Values: size, alignment, name, qualifiedName
- Functions: offsetof
- Distinct types
- Simd types?
- Complex types?
- Subtype casts
- Bitstruct
- Enumset
- Typeid
* Struct / union
- Cast to union?
- Structural typed anonymous structs and casts to them.
* Expressions
- Disallow x >= 0 and x < 0 on unsigned types unless in a macro.
- Range check arrays on debug
- Allow negating int if assigned to a larger type. E.g short x = 1; int y = -x;
* Switch
- String switch
- Range case
* Functions
- Varargs
- C ABI
- Safe varargs
* Pre-post conditions
- Breakdown here
* Error handling
- Error unions
- Catch/try
- Function return channel
* Enum
- Values: min, max, array
- Functions: fomOrdinal, ordinal, fromName, name, fromFullName, fullName, fromQualifiedName, qualifiedName, <value>(), fromValue()

View File

@@ -2,16 +2,6 @@ module bar;
typedef int as Bob;
/* hello *//* there */
/+ why /+ you /* lucky +/ +/
// Whut
// Here
//
//---
/*
Hello
*/
struct Test
{
int a;
@@ -38,30 +28,6 @@ struct Teob
int oekfeo;
}
enum EnumTest : long
{
VALUE1 = 4,
VALUE2
}
enum EnumTestDefault
{
VALUE,
VALUE2
}
enum EnumTestNoOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestSmall : ushort
{
VALUE = 0xFF,
VALUE2 = 0xFFFF
}
enum EnumWithData : ushort (int a, char[] x, long b = 4)
{
// Currently the args are ignored TODO!
@@ -69,37 +35,15 @@ enum EnumWithData : ushort (int a, char[] x, long b = 4)
TEST2(12, "world")
}
/* ERRORS
enum EnumWithErrorData : int (int
{
TEST
}
enum EnumWithErrorWithMissingName : int (int)
{
TEST
}
/*
enum EnumTestNoOverflowAfterULong : ulong
{
VALUE = 0xFFFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestOverflow
{
VALUE = 0x80000000,
}
enum EnumTestOverflowAfter
{
VALUE = 0x80000000 - 1,
VALUE_EXCEED
}
enum EnumTestOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFF,
@@ -112,24 +56,153 @@ enum EnumTestOverflowAfterULong : ulong
VALUE_EXCEED
}
enum EnumTestErrorType : float
enum EnumTestOverflowAfter
{
VALUE_BOOM
}
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;
}
struct AnonStruct
{
int a;
struct sune
{
int b;
int c;
}
struct
{
int b1;
int c1;
}
union
{
int b2;
int c2;
}
int x;
}
func void testAnonStruct()
{
AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 };
AnonStruct foo;
s.sune.b = 1;
s.b1 = 2;
s.b2 = 3;
s.c2 = 4;
}
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;
@@ -144,6 +217,7 @@ func int borok() throws
func void testNoReturn()
{
int i = 0;
i = -i;
}
func int testReturn()
@@ -440,7 +514,10 @@ func int testPointers(int x)
}
func int main(int x)
{
printf("Helo!\n");
int efd = 9;
uint fefoek = 1;
long fefoek = -fefoek;
int okfe = 1;
return 1;
switch (int bobe = okfe > 0 ? 1 : 0)

View File

@@ -0,0 +1,13 @@
module comments;
/* Span *//* style */
/+ Nested /+ Errors /* Inside +/ +/
// Single line
/*
Multiline span style
*/
func void test()
{
return;
}

View File

@@ -0,0 +1,24 @@
enum EnumWithErrorWithMissingName : int (int)
// @error The function parameter must be named
{
TEST
}
enum EnumWithErrorData : int (int
// @error Unexpected end of parameter list
{
TEST
}
enum EnumTestOverflow
{
VALUE = 0x80000000,
// @error does not fit into 'int'
}
enum EnumTestErrorType : float
// @error The enum type must be an integer type not 'float'
{
VALUE_BOOM
}

View File

@@ -0,0 +1,31 @@
enum EnumTest : long
{
VALUE1 = 4,
VALUE2
}
typedef long as Frob;
enum EnumTestAlias : Frob
{
VALUE1 = 4,
VALUE2
}
enum EnumTestDefault
{
VALUE,
VALUE2
}
enum EnumTestNoOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestSmall : ushort
{
VALUE = 0xFF,
VALUE2 = 0xFFFF
}

View File

@@ -0,0 +1,12 @@
module errors;
error TheError
{
FOO_MISSING,
NO_SUCH_FILE,
}
error OtherError
{
BAR_OVERFLOWED
}

View File

View File

@@ -0,0 +1,5 @@
module typedefs;
typedef Loop as Loop2;
typedef Loop2 as Loop3;
typedef Loop3 as Loop;

View File

@@ -0,0 +1,14 @@
module typedefs;
// Standard case
typedef int as Foo;
// Nested resolution
typedef AType as BType;
typedef int as AType;
enum Bar : BType
{
A,
B
}

View File

@@ -316,6 +316,7 @@ void parse_arguments(int argc, const char *argv[])
build_options.optimization_level = OPTIMIZATION_NOT_SET;
build_options.size_optimization_level = SIZE_OPTIMIZATION_NOT_SET;
build_options.debug_info = false;
build_options.debug_mode = false;
build_options.command = COMMAND_MISSING;
build_options.symtab_size = DEFAULT_SYMTAB_SIZE;
build_options.files = NULL;

View File

@@ -103,6 +103,7 @@ typedef struct
OptimizationLevel optimization_level;
SizeOptimizationLevel size_optimization_level;
bool debug_info;
bool debug_mode;
bool emit_llvm;
bool emit_bitcode;
} BuildOptions;

View File

@@ -8,7 +8,6 @@ static void fprint_asts_recursive(FILE *file, Ast **asts, int indent);
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
{
assert(name.string);
Decl *decl = CALLOCS(Decl);
decl->decl_kind = decl_kind;
decl->name_span = name.span;
@@ -551,12 +550,6 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->type_access.type, indent + 1);
break;
case EXPR_STRUCT_VALUE:
fprintf_indented(file, indent, "(structvalue\n");
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->struct_value_expr.type, indent + 1);
fprint_expr_recursive(file, expr->struct_value_expr.init_expr, indent + 1);
break;
case EXPR_ACCESS:
fprintf_indented(file, indent, "(access .%s\n", expr->access_expr.sub_element.string);
fprint_expr_common(file, expr, indent + 1);
@@ -567,6 +560,10 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->type_expr.type, indent + 1);
break;
case EXPR_GROUP:
fprintf_indented(file, indent, "(group\n");
fprint_expr_recursive(file, expr->group_expr, indent + 1);
break;
case EXPR_CALL:
fprintf_indented(file, indent, "(call\n");
fprint_expr_common(file, expr, indent + 1);
@@ -595,12 +592,27 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_recursive(file, expr->ternary_expr.else_expr, indent + 1);
break;
case EXPR_INITIALIZER_LIST:
fprintf_indented(file, indent, "(initializerlist\n");
fprintf_indented(file, indent, "(initializerlist ");
switch (expr->expr_initializer.init_type)
{
case INITIALIZER_UNKNOWN:
fprintf(file, "not-analyzed\n");
break;
case INITIALIZER_ZERO:
fprintf(file, "zero\n");
break;
case INITIALIZER_NORMAL:
fprintf(file, "normal\n");
break;
case INITIALIZER_DESIGNATED:
fprintf(file, "designated\n");
break;
}
fprint_expr_common(file, expr, indent + 1);
{
VECEACH(expr->initializer_expr, i)
VECEACH(expr->expr_initializer.initializer_expr, i)
{
fprint_expr_recursive(file, expr->initializer_expr[i], indent + 1);
fprint_expr_recursive(file, expr->expr_initializer.initializer_expr[i], indent + 1);
}
}
break;

View File

@@ -302,13 +302,24 @@ bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
return true;
}
/**
* Convert from compile time int to any signed or unsigned int
* @return true unless the conversion was lossy.
*/
bool ixxen(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
assert(canonical->type_kind == TYPE_ENUM);
canonical = canonical->decl->enums.type_info->type->canonical;
return ixxxi(left, canonical, type, cast_type);
}
/**
* Cast signed int -> signed int
* @return true if this is a widening, an explicit cast or if it is an implicit assign add
*/
bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
bool sisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
{
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize;
if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT)
{
@@ -330,9 +341,9 @@ bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
* Cast unsigned int -> unsigned int
* @return true if this was not a narrowing implicit assign or narrowing implicit assign add
*/
bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
bool uiui(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
{
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize;
if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT)
{
@@ -355,9 +366,9 @@ bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
* Cast unsigned int -> signed int
* @return true if this is an explicit cast or if it is an implicit assign add or if it is a widening cast.
*/
bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
bool uisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
{
bool is_widening = from->builtin.bytesize < canonical->builtin.bytesize;
bool is_widening = from_canonical->builtin.bytesize < canonical->builtin.bytesize;
if (!is_widening && cast_type != CAST_TYPE_EXPLICIT)
{
@@ -505,9 +516,45 @@ bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
return true;
}
bool xixi(Expr *left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
{
assert(from_canonical->canonical == from_canonical);
switch (from_canonical->type_kind)
{
case TYPE_IXX:
return ixxxi(left, canonical, type, cast_type);
case ALL_SIGNED_INTS:
if (type_is_unsigned(canonical)) return siui(left, canonical, type, cast_type);
return sisi(left, from_canonical, canonical, type, cast_type);
case ALL_UNSIGNED_INTS:
if (type_is_unsigned(canonical)) return uiui(left, from_canonical, canonical, type, cast_type);
return uisi(left, from_canonical, canonical, type, cast_type);
default:
UNREACHABLE
}
}
bool enxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
TODO
Type *enum_type = from->decl->enums.type_info->type;
Type *enum_type_canonical = enum_type->canonical;
// 1. If the underlying type is the same, this is just setting the type.
if (canonical == enum_type_canonical)
{
left->type = type;
return true;
}
// 2. See if we can convert to the target type.
if (cast_type != CAST_TYPE_EXPLICIT && type_find_max_type(enum_type_canonical, canonical) != canonical)
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
SEMA_ERROR(left, "Cannot implictly convert '%s' with underlying type of '%s' to '%s',"
" use an explicit cast if this is what you want.", type_to_error_string(from),
type_to_error_string(enum_type_canonical), type_to_error_string(canonical));
return false;
}
// 3. Dispatch to the right cast:
return xixi(left, enum_type_canonical, canonical, type, cast_type);
}
bool erxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
@@ -632,6 +679,7 @@ CastKind cast_to_bool_kind(Type *type)
UNREACHABLE
}
bool cast(Expr *expr, Type *to_type, CastType cast_type)
{
Type *from_type = expr->type->canonical;
@@ -656,6 +704,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
if (type_is_float(canonical)) return ixxfp(expr, canonical, to_type, cast_type);
if (canonical == type_bool) return ixxbo(expr, to_type);
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_ENUM) return ixxen(expr, canonical, to_type, cast_type);
break;
case TYPE_I8:
case TYPE_I16:
@@ -726,5 +775,6 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
if (canonical->type_kind == TYPE_POINTER) return sapt(expr, from_type, canonical, to_type, cast_type);
break;
}
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
return sema_type_mismatch(expr, canonical, cast_type);
}

View File

@@ -95,6 +95,7 @@ void compiler_compile(BuildTarget *target)
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
llvm_codegen_setup();
VECEACH(contexts, i)
{
Context *context = contexts[i];

View File

@@ -30,8 +30,6 @@ typedef struct _Expr Expr;
typedef struct _Module Module;
typedef struct _Type Type;
typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type);
typedef struct _BigInt
{
unsigned digit_count;
@@ -55,7 +53,11 @@ typedef struct
char* chars;
int len;
} string;
Decl *enum_constant;
Decl *error_constant;
};
// Valid type kinds:
// bool, ints, floats, string
TypeKind kind;
} ExprConst;
@@ -135,7 +137,7 @@ typedef struct
{
unsigned char bitsize;
unsigned char bytesize;
unsigned char min_alignment;
unsigned char abi_alignment;
unsigned char pref_alignment;
} TypeBuiltin;
@@ -224,7 +226,8 @@ typedef struct
typedef struct
{
uint32_t alignment;
uint32_t abi_alignment;
uint32_t id;
uint64_t size;
Decl **members;
} StructDecl;
@@ -235,7 +238,11 @@ typedef struct _VarDecl
unsigned id : 16;
VarDeclKind kind : 3;
TypeInfo *type_info;
Expr *init_expr;
union
{
Expr *init_expr;
Decl *parent;
};
void *backend_ref;
void *backend_debug_ref;
} VarDecl;
@@ -315,7 +322,6 @@ typedef struct
{
FunctionSignature function_signature;
TypeInfo *type_info;
Type *type;
};
} TypedefDecl;
@@ -363,7 +369,11 @@ typedef struct _Decl
{
struct
{
Decl** method_functions;
union
{
Decl* parent_struct;
Decl** method_functions;
};
union
{
ErrorDecl error;
@@ -459,8 +469,6 @@ typedef struct
Token sub_element;
Decl *ref;
};
// TODO cleanup
int index;
} ExprAccess;
typedef struct
@@ -499,6 +507,32 @@ typedef struct
Ast **stmts;
} ExprFuncBlock;
typedef enum
{
INITIALIZER_UNKNOWN,
INITIALIZER_ZERO,
INITIALIZER_DESIGNATED,
INITIALIZER_NORMAL
} InitializerType;
typedef struct
{
InitializerType init_type;
Expr** initializer_expr;
} ExprInitializer;
typedef struct _DesignatedInitPath
{
Decl *decl;
struct _DesignatedInitPath *sub_path;
} DesignatedInitPath;
typedef struct
{
DesignatedInitPath path;
Expr *value;
} ExprDesignatedInit;
struct _Expr
{
ExprKind expr_kind : 8;
@@ -506,6 +540,7 @@ struct _Expr
SourceRange span;
Type *type;
union {
ExprDesignatedInit designated_init_expr;
ExprCast cast_expr;
ExprConst const_expr;
ExprStructValue struct_value_expr;
@@ -521,7 +556,7 @@ struct _Expr
ExprAccess access_expr;
ExprIdentifier identifier_expr;
ExprType type_expr;
Expr** initializer_expr;
ExprInitializer expr_initializer;
Expr** expression_list;
ExprScope expr_scope;
ExprFuncBlock expr_block;
@@ -809,6 +844,7 @@ typedef struct _Context
Decl **ct_ifs;
Ast **defers;
Decl *active_function_for_analysis;
Decl *active_type_for_analysis;
Decl **last_local;
Ast **labels;
Ast **gotos;
@@ -884,14 +920,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 t_i8, t_i16, t_i32, t_i64, t_isz, t_ixx;
extern Type t_u1, t_u8, t_u16, t_u32, t_u64, t_usz, t_uxx;
extern Type t_f32, t_f64, t_fxx;
extern Type t_u0, t_str;
extern Type t_cus, t_cui, t_cul, t_cull;
extern Type t_cs, t_ci, t_cl, t_cll;
extern Type t_voidstar;
extern Type *type_typeid, *type_error;
extern const char *main_name;
@@ -976,7 +1005,7 @@ bool cast_to_runtime(Expr *expr);
void cast_to_smallest_runtime(Expr *expr);
void llvm_codegen(Context *context);
void llvm_set_struct_size_alignment(Decl *decl);
void llvm_codegen_setup();
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr);
@@ -1139,17 +1168,48 @@ 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);
void type_append_signature_name(Type *type, char *dst, size_t *offset);
Type *type_find_max_type(Type *type, Type *other);
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64; }
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; }
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
bool type_may_have_method_functions(Type *type);
static inline Type *type_reduced(Type *type)
{
Type *canonical = type->canonical;
if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical;
if (canonical->type_kind == TYPE_ERROR) return type_error->canonical;
return canonical;
}
static inline bool type_is_structlike(Type *type)
{
assert(type->canonical = type);
switch (type->type_kind)
{
case TYPE_UNION:
case TYPE_STRUCT:
return true;
default:
return false;
}
}
static inline Type *type_reduced_from_expr(Expr *expr)
{
return type_reduced(expr->type);
}
static inline bool type_is_integer(Type *type)
{
assert(type == type->canonical);

View File

@@ -220,11 +220,10 @@ typedef enum
EXPR_IDENTIFIER,
EXPR_TYPE_ACCESS,
EXPR_CALL,
EXPR_GROUP,
EXPR_SIZEOF,
EXPR_SUBSCRIPT,
EXPR_ACCESS,
EXPR_STRUCT_VALUE,
EXPR_STRUCT_INIT_VALUES,
EXPR_INITIALIZER_LIST,
EXPR_EXPRESSION_LIST,
EXPR_CAST,

View File

@@ -46,7 +46,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl
}
// TODO fix name
decl->var.backend_ref = LLVMAddGlobal(context->module, decl->type->backend_type, decl->name);
decl->var.backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->name);
// If read only: LLVMSetGlobalConstant(decl->var.backend_ref, 1);
@@ -155,8 +155,39 @@ static int get_inlining_threshold(void)
return 250;
}
}
static inline unsigned lookup_intrinsic(const char *name)
{
return LLVMLookupIntrinsicID(name, strlen(name));
}
static bool intrinsics_setup = false;
unsigned ssub_overflow_intrinsic_id;
unsigned usub_overflow_intrinsic_id;
unsigned sadd_overflow_intrinsic_id;
unsigned uadd_overflow_intrinsic_id;
unsigned smul_overflow_intrinsic_id;
unsigned umul_overflow_intrinsic_id;
unsigned trap_intrinsic_id;
void llvm_codegen_setup()
{
assert(intrinsics_setup == false);
ssub_overflow_intrinsic_id = lookup_intrinsic("llvm.ssub.with.overflow");
usub_overflow_intrinsic_id = lookup_intrinsic("llvm.usub.with.overflow");
sadd_overflow_intrinsic_id = lookup_intrinsic("llvm.sadd.with.overflow");
uadd_overflow_intrinsic_id = lookup_intrinsic("llvm.uadd.with.overflow");
smul_overflow_intrinsic_id = lookup_intrinsic("llvm.smul.with.overflow");
umul_overflow_intrinsic_id = lookup_intrinsic("llvm.umul.with.overflow");
trap_intrinsic_id = lookup_intrinsic("llvm.trap");
intrinsics_setup = true;
}
void llvm_codegen(Context *context)
{
assert(intrinsics_setup);
GenContext gen_context;
gencontext_init(&gen_context, context);
gencontext_begin_module(&gen_context);

View File

@@ -13,7 +13,26 @@ static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *ty
return LLVMBuildAdd(context->builder, left, right, "add_mod");
}
// TODO insert trap
if (build_options.debug_mode)
{
LLVMTypeRef type_to_use = llvm_type(type->canonical);
LLVMTypeRef types[2] = { type_to_use, type_to_use };
LLVMValueRef args[2] = { left, right };
assert(type->canonical == type);
LLVMValueRef add_res;
if (type_is_unsigned(type))
{
add_res = gencontext_emit_call_intrinsic(context, uadd_overflow_intrinsic_id, types, args, 2);
}
else
{
add_res = gencontext_emit_call_intrinsic(context, sadd_overflow_intrinsic_id, types, args, 2);
}
LLVMValueRef result = LLVMBuildExtractValue(context->builder, add_res, 0, "");
LLVMValueRef ok = LLVMBuildExtractValue(context->builder, add_res, 1, "");
gencontext_emit_panic_on_true(context, ok, "Addition overflow");
return result;
}
return type_is_unsigned_integer(type)
? LLVMBuildNUWAdd(context->builder, left, right, "uadd")
: LLVMBuildNSWAdd(context->builder, left, right, "add");
@@ -26,25 +45,43 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty
return LLVMBuildSub(context->builder, left, right, "sub_mod");
}
// TODO insert trap
if (build_options.debug_mode)
{
LLVMTypeRef type_to_use = llvm_type(type);
LLVMTypeRef types[2] = { type_to_use, type_to_use };
LLVMValueRef args[2] = { left, right };
assert(type->canonical == type);
LLVMValueRef add_res;
if (type_is_unsigned(type))
{
add_res = gencontext_emit_call_intrinsic(context, usub_overflow_intrinsic_id, types, args, 2);
}
else
{
add_res = gencontext_emit_call_intrinsic(context, ssub_overflow_intrinsic_id, types, args, 2);
}
LLVMValueRef result = LLVMBuildExtractValue(context->builder, add_res, 0, "");
LLVMValueRef ok = LLVMBuildExtractValue(context->builder, add_res, 1, "");
gencontext_emit_panic_on_true(context, ok, "Subtraction overflow");
return result;
}
return type_is_unsigned_integer(type)
? LLVMBuildNUWSub(context->builder, left, right, "usub")
: LLVMBuildNSWSub(context->builder, left, right, "sub");
}
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext *context, LLVMValueRef parent, Type *parent_type, Expr *index_expr)
{
LLVMValueRef index = gencontext_emit_expr(context, expr->subscript_expr.index);
Type *type = expr->subscript_expr.expr->type->canonical;
switch (type->type_kind)
assert(parent_type->canonical == parent_type);
LLVMValueRef index = gencontext_emit_expr(context, index_expr);
switch (parent_type->type_kind)
{
case TYPE_ARRAY:
TODO
case TYPE_POINTER:
return LLVMBuildGEP2(context->builder,
llvm_type(type->pointer),
gencontext_emit_expr(context, expr->subscript_expr.expr),
&index, 1, "[]");
llvm_type(parent_type->pointer),
parent, &index, 1, "[]");
case TYPE_ARRAY:
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
case TYPE_STRING:
@@ -52,12 +89,48 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
default:
UNREACHABLE
}
}
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
{
LLVMValueRef parent = gencontext_emit_expr(context, expr->subscript_expr.expr);
return gencontext_emit_subscript_addr_from_value(context, parent, expr->subscript_expr.expr->type->canonical, expr->subscript_expr.index);
}
static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member)
{
unsigned index;
Decl *current_parent;
if (decl_is_struct_type(member))
{
index = member->strukt.id;
current_parent = member->parent_struct;
}
else
{
index = member->var.id;
current_parent = member->var.parent;
}
assert(current_parent);
if (parent != current_parent)
{
value = gencontext_emit_member_addr(context, value, parent, current_parent);
}
if (current_parent->decl_kind == DECL_UNION)
{
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "unionref");
}
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "structref");
}
static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr)
{
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
return LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
Expr *parent = expr->access_expr.parent;
LLVMValueRef value = gencontext_emit_address(context, parent);
Decl *member = expr->access_expr.ref;
return gencontext_emit_member_addr(context, value, parent->type->canonical->decl, member);
}
LLVMValueRef gencontext_emit_scoped_expr(GenContext *context, Expr *expr)
@@ -91,6 +164,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
return gencontext_emit_subscript_addr(context, expr);
case EXPR_SCOPED_EXPR:
return gencontext_emit_scoped_expr_address(context, expr);
case EXPR_GROUP:
return gencontext_emit_address(context, expr->group_expr);
case EXPR_CONST:
case EXPR_TYPE:
case EXPR_POISONED:
@@ -101,12 +176,11 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
case EXPR_POST_UNARY:
case EXPR_TYPE_ACCESS:
case EXPR_CALL:
case EXPR_STRUCT_VALUE:
case EXPR_STRUCT_INIT_VALUES:
case EXPR_INITIALIZER_LIST:
case EXPR_EXPRESSION_LIST:
case EXPR_CAST:
case EXPR_MACRO_EXPR:
case EXPR_DESIGNATED_INIT:
UNREACHABLE
}
UNREACHABLE
@@ -178,9 +252,93 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical);
}
static inline LLVMValueRef gencontext_emit_designated_initializer(GenContext *context, Type *parent_type, LLVMValueRef parent, Expr *expr)
{
assert(parent_type == parent_type->canonical);
switch (expr->expr_kind)
{
case EXPR_SUBSCRIPT:
if (expr->subscript_expr.expr)
{
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->subscript_expr.expr);
parent_type = expr->subscript_expr.expr->type->canonical;
}
return gencontext_emit_subscript_addr_from_value(context, parent, parent_type, expr->subscript_expr.index);
case EXPR_ACCESS:
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->access_expr.parent);
parent_type = expr->subscript_expr.expr->type->canonical;
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->access_expr.ref);
case EXPR_IDENTIFIER:
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->identifier_expr.decl);
default:
UNREACHABLE
}
}
/**
* Emit a Foo { .... } literal.
*
* 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)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef ref = gencontext_emit_alloca(context, type, "literal");
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 ref;
}
Expr **elements = expr->expr_initializer.initializer_expr;
bool is_union = expr->type->canonical->type_kind == TYPE_UNION;
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
{
if (is_union)
{
assert(vec_size(elements) == 1);
LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]);
LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), "");
LLVMBuildStore(context->builder, init_value, u);
return ref;
}
VECEACH(elements, i)
{
Expr *element = elements[i];
LLVMValueRef init_value = gencontext_emit_expr(context, element);
LLVMValueRef subref = LLVMBuildStructGEP2(context->builder, type, ref, i, "");
LLVMBuildStore(context->builder, init_value, subref);
}
return 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];
LLVMValueRef sub_value = gencontext_emit_expr(context, element->binary_expr.right);
LLVMValueRef sub_ref = gencontext_emit_designated_initializer(context, expr->type->canonical, ref, element->binary_expr.left);
LLVMBuildStore(context->builder, sub_value, sub_ref);
}
return ref;
}
static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff)
{
Type *type = expr->type->canonical;
Type *type = type_reduced_from_expr(expr);
LLVMTypeRef llvm_type = llvm_type(type);
if (type->type_kind == TYPE_POINTER)
@@ -221,32 +379,43 @@ static inline LLVMValueRef gencontext_emit_post_inc_dec(GenContext *context, Exp
LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
{
Type *type = type_reduced_from_expr(expr->unary_expr.expr);
switch (expr->unary_expr.operator)
{
case UNARYOP_ERROR:
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
case UNARYOP_NOT:
return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(type_bool->backend_type, 1, 0), "not");
return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(llvm_type(type_bool), 1, 0), "not");
case UNARYOP_BITNEG:
return LLVMBuildNot(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "bnot");
case UNARYOP_NEGMOD:
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "negmod");
case UNARYOP_NEG:
// TODO improve how unsigned numbers are negated.
if (type_is_float(expr->unary_expr.expr->type->canonical))
if (type_is_float(type))
{
return LLVMBuildFNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "fneg");
}
if (type_is_unsigned(expr->unary_expr.expr->type->canonical))
assert(!type_is_unsigned(type));
{
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
LLVMValueRef to_negate = gencontext_emit_expr(context, expr->unary_expr.expr);
LLVMValueRef zero = LLVMConstInt(llvm_type(expr->unary_expr.expr->type->canonical), 0, false);
if (build_options.debug_mode)
{
LLVMTypeRef type_to_use = llvm_type(type->canonical);
LLVMValueRef args[2] = { zero, to_negate };
LLVMTypeRef types[2] = { type_to_use, type_to_use };
LLVMValueRef call_res = gencontext_emit_call_intrinsic(context, ssub_overflow_intrinsic_id, types, args, 2);
LLVMValueRef result = LLVMBuildExtractValue(context->builder, call_res, 0, "");
LLVMValueRef ok = LLVMBuildExtractValue(context->builder, call_res, 1, "");
gencontext_emit_panic_on_true(context, ok, "Signed negation overflow");
return result;
}
return LLVMBuildNSWSub(context->builder, zero, to_negate, "neg");
}
// TODO insert trap
return LLVMBuildNSWNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
case UNARYOP_ADDR:
return gencontext_emit_address(context, expr->unary_expr.expr);
case UNARYOP_DEREF:
return LLVMBuildLoad2(context->builder, llvm_type(expr->unary_expr.expr->type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
return LLVMBuildLoad2(context->builder, llvm_type(type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
case UNARYOP_INC:
return gencontext_emit_pre_inc_dec(context, expr->unary_expr.expr, 1, false);
case UNARYOP_DEC:
@@ -285,7 +454,7 @@ static LLVMValueRef gencontext_emit_logical_and_or(GenContext *context, Expr *ex
// Generate phi
gencontext_emit_block(context, phi_block);
LLVMValueRef phi = LLVMBuildPhi(context->builder, type_bool->backend_type, "val");
LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(type_bool), "val");
// Simplify for LLVM by entering the constants we already know of.
LLVMValueRef result_on_skip = LLVMConstInt(LLVMInt1TypeInContext(context->context), op == BINARYOP_AND ? 0 : 1, false);
@@ -440,7 +609,6 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
{
return gencontext_emit_logical_and_or(context, expr, binary_op);
}
Type *type = expr->type->canonical;
Expr *lhs = expr->binary_expr.left;
Expr *rhs = expr->binary_expr.right;
@@ -456,10 +624,10 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
}
rhs_value = gencontext_emit_expr(context, rhs);
Type *lhs_type = expr->binary_expr.left->type->canonical;
Type *lhs_type = type_reduced_from_expr(lhs);
if (type_is_integer(lhs_type) && binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ)
{
return gencontext_emit_int_comparison(context, lhs_type, rhs->type->canonical, lhs_value, rhs_value, binary_op);
return gencontext_emit_int_comparison(context, lhs_type, type_reduced_from_expr(rhs), lhs_value, rhs_value, binary_op);
}
bool is_float = type_is_float(lhs_type);
switch (binary_op)
@@ -468,15 +636,33 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
UNREACHABLE
case BINARYOP_MULT:
if (is_float) return LLVMBuildFMul(context->builder, lhs_value, rhs_value, "fmul");
// TODO insert trap
if (type_is_unsigned_integer(lhs_type))
{
if (build_options.debug_mode)
{
LLVMTypeRef type_to_use = llvm_type(lhs_type);
LLVMValueRef args[2] = { lhs_value, rhs_value };
LLVMTypeRef types[2] = { type_to_use, type_to_use };
LLVMValueRef call_res = gencontext_emit_call_intrinsic(context, umul_overflow_intrinsic_id, types, args, 2);
LLVMValueRef result = LLVMBuildExtractValue(context->builder, call_res, 0, "");
LLVMValueRef ok = LLVMBuildExtractValue(context->builder, call_res, 1, "");
gencontext_emit_panic_on_true(context, ok, "Unsigned multiplication overflow");
return result;
}
return LLVMBuildNUWMul(context->builder, lhs_value, rhs_value, "umul");
}
else
if (build_options.debug_mode)
{
return LLVMBuildNSWMul(context->builder, lhs_value, rhs_value, "mul");
LLVMTypeRef type_to_use = llvm_type(lhs_type);
LLVMValueRef args[2] = { lhs_value, rhs_value };
LLVMTypeRef types[2] = { type_to_use, type_to_use };
LLVMValueRef call_res = gencontext_emit_call_intrinsic(context, smul_overflow_intrinsic_id, types, args, 2);
LLVMValueRef result = LLVMBuildExtractValue(context->builder, call_res, 0, "");
LLVMValueRef ok = LLVMBuildExtractValue(context->builder, call_res, 1, "");
gencontext_emit_panic_on_true(context, ok, "Signed multiplication overflow");
return result;
}
return LLVMBuildNSWMul(context->builder, lhs_value, rhs_value, "mul");
case BINARYOP_MULT_MOD:
return LLVMBuildMul(context->builder, lhs_value, rhs_value, "mul");
case BINARYOP_SUB:
@@ -520,28 +706,27 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
case BINARYOP_BIT_XOR:
return LLVMBuildXor(context->builder, lhs_value, rhs_value, "xor");
case BINARYOP_EQ:
assert(!type_is_integer(lhs_type));
// Unordered?
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealUEQ, lhs_value, rhs_value, "eq");
case BINARYOP_NE:
assert(!type_is_integer(lhs_type));
// Unordered?
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealUNE, lhs_value, rhs_value, "neq");
case BINARYOP_GE:
assert(!type_is_integer(lhs_type));
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealUGE, lhs_value, rhs_value, "ge");
case BINARYOP_GT:
assert(!type_is_integer(lhs_type));
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealUGT, lhs_value, rhs_value, "gt");
case BINARYOP_LE:
assert(!type_is_integer(lhs_type));
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "le");
case BINARYOP_LT:
assert(!type_is_integer(lhs_type));
assert(type_is_float(lhs_type));
return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "lt");
case BINARYOP_AND:
case BINARYOP_OR:
UNREACHABLE
case BINARYOP_ASSIGN:
case BINARYOP_MULT_ASSIGN:
case BINARYOP_MULT_MOD_ASSIGN:
@@ -581,10 +766,6 @@ 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);
if (expr->binary_expr.right->expr_kind == EXPR_INITIALIZER_LIST)
{
return gencontext_emit_initialization_from_expr(context, addr, expr->binary_expr.right);
}
LLVMValueRef value = gencontext_emit_expr(context, expr->binary_expr.right);
LLVMBuildStore(context->builder, value, addr);
return value;
@@ -616,7 +797,7 @@ LLVMValueRef gencontext_emit_elvis_expr(GenContext *context, Expr *expr)
// Generate phi
gencontext_emit_block(context, phi_block);
LLVMValueRef phi = LLVMBuildPhi(context->builder, expr->type->backend_type, "val");
LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(expr->type), "val");
LLVMValueRef logic_values[2] = { lhs, rhs };
LLVMBasicBlockRef blocks[2] = { current_block, rhs_block };
@@ -649,24 +830,19 @@ LLVMValueRef gencontext_emit_ternary_expr(GenContext *context, Expr *expr)
// Generate phi
gencontext_emit_block(context, phi_block);
LLVMValueRef phi = LLVMBuildPhi(context->builder, expr->type->backend_type, "val");
LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(expr->type), "val");
LLVMValueRef logicValues[2] = { lhs, rhs };
LLVMValueRef logic_values[2] = { lhs, rhs };
LLVMBasicBlockRef blocks[2] = { lhs_block, rhs_block };
LLVMAddIncoming(phi, logicValues, blocks, 2);
LLVMAddIncoming(phi, logic_values, blocks, 2);
return phi;
}
static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr)
{
return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type,
expr->identifier_expr.decl->var.backend_ref, expr->identifier_expr.decl->name);
}
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMTypeRef type = llvm_type(type_reduced_from_expr(expr));
switch (expr->const_expr.kind)
{
case ALL_INTS:
@@ -731,7 +907,7 @@ static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr
{
// Improve, add string description to the access?
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, expr->access_expr.ref->var.id, "");
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
}
@@ -745,31 +921,6 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont
return value;
}
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef value = LLVMGetUndef(type);
if (!vec_size(expr->initializer_expr))
{
LLVMValueRef ref = gencontext_emit_alloca(context, type, "temp");
value = 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.alignment);
return ref;
}
VECEACH(expr->initializer_expr, i)
{
LLVMValueRef init_value = gencontext_emit_expr(context, expr->initializer_expr[i]);
value = LLVMBuildInsertValue(context->builder, value, init_value, i, "literal");
}
return value;
}
static inline LLVMValueRef gencontext_emit_struct_init_values_expr(GenContext *context, Expr *expr)
{
TODO
}
static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr *expr)
{
@@ -802,12 +953,24 @@ static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr
return return_out;
}
LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrinsic_id, LLVMTypeRef *types,
LLVMValueRef *values, unsigned arg_count)
{
LLVMValueRef decl = LLVMGetIntrinsicDeclaration(context->module, intrinsic_id, types, arg_count);
LLVMTypeRef type = LLVMIntrinsicGetType(context->context, intrinsic_id, types, arg_count);
return LLVMBuildCall2(context->builder, type, decl, values, arg_count, "");
}
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_POISONED:
UNREACHABLE
case EXPR_DESIGNATED_INIT:
// This is handled inside of initializer setup
UNREACHABLE
case EXPR_EXPR_BLOCK:
return gencontext_emit_expr_block(context, expr);
case EXPR_SCOPED_EXPR:
@@ -834,12 +997,10 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
return gencontext_load_expr(context, gencontext_emit_address(context, expr));
case EXPR_CALL:
return gencontext_emit_call_expr(context, expr);
case EXPR_GROUP:
return gencontext_emit_expr(context, expr->group_expr);
case EXPR_ACCESS:
return gencontext_emit_access_expr(context, expr);
case EXPR_STRUCT_VALUE:
return gencontext_emit_struct_value_expr(context, expr);
case EXPR_STRUCT_INIT_VALUES:
return gencontext_emit_struct_init_values_expr(context, expr);
case EXPR_INITIALIZER_LIST:
return gencontext_emit_initializer_list_expr(context, expr);
case EXPR_EXPRESSION_LIST:

View File

@@ -68,10 +68,20 @@ typedef struct
bool did_call_stack_save : 1;
} GenContext;
extern unsigned sadd_overflow_intrinsic_id;
extern unsigned uadd_overflow_intrinsic_id;
extern unsigned ssub_overflow_intrinsic_id;
extern unsigned usub_overflow_intrinsic_id;
extern unsigned smul_overflow_intrinsic_id;
extern unsigned umul_overflow_intrinsic_id;
extern unsigned trap_intrinsic_id;
void gencontext_begin_module(GenContext *context);
void gencontext_end_module(GenContext *context);
void gencontext_emit_stmt(GenContext *context, Ast *ast);
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);

View File

@@ -23,7 +23,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
Decl *decl = ast->declare_stmt;
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(type_reduced(decl->type)), decl->name);
// TODO NRVO
// TODO debug info
/*
@@ -44,11 +44,11 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
Expr *expr = decl->var.init_expr;
// Quick path for empty initializer list
if (expr->expr_kind == EXPR_INITIALIZER_LIST && vec_size(expr->initializer_expr) == 0)
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.alignment);
expr->type->decl->strukt.abi_alignment);
return decl->var.backend_ref;
}
@@ -600,6 +600,18 @@ void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
gencontext_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
}
void gencontext_emit_panic_on_true(GenContext *context, LLVMValueRef value, const char *panic_name)
{
LLVMBasicBlockRef panic_block = gencontext_create_free_block(context, "panic");
LLVMBasicBlockRef ok_block = gencontext_create_free_block(context, "checkok");
gencontext_emit_cond_br(context, value, panic_block, ok_block);
gencontext_emit_block(context, panic_block);
gencontext_emit_call_intrinsic(context, trap_intrinsic_id, NULL, NULL, 0);
gencontext_emit_br(context, ok_block);
gencontext_emit_block(context, ok_block);
}
void gencontext_emit_stmt(GenContext *context, Ast *ast)
{
switch (ast->ast_kind)

View File

@@ -38,7 +38,7 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
}
case DECL_TYPEDEF:
return llvm_get_type(context, decl->typedef_decl.type);
return llvm_get_type(context, decl->typedef_decl.type_info->type);
case DECL_STRUCT:
{
LLVMTypeRef *types = NULL;
@@ -52,20 +52,28 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
}
case DECL_UNION:
{
LLVMTypeRef max_type = NULL;
Decl *max_type = NULL;
unsigned long long max_size = 0;
VECEACH(decl->strukt.members, i)
{
LLVMTypeRef type = llvm_get_type(context, decl->strukt.members[i]->type);
unsigned long long size = LLVMStoreSizeOfType(target_data_layout(), type);
Decl *member = decl->strukt.members[i];
unsigned size = type_size(member->type);
if (size > max_size || !max_type)
{
max_size = size;
max_type = type;
max_type = member;
}
}
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
LLVMStructSetBody(type, &max_type, 1, false);
if (max_type)
{
LLVMTypeRef type_ref = llvm_get_type(context, max_type->type);
LLVMStructSetBody(type, &type_ref, 1, false);
}
else
{
LLVMStructSetBody(type, NULL, 0, true);
}
return type;
}
case DECL_ENUM:
@@ -155,14 +163,20 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
{
case TYPE_POISONED:
case TYPE_META_TYPE:
case TYPE_ENUM:
case TYPE_ERROR:
UNREACHABLE;
case TYPE_TYPEDEF:
return type->backend_type = llvm_get_type(context, type->canonical);
case TYPE_ERROR_UNION:
{
LLVMTypeRef types[2];
types[0] = llvm_get_type(context, type_typeid->canonical);
types[1] = llvm_get_type(context, type_error->canonical);
return type->backend_type = LLVMStructType(types, 2, false);
}
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM:
case TYPE_ERROR:
case TYPE_ERROR_UNION:
return type->backend_type = llvm_type_from_decl(context, type->decl);
case TYPE_FUNC:
return type->backend_type = llvm_func_type(context, type);
@@ -216,9 +230,3 @@ LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type)
return llvm_get_type(context->context, type);
}
void llvm_set_struct_size_alignment(Decl *decl)
{
LLVMTypeRef type = llvm_get_type(LLVMGetGlobalContext(), decl->type);
decl->strukt.size = LLVMStoreSizeOfType(target_data_layout(), type);
decl->strukt.alignment = LLVMPreferredAlignmentOfType(target_data_layout(), type);
}

View File

@@ -34,19 +34,6 @@ static int type_bits[TYPE_U64 + 1] = {
[TYPE_I64] = 64,
};
static int64_t int_type_max[TYPE_I64 + 1] = {
[TYPE_I8] = 0x7F,
[TYPE_I16] = 0x7FFF,
[TYPE_I32] = 0x7FFFFFFFLL,
[TYPE_I64] = 0x7FFFFFFFFFFFFFFFLL,
};
static int64_t int_type_min[TYPE_I64 + 1] = {
[TYPE_I8] = -0x80,
[TYPE_I16] = -0x8000L,
[TYPE_I32] = -0x80000000L,
[TYPE_I64] = -0x8000000000000000LL,
};
void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
{
@@ -74,6 +61,12 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
case TYPE_FXX:
fprintf(file, "%Lf", expr->f);
break;
case TYPE_ENUM:
fprintf(file, "%s", expr->enum_constant->name);
break;
case TYPE_ERROR:
fprintf(file, "%s", expr->error_constant->name);
break;
default:
UNREACHABLE
}
@@ -172,6 +165,7 @@ static inline bool compare_fps(long double left, long double right, BinaryOp op)
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op)
{
bool is_eq;
switch (left->kind)
{
case TYPE_BOOL:
@@ -183,10 +177,23 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
case TYPE_POINTER:
return true;
case TYPE_STRING:
TODO
if (left->string.len != right->string.len)
{
is_eq = false;
break;
}
if (right->string.chars == left->string.chars)
{
is_eq = true;
break;
}
is_eq = strncmp(left->string.chars, right->string.chars, left->string.len);
break;
default:
UNREACHABLE
}
assert(op == BINARYOP_EQ || op == BINARYOP_NE);
return op == BINARYOP_EQ == is_eq;
}
bool expr_const_int_overflowed(const ExprConst *expr)
@@ -239,6 +246,15 @@ const char *expr_const_to_error_string(const ExprConst *expr)
case TYPE_FXX:
asprintf(&buff, "%Lf", expr->f);
return buff;
case TYPE_ENUM:
asprintf(&buff, "%s.%s", expr->enum_constant->type->name, expr->enum_constant->name);
return buff;
case TYPE_ERROR:
asprintf(&buff, "%s.%s", expr->error_constant->type->name, expr->error_constant->name);
return buff;
case TYPE_STRING:
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
return buff;
default:
UNREACHABLE
}

View File

@@ -208,10 +208,12 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side)
static Expr *parse_grouping_expr(Context *context, Expr *left)
{
assert(!left && "Unexpected left hand side");
Expr *expr = expr_new(EXPR_GROUP, context->tok.span);
advance_and_verify(context, TOKEN_LPAREN);
Expr *right = TRY_EXPR_OR(parse_expr(context), &poisoned_expr);
expr->group_expr = TRY_EXPR_OR(parse_expr(context), &poisoned_expr);
CONSUME_OR(TOKEN_RPAREN, &poisoned_expr);
return right;
RANGE_EXTEND_PREV(expr);
return expr;
}
/**
@@ -249,8 +251,9 @@ Expr *parse_initializer(Context *context)
Expr *parse_initializer_list(Context *context)
{
Expr *initializer_list = EXPR_NEW_TOKEN(EXPR_INITIALIZER_LIST, context->tok);
initializer_list->expr_initializer.init_type = INITIALIZER_UNKNOWN;
CONSUME_OR(TOKEN_LBRACE, &poisoned_expr);
if (!parse_param_list(context, &initializer_list->initializer_expr, false)) return &poisoned_expr;
if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr;
CONSUME_OR(TOKEN_RBRACE, &poisoned_expr);
return initializer_list;
}
@@ -324,6 +327,8 @@ static Expr *parse_access_expr(Context *context, Expr *left)
access_expr->access_expr.parent = left;
access_expr->access_expr.sub_element = context->tok;
TRY_CONSUME_OR(TOKEN_IDENT, "Expected identifier", &poisoned_expr);
access_expr->span = left->span;
access_expr->span.end_loc = access_expr->access_expr.sub_element.span.end_loc;
return access_expr;
}

View File

@@ -891,7 +891,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
{
if (context->tok.type != TOKEN_COMMA && context->tok.type != TOKEN_RPAREN)
{
SEMA_TOKEN_ERROR(context->tok, "Unexpected end of the parameter list, did you forget an ')'?");
sema_error_at(context->prev_tok_end, "Unexpected end of the parameter list, did you forget an ')'?");
return false;
}
SEMA_ERROR(type, "The function parameter must be named.");
@@ -989,11 +989,11 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
Decl *member;
if (context->next_tok.type != TOKEN_IDENT)
{
Token name_replacement = context->tok;
name_replacement.string = NULL;
member = decl_new_with_type(name_replacement, decl_kind, parent->visibility);
advance(context);
}
Token name_replacement = context->tok;
name_replacement.string = NULL;
member = decl_new_with_type(name_replacement, decl_kind, parent->visibility);
advance(context);
}
else
{
advance(context);
@@ -1010,6 +1010,8 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
advance_and_verify(context, TOKEN_IDENT);
}
if (!parse_attributes(context, member)) return false;
member->parent_struct = parent;
member->strukt.id = vec_size(parent->strukt.members);
parent->strukt.members = VECADD(parent->strukt.members, member);
if (!parse_struct_body(context, member, context->tok.type == TOKEN_IDENT ? member : visible_parent))
{
@@ -1033,7 +1035,10 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
decl_poison(other);
decl_poison(member);
}
unsigned index = vec_size(parent->strukt.members);
parent->strukt.members = VECADD(parent->strukt.members, member);
member->var.id = index;
member->var.parent = parent;
advance(context);
if (context->tok.type != TOKEN_COMMA) break;
}
@@ -1955,6 +1960,7 @@ void parse_file(Context *context)
static Expr *parse_type_access(Context *context, TypeInfo *type)
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE_ACCESS, context->tok);
expr->span = type->span;
expr->type_access.type = type;
advance_and_verify(context, TOKEN_DOT);
@@ -1966,6 +1972,7 @@ static Expr *parse_type_access(Context *context, TypeInfo *type)
case TOKEN_IDENT:
case TOKEN_CONST_IDENT:
advance(context);
RANGE_EXTEND_PREV(expr);
return expr;
default:
SEMA_TOKEN_ERROR(context->tok, "Expected a function name, macro, or constant.");
@@ -1992,11 +1999,7 @@ Expr *parse_type_identifier_with_path(Context *context, Path *path)
RANGE_EXTEND_PREV(type);
if (context->tok.type == TOKEN_LBRACE)
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, context->tok);
expr->struct_value_expr.type = type;
expr->struct_value_expr.init_expr = TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr);
return expr;
return TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr);
}
EXPECT_OR(TOKEN_DOT, &poisoned_expr);
return parse_type_access(context, type);

View File

@@ -31,15 +31,64 @@ static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
break;
}
}
constant->error_constant.value = i;
constant->error_constant.value = i + 1;
constant->resolve_status = RESOLVE_DONE;
}
return success;
}
static inline void sema_set_struct_size(Decl *decl)
{
// TODO packed
uint64_t size = 0;
uint64_t alignment = 0;
VECEACH(decl->strukt.members, i)
{
Decl *member = decl->strukt.members[i];
Type *canonical = member->type->canonical;
uint64_t member_size = type_size(canonical);
uint64_t member_alignment = type_abi_alignment(canonical);
assert(member_size > 0);
// Add padding.
if (member_alignment && (size % member_alignment))
{
size += member_alignment - size % member_alignment;
}
// Add size.
size += member_size;
if (member_alignment > alignment) alignment = member_alignment;
}
decl->strukt.abi_alignment = alignment;
if (alignment && size % alignment)
{
size += alignment - size % alignment;
}
decl->strukt.size = size;
}
static inline void sema_set_union_size(Decl *decl)
{
uint64_t size = 0;
uint64_t alignment = 0;
VECEACH(decl->strukt.members, i)
{
Decl *member = decl->strukt.members[i];
Type *canonical = member->type->canonical;
uint64_t member_size = type_size(canonical);
uint64_t member_alignment = type_abi_alignment(canonical);
if (member_size > size) size = member_size;
if (member_alignment > alignment) alignment = member_alignment;
}
decl->strukt.abi_alignment = alignment;
decl->strukt.size = size;
}
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
{
assert(decl->resolve_status == RESOLVE_NOT_DONE);
decl->resolve_status = RESOLVE_RUNNING;
if (decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION)
{
DEBUG_LOG("Beginning analysis of inner struct/union");
@@ -61,12 +110,19 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
decl_poison(decl);
}
}
if (decl->decl_kind == DECL_UNION)
{
sema_set_union_size(decl);
}
else
{
sema_set_struct_size(decl);
}
DEBUG_LOG("Analysis complete.");
return decl_ok(decl);
}
assert(decl->decl_kind == DECL_VAR);
assert(decl->var.kind == VARDECL_MEMBER);
assert(!decl->var.init_expr);
if (!sema_resolve_type_info(context, decl->var.type_info))
{
decl_poison(decl);
@@ -74,6 +130,7 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
}
decl->type = decl->var.type_info->type;
assert(decl->var.type_info->type);
decl->resolve_status = RESOLVE_DONE;
return true;
}
@@ -89,7 +146,7 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
decl_poison(decl);
continue;
}
if (!sema_analyse_struct_member(context, decl->strukt.members[i]))
if (!sema_analyse_struct_member(context, member))
{
if (decl_ok(decl))
{
@@ -235,7 +292,7 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl)
return true;
}
if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false;
decl->type->canonical = decl->typedef_decl.type_info->type;
decl->type->canonical = decl->typedef_decl.type_info->type->canonical;
// Do we need anything else?
return true;
}
@@ -246,7 +303,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
if (!sema_resolve_type_info(context, decl->enums.type_info)) return false;
Type *type = decl->enums.type_info->type;
Type *canonical = decl->enums.type_info->type;
Type *canonical = type->canonical;
// Require an integer type
if (!type_is_integer(canonical))
@@ -430,6 +487,7 @@ static inline bool sema_analyse_generic(Context *context, Decl *decl)
return true;
}
bool sema_analyse_decl(Context *context, Decl *decl)
{
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
@@ -450,9 +508,13 @@ bool sema_analyse_decl(Context *context, Decl *decl)
if (!sema_analyse_throws(context, decl)) return decl_poison(decl);
break;
case DECL_STRUCT:
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
sema_set_struct_size(decl);
decl_set_external_name(decl);
break;
case DECL_UNION:
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
llvm_set_struct_size_alignment(decl);
sema_set_union_size(decl);
decl_set_external_name(decl);
break;
case DECL_FUNC:

View File

@@ -49,6 +49,8 @@ static bool expr_is_ltype(Expr *expr)
return expr->unary_expr.operator == UNARYOP_DEREF;
case EXPR_ACCESS:
return expr_is_ltype(expr->access_expr.parent);
case EXPR_GROUP:
return expr_is_ltype(expr->group_expr);
case EXPR_SUBSCRIPT:
return true;
default:
@@ -114,15 +116,72 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
return true;
}
static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl)
{
VECEACH(decl->enums.values, i)
{
Decl *enum_constant = decl->enums.values[i];
if (enum_constant->name == name)
{
assert(enum_constant->resolve_status == RESOLVE_DONE);
expr->type = enum_constant->type;
expr->const_expr = enum_constant->enum_constant.expr->const_expr;
expr->expr_kind = EXPR_CONST;
return true;
}
}
return false;
}
static inline bool sema_expr_analyse_error_constant(Expr *expr, const char *name, Decl *decl)
{
VECEACH(decl->error.error_constants, i)
{
Decl *error_constant = decl->error.error_constants[i];
if (error_constant->name == name)
{
assert(error_constant->resolve_status == RESOLVE_DONE);
expr->type = decl->type;
expr->expr_kind = EXPR_CONST;
expr_const_set_int(&expr->const_expr, error_constant->error_constant.value, type_error->canonical->type_kind);
return true;
}
}
return false;
}
static inline bool find_possible_inferred_identifier(Type *to, Expr *expr)
{
if (to->canonical->type_kind != TYPE_ENUM && to->canonical->type_kind != TYPE_ERROR) return false;
Decl *parent_decl = to->canonical->decl;
switch (parent_decl->decl_kind)
{
case DECL_ENUM:
return sema_expr_analyse_enum_constant(expr, expr->identifier_expr.identifier, parent_decl);
case DECL_ERROR:
return sema_expr_analyse_error_constant(expr, expr->identifier_expr.identifier, parent_decl);
case DECL_UNION:
case DECL_STRUCT:
return false;
default:
UNREACHABLE
}
}
static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr *expr)
{
// TODO what about struct functions
Decl *ambiguous_decl;
Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier, expr->identifier_expr.path, &ambiguous_decl);
if (!decl && !expr->identifier_expr.path && to)
{
if (find_possible_inferred_identifier(to, expr)) return true;
}
if (!decl)
{
SEMA_ERROR(expr, "Unknown symbol '%s'.", expr->identifier_expr.identifier);
SEMA_ERROR(expr, "The symbol '%s' could not be found.", expr->identifier_expr.identifier);
return false;
}
@@ -163,6 +222,7 @@ static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Type *to,
static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr) { TODO }
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO };
static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl)
{
Expr **args =expr->call_expr.arguments;
@@ -221,15 +281,6 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
}
}
static inline bool sema_expr_analyse_struct_value(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_expr_analyse_struct_init_values(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr *expr)
{
@@ -284,58 +335,33 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp
return false;
}
static inline bool sema_expr_analyse_enum_constant(Context *context, Expr *expr, Decl *decl)
{
const char *name = expr->type_access.name.string;
VECEACH(decl->enums.values, i)
{
Decl *enum_constant = decl->enums.values[i];
if (enum_constant->name == name)
{
assert(enum_constant->resolve_status == RESOLVE_DONE);
expr_replace(expr, enum_constant->enum_constant.expr);
return true;
}
}
SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name);
return false;
}
static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr, Decl *decl)
{
const char *name = expr->type_access.name.string;
VECEACH(decl->error.error_constants, i)
{
Decl *error_constant = decl->error.error_constants[i];
if (error_constant->name == name)
{
assert(error_constant->resolve_status == RESOLVE_DONE);
expr->type = decl->type;
expr->expr_kind = EXPR_CONST;
expr_const_set_int(&expr->const_expr, decl->error_constant.value, TYPE_U32);
return true;
}
}
SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, name);
return false;
}
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int *index)
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
{
VECEACH(strukt->strukt.members, i)
{
(*index)++;
Decl *member = strukt->strukt.members[i];
if (member->name == name) return member;
if (!member->name && decl_is_struct_type(member))
if (!member->name && type_is_structlike(member->type->canonical))
{
Decl *result = strukt_recursive_search_member(member, name, index);
if (result) return result;
Decl *result = strukt_recursive_search_member(member->type->canonical->decl, name);
if (result)
{
return result;
}
}
}
return NULL;
}
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
{
if (!sema_analyse_expr(context, to, expr->group_expr)) return false;
*expr = *expr->group_expr;
return true;
}
static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false;
@@ -364,8 +390,7 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
default:
UNREACHABLE
}
int index = -1;
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string, &index);
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string);
if (!member)
{
SEMA_TOKEN_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name, expr->access_expr.sub_element.string);
@@ -381,7 +406,7 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
expr->access_expr.parent = deref;
}
expr->type = member->type;
expr->access_expr.index = index;
expr->access_expr.ref = member;
return true;
}
@@ -389,21 +414,38 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
{
TypeInfo *type_info = expr->type_access.type;
if (!sema_resolve_type_info(context, type_info)) return false;
if (!type_may_have_method_functions(type_info->type))
Type *canonical = type_info->type->canonical;
if (!type_may_have_method_functions(canonical))
{
SEMA_ERROR(expr, "'%s' does not have method functions.", type_to_error_string(type_info->type));
return false;
}
Decl *decl = type_info->type->decl;
Decl *decl = canonical->decl;
// TODO add more constants that can be inspected?
// e.g. SomeEnum.values, MyUnion.x.offset etc?
switch (decl->decl_kind)
{
case DECL_ENUM:
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_enum_constant(context, expr, decl);
if (expr->type_access.name.type == TOKEN_CONST_IDENT)
{
if (!sema_expr_analyse_enum_constant(expr, expr->type_access.name.string, decl))
{
SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, expr->type_access.name.string);
return false;
}
return true;
}
break;
case DECL_ERROR:
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_error_constant(context, expr, decl);
if (expr->type_access.name.type == TOKEN_CONST_IDENT)
{
if (!sema_expr_analyse_error_constant(expr, expr->type_access.name.string, decl))
{
SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, expr->type_access.name.string);
return false;
}
return true;
}
break;
case DECL_UNION:
case DECL_STRUCT:
@@ -448,9 +490,12 @@ static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *
{
assert(expr->resolve_status == RESOLVE_NOT_DONE);
expr->resolve_status = RESOLVE_RUNNING;
expr->identifier_expr.decl = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
Decl *res = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
if (!res) return NULL;
expr->identifier_expr.decl = res;
expr->resolve_status = RESOLVE_DONE;
return expr->identifier_expr.decl;
expr->type = res->type;
return res;
}
static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr)
@@ -465,6 +510,7 @@ static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *acce
}
decl = access_expr->access_expr.ref = sema_analyse_init_identifier_string(context, decl->type->decl, access_expr->access_expr.sub_element.string);
access_expr->resolve_status = RESOLVE_DONE;
access_expr->type = decl->type;
return decl;
}
@@ -492,77 +538,94 @@ static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr)
}
}
typedef enum
static bool sema_expr_analyse_struct_designated_initializer(Context *context, Decl *assigned, Expr *initializer)
{
INIT_SEMA_ERROR,
INIT_SEMA_NOT_FOUND,
INIT_SEMA_OK
} InitSemaResult;
Expr **init_expressions = initializer->expr_initializer.initializer_expr;
static InitSemaResult sema_expr_analyse_struct_named_initializer_list(Context *context, Decl *assigned, Expr *expr_list)
{
VECEACH(expr_list->initializer_expr, i)
VECEACH(init_expressions, i)
{
Expr *expr = expr_list->initializer_expr[i];
if (expr->expr_kind != EXPR_BINARY && expr->binary_expr.operator != BINARYOP_ASSIGN)
Expr *expr = init_expressions[i];
// 1. Ensure that're seeing expr = expr on the top level.
if (expr->expr_kind != EXPR_BINARY || expr->binary_expr.operator != BINARYOP_ASSIGN)
{
if (i != 0)
{
SEMA_ERROR(expr, "Named and non-named initializers are not allowed together, please choose one or the other.");
return INIT_SEMA_ERROR;
}
// If there is an unexpected expression and no previous element then this is a normal initializer list.
return INIT_SEMA_NOT_FOUND;
SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here.");
return false;
}
Expr *path = expr->binary_expr.left;
Expr *value = expr->binary_expr.right;
Decl *result = sema_analyse_init_path(context, assigned, path);
if (!result)
if (!sema_analyse_init_path(context, assigned, path))
{
if (i != 0)
{
SEMA_ERROR(path, "Unexpected element when initializing '%s', did you get the name right?", assigned->name);
return INIT_SEMA_ERROR;
}
return INIT_SEMA_NOT_FOUND;
SEMA_ERROR(path, "This is not a valid member of '%s'.", type_to_error_string(assigned->type));
return false;
}
if (!sema_analyse_expr_of_required_type(context, result->type, value)) return INIT_SEMA_ERROR;
Expr *value = expr->binary_expr.right;
if (!sema_analyse_expr_of_required_type(context, path->type, value)) return false;
expr->type = path->type;
}
return INIT_SEMA_OK;
initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED;
return true;
}
static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr)
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
{
Decl **members = assigned->decl->strukt.members;
unsigned size = vec_size(members);
// Zero size init will initialize to empty.
if (size == 0) return true;
Expr **elements = initializer->expr_initializer.initializer_expr;
Decl **members = assigned->strukt.members;
initializer->expr_initializer.init_type = INITIALIZER_NORMAL;
unsigned size = vec_size(elements);
unsigned expected_members = vec_size(members);
InitSemaResult result = sema_expr_analyse_struct_named_initializer_list(context, assigned->decl, expr);
if (result == INIT_SEMA_ERROR) return false;
if (result == INIT_SEMA_OK)
// For struct number of members must be the same as the size of the struct.
assert(size > 0);
if (expected_members == 0)
{
TODO
}
if (assigned->type_kind == TYPE_UNION)
{
SEMA_ERROR(expr->initializer_expr[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }");
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
return false;
}
if (size < vec_size(expr->initializer_expr))
bool is_union = assigned->decl_kind == DECL_UNION;
expected_members = is_union ? 1 : expected_members;
VECEACH(elements, i)
{
SEMA_ERROR(expr->initializer_expr[size], "Too many elements in initializer, expected only %d.", size);
if (i >= expected_members)
{
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
return false;
}
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false;
}
if (expected_members > size)
{
SEMA_ERROR(elements[size - 1], "Few elements in initializer, there should be elements after this one.");
return false;
}
VECEACH(expr->initializer_expr, i)
{
if (!sema_analyse_expr_of_required_type(context, members[i]->type, expr->initializer_expr[i])) return false;
}
expr->type = assigned;
return true;
}
static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *assigned, Expr *expr)
{
expr->type = assigned;
Expr **init_expressions = expr->expr_initializer.initializer_expr;
// 1. Zero size init will initialize to empty.
if (vec_size(init_expressions) == 0)
{
expr->expr_initializer.init_type = INITIALIZER_ZERO;
return true;
}
// 2. Check if we might have a designated initializer
// this means that in this case we're actually not resolving macros here.
if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN)
{
return sema_expr_analyse_struct_designated_initializer(context, assigned->decl, expr);
}
// 3. Otherwise use the plain initializer.
return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr);
}
static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr)
{
assert(to);
@@ -572,7 +635,9 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
{
case TYPE_STRUCT:
case TYPE_UNION:
if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, assigned, expr);
if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer(context,
assigned,
expr);
break;
case TYPE_ARRAY:
TODO
@@ -831,6 +896,8 @@ static bool binary_arithmetic_promotion(Expr *left, Expr *right, Type *left_type
*/
static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
{
// TODO enums
bool is_mod = expr->binary_expr.operator == BINARYOP_SUB_MOD;
// 1. Analyse a and b. Do not push down if this is a -%
@@ -926,6 +993,8 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
*/
static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
{
// TODO enums
bool is_mod = expr->binary_expr.operator == BINARYOP_ADD_MOD;
// 1. Promote everything to the recipient type if possible
@@ -1446,11 +1515,15 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
Type *max = type_find_max_type(left_type, right_type);
// 4. If no common type, then that's an error:
if (!max) goto ERR;
if (!max)
{
SEMA_ERROR(expr, "'%s' and '%s' are different types and cannot be compared.",
type_to_error_string(left->type), type_to_error_string(right->type));
};
// 5. Most types can do equality, but not all can do comparison,
// so we need to check that as well.
if (is_equality_type_op)
if (!is_equality_type_op)
{
switch (max->type_kind)
{
@@ -1496,21 +1569,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
// 7. Do constant folding.
if (both_const(left, right))
{
switch (left->const_expr.kind)
{
case TYPE_BOOL:
SEMA_ERROR(expr, "Cannot compare booleans, convert them into integers first.");
return false;
case ALL_FLOATS:
case ALL_INTS:
expr->const_expr.b = expr_const_compare(&left->const_expr, &right->const_expr, expr->binary_expr.operator);
return true;
case TYPE_STRING:
SEMA_ERROR(expr, "Cannot compare strings.");
return false;
default:
UNREACHABLE
}
expr->const_expr.b = expr_const_compare(&left->const_expr, &right->const_expr, expr->binary_expr.operator);
expr->const_expr.kind = TYPE_BOOL;
expr->expr_kind = EXPR_CONST;
}
@@ -1678,6 +1737,9 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
case TYPE_STRING:
expr->const_expr.b = !inner->const_expr.string.len;
break;
case TYPE_ERROR:
case TYPE_ENUM:
TODO
default:
UNREACHABLE
}
@@ -1871,6 +1933,7 @@ static Expr *expr_shallow_copy(Expr *source)
return copy;
}
static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list);
static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr);
static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source);
@@ -1929,6 +1992,9 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
Expr *expr = expr_shallow_copy(source_expr);
switch (source_expr->expr_kind)
{
case EXPR_DESIGNATED_INIT:
// This type of expression is only created after analysis.
UNREACHABLE
case EXPR_EXPR_BLOCK:
ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts);
return expr;
@@ -1975,18 +2041,14 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
EXPR_COPY(expr->subscript_expr.expr);
EXPR_COPY(expr->subscript_expr.index);
return expr;
case EXPR_GROUP:
EXPR_COPY(expr->group_expr->group_expr);
return expr;
case EXPR_ACCESS:
EXPR_COPY(expr->access_expr.parent);
return expr;
case EXPR_STRUCT_VALUE:
expr->struct_value_expr.type = type_info_copy_from_macro(context, macro, expr->struct_value_expr.type);
EXPR_COPY(expr->struct_value_expr.init_expr);
return expr;
case EXPR_STRUCT_INIT_VALUES:
TODO
return expr;
case EXPR_INITIALIZER_LIST:
expr->initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->initializer_expr);
expr->expr_initializer.initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->expr_initializer.initializer_expr);
return expr;
case EXPR_EXPRESSION_LIST:
expr->expression_list = expr_copy_expr_list_from_macro(context, macro, expr->expression_list);
@@ -2387,6 +2449,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
case EXPR_POISONED:
return false;
case EXPR_SCOPED_EXPR:
case EXPR_DESIGNATED_INIT:
UNREACHABLE
case EXPR_EXPR_BLOCK:
return sema_expr_analyse_expr_block(context, to, expr);
@@ -2416,12 +2479,10 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
return sema_expr_analyse_sizeof(context, to, expr);
case EXPR_SUBSCRIPT:
return sema_expr_analyse_subscript(context, to, expr);
case EXPR_GROUP:
return sema_expr_analyse_group(context, to, expr);
case EXPR_ACCESS:
return sema_expr_analyse_access(context, to, expr);
case EXPR_STRUCT_VALUE:
return sema_expr_analyse_struct_value(context, to, expr);
case EXPR_STRUCT_INIT_VALUES:
return sema_expr_analyse_struct_init_values(context, to, expr);
case EXPR_INITIALIZER_LIST:
return sema_expr_analyse_initializer_list(context, to, expr);
case EXPR_CAST:

View File

@@ -20,7 +20,7 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags)
context->current_scope->local_decl_start = context->last_local;
context->current_scope->defers.start = parent_defer;
context->current_scope->defers.end = parent_defer;
if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK))
if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK | SCOPE_NEXT))
{
context->current_scope->flags = flags;
}
@@ -550,29 +550,40 @@ static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement)
}
}
/**
* Cast the case expression to the switch type and ensure it is constant.
*
* @return true if the analysis succeeds.
*/
static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_stmt)
{
assert(to_type);
Expr *case_expr = case_stmt->case_stmt.expr;
// TODO handle enums
// TODO string expr
if (!sema_analyse_expr_of_required_type(context, to_type, case_expr)) return false;
// 1. Try to do implicit conversion to the correct type.
if (!sema_analyse_expr(context, to_type, case_expr)) return false;
// 2. Skip continued analysis if it's not constant.
if (case_expr->expr_kind != EXPR_CONST)
{
SEMA_ERROR(case_expr, "This must be a constant expression.");
SEMA_ERROR(case_expr, "A case value must always be constant at compile time.");
return false;
}
if (!cast_to_runtime(case_expr)) return false;
Type *case_type = case_expr->type->canonical;
Type *to_type_canonical = to_type->canonical;
if (case_expr->const_expr.kind == TYPE_BOOL) return true;
// 3. If we already have the same type we're done.
if (to_type_canonical == case_type) return true;
if (!type_is_integer(case_expr->type))
// 4. Otherwise check if we have an enum receiving type and a number on
// in the case. In that case we do an implicit conversion.
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_expr->type))
{
SEMA_ERROR(case_expr, "The 'case' value must be a boolean or integer constant.");
return false;
return cast(case_expr, to_type, CAST_TYPE_EXPLICIT);
}
return true;
return cast_implicit(case_expr, to_type);
}
@@ -614,15 +625,23 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
bool success = sema_analyse_cond(context, cond, false);
Type *switch_type = ast_cond_type(cond)->canonical;
if (switch_type == type_bool || !type_is_integer(switch_type))
switch (switch_type->type_kind)
{
SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
return false;
case ALL_INTS:
assert(switch_type->type_kind != TYPE_IXX);
case TYPE_BOOL:
case TYPE_ERROR:
case TYPE_META_TYPE:
case TYPE_ENUM:
case TYPE_STRING:
break;
default:
SEMA_ERROR(cond, "It is not possible to switch over '%s'.", type_to_error_string(switch_type));
return false;
}
Ast *default_case = NULL;
assert(context->current_scope->defers.start == context->current_scope->defers.end);
// TODO enum, exhaustive cases.
ExitType prev_exit = context->current_scope->exit;
bool exhaustive = false;
ExitType lowest_exit = EXIT_NONE;
@@ -693,15 +712,10 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
}
context_pop_defers_and_replace_ast(context, statement);
if (lowest_exit <= EXIT_BREAK) lowest_exit = prev_exit;
// Check exhaustive use.
context->current_scope->exit = exhaustive ? lowest_exit : EXIT_NONE;
context_pop_scope(context);
if (!success) return false;
// Is this a typeless switch value?
if (switch_type->type_kind == TYPE_IXX)
{
TODO
}
return success;
}

View File

@@ -93,7 +93,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
return type_info_poison(type_info);
}
DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string);
type_info->type = decl->type;
type_info->type = decl->typedef_decl.type_info->type;
type_info->resolve_status = RESOLVE_DONE;
return true;
case DECL_POISONED:

View File

@@ -109,6 +109,7 @@ void target_setup()
LLVMTypeRef float_type = LLVMFloatType();
LLVMTypeRef double_type = LLVMDoubleType();
LLVMTypeRef quad_type = LLVMFP128Type();
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);
build_target.align_int = LLVMABIAlignmentOfType(build_target.llvm_data_layout, int_type);
@@ -116,6 +117,7 @@ void target_setup()
build_target.align_f128 = LLVMABIAlignmentOfType(build_target.llvm_data_layout, quad_type);
build_target.align_double = LLVMABIAlignmentOfType(build_target.llvm_data_layout, double_type);
build_target.align_float = LLVMABIAlignmentOfType(build_target.llvm_data_layout, float_type);
build_target.align_pointer = LLVMABIAlignmentOfType(build_target.llvm_data_layout, pointer_type);
build_target.little_endian = LLVMByteOrder(build_target.llvm_data_layout) == LLVMLittleEndian;
build_target.width_c_short = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_SHORT);
build_target.width_c_int = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_INT);

View File

@@ -151,15 +151,15 @@ typedef struct
bool asm_supported;
bool float_128;
bool float_16;
unsigned align_min_pointer;
unsigned align_min_byte;
unsigned align_min_short;
unsigned align_min_int;
unsigned align_min_long;
unsigned align_min_half;
unsigned align_min_float;
unsigned align_min_double;
unsigned align_min_f128;
unsigned align_pref_pointer;
unsigned align_pref_byte;
unsigned align_pref_short;
unsigned align_pref_int;
unsigned align_pref_long;
unsigned align_pref_half;
unsigned align_pref_float;
unsigned align_pref_double;
unsigned align_pref_f128;
unsigned align_pointer;
unsigned align_byte;
unsigned align_short;

View File

@@ -4,22 +4,44 @@
#include "compiler_internal.h"
Type *type_bool, *type_void, *type_string, *type_voidptr;
Type *type_float, *type_double;
Type *type_char, *type_short, *type_int, *type_long, *type_isize;
Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
Type *type_compint, *type_compfloat;
Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_ixx;
static Type t_u8, t_u16, t_u32, t_u64;
static Type t_f32, t_f64, t_fxx;
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;
Type *type_bool = &t_u1;
Type *type_void = &t_u0;
Type *type_string = &t_str;
Type *type_voidptr = &t_voidstar;
Type *type_float = &t_f32;
Type *type_double = &t_f64;
Type *type_error = &t_err;
Type *type_typeid = &t_typeid;
Type *type_char = &t_i8;
Type *type_short = &t_i16;
Type *type_int = &t_i32;
Type *type_long = &t_i64;
Type *type_isize = &t_isz;
Type *type_byte = &t_u8;
Type *type_ushort = &t_u16;
Type *type_uint = &t_u32;
Type *type_ulong = &t_u64;
Type *type_usize = &t_usz;
Type *type_compint = &t_ixx;
Type *type_compfloat = &t_fxx;
Type *type_c_short = &t_cs;
Type *type_c_int = &t_ci;
Type *type_c_long = &t_cl;
Type *type_c_longlong = &t_cll;
Type *type_c_ushort = &t_cus;
Type *type_c_uint = &t_cui;
Type *type_c_ulong = &t_cul;
Type *type_c_ulonglong = &t_cull;
Type t_u0, t_str;
Type t_u1, t_i8, t_i16, t_i32, t_i64, t_ixx;
Type t_u8, t_u16, t_u32, t_u64, t_uxx;
Type t_f32, t_f64, t_fxx;
Type t_usz, t_isz;
Type t_cus, t_cui, t_cul, t_cull;
Type t_cs, t_ci, t_cl, t_cll;
Type t_voidstar;
#define META_OFFSET 0
#define PTR_OFFSET 1
@@ -176,29 +198,18 @@ size_t type_size(Type *canonical)
case TYPE_META_TYPE:
return 0;
case TYPE_ENUM:
return type_size(canonical->decl->enums.type_info->type->canonical);
return canonical->decl->enums.type_info->type->canonical->builtin.bytesize;
case TYPE_ERROR:
return type_error->canonical->builtin.bytesize;
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ERROR:
TODO
return canonical->decl->strukt.size;
case TYPE_VOID:
return 1;
case TYPE_BOOL:
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_F32:
case TYPE_F64:
case ALL_INTS:
case ALL_FLOATS:
return canonical->builtin.bytesize;
case TYPE_IXX:
return 8;
case TYPE_FXX:
return 8;
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
@@ -211,7 +222,44 @@ size_t type_size(Type *canonical)
case TYPE_ERROR_UNION:
TODO
}
TODO
UNREACHABLE
}
size_t type_abi_alignment(Type *canonical)
{
assert(canonical && canonical->canonical == canonical);
switch (canonical->type_kind)
{
case TYPE_POISONED:
case TYPE_TYPEDEF:
case TYPE_VOID:
UNREACHABLE;
case TYPE_META_TYPE:
return 0;
case TYPE_ENUM:
return canonical->decl->enums.type_info->type->canonical->builtin.abi_alignment;
case TYPE_ERROR:
return type_error->canonical->builtin.abi_alignment;
case TYPE_STRUCT:
case TYPE_UNION:
return canonical->decl->strukt.abi_alignment;
case TYPE_BOOL:
case ALL_INTS:
case ALL_FLOATS:
return canonical->builtin.abi_alignment;
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
case TYPE_STRING:
return t_usz.canonical->builtin.abi_alignment;
case TYPE_ARRAY:
return type_abi_alignment(canonical->array.base);
case TYPE_SUBARRAY:
TODO
case TYPE_ERROR_UNION:
TODO
}
UNREACHABLE
}
static inline void create_type_cache(Type *canonical_type)
@@ -346,31 +394,29 @@ Type *type_get_array(Type *arr_type, uint64_t len)
return type_create_array(arr_type, len, false);
}
static void type_create(const char *name, Type *location, Type **ptr, TypeKind kind, unsigned bitsize,
static void type_create(const char *name, Type *location, TypeKind kind, unsigned bitsize,
unsigned align, unsigned pref_align)
{
*location = (Type) {
.type_kind = kind,
.builtin.bytesize = (bitsize + 7) / 8,
.builtin.bitsize = bitsize,
.builtin.min_alignment = align,
.builtin.abi_alignment = align,
.builtin.pref_alignment = pref_align,
.name = name,
.canonical = location,
};
location->name = name;
location->canonical = location;
*ptr = location;
}
static void type_create_alias(const char *name, Type *location, Type **ptr, Type *canonical)
static void type_create_alias(const char *name, Type *location, Type *canonical)
{
*location = (Type) {
.type_kind = TYPE_TYPEDEF,
.name = name,
.canonical = canonical
};
*ptr = location;
}
@@ -383,7 +429,7 @@ void builtin_setup(Target *target)
type_string.type_kind = TYPE_STRING;
*/
#define DEF_TYPE(_name, _shortname, _type, _bits, _align) \
type_create(#_name, &_shortname, &type_ ## _name, _type, _bits, target->align_min_ ## _align, target->align_ ## _align)
type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target->align_pref_ ## _align)
DEF_TYPE(bool, t_u1, TYPE_BOOL, 1, byte);
DEF_TYPE(float, t_f32, TYPE_F32, 32, float);
@@ -404,26 +450,28 @@ type_create(#_name, &_shortname, &type_ ## _name, _type, _bits, target->align_mi
#undef DEF_TYPE
type_create("void*", &t_voidstar, &type_voidptr, TYPE_POINTER, target->width_pointer, target->align_min_pointer, target->align_pointer);
type_create("void*", &t_voidstar, TYPE_POINTER, target->width_pointer, target->align_pref_pointer, target->align_pointer);
create_type_cache(type_void);
type_void->type_cache[0] = &t_voidstar;
t_voidstar.pointer = type_void;
type_create("compint", &t_ixx, &type_compint, TYPE_IXX, 32, 0, 0);
type_create("compfloat", &t_fxx, &type_compfloat, TYPE_FXX, 64, 0, 0);
type_create("compint", &t_ixx, TYPE_IXX, 32, 0, 0);
type_create("compfloat", &t_fxx, TYPE_FXX, 64, 0, 0);
type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_bitsize(target->width_pointer));
type_create_alias("isize", &t_isz, &type_isize, type_signed_int_by_bitsize(target->width_pointer));
type_create_alias("usize", &t_usz, type_unsigned_int_by_bitsize(target->width_pointer));
type_create_alias("isize", &t_isz, type_signed_int_by_bitsize(target->width_pointer));
type_create_alias("c_ushort", &t_cus, &type_c_ushort, type_unsigned_int_by_bitsize(target->width_c_short));
type_create_alias("c_uint", &t_cui, &type_c_uint, type_unsigned_int_by_bitsize(target->width_c_int));
type_create_alias("c_ulong", &t_cul, &type_c_ulong, type_unsigned_int_by_bitsize(target->width_c_long));
type_create_alias("c_ulonglong", &t_cull, &type_c_ulonglong, type_unsigned_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_short", &t_cs, &type_c_short, type_signed_int_by_bitsize(target->width_c_short));
type_create_alias("c_int", &t_ci, &type_c_int, type_signed_int_by_bitsize(target->width_c_int));
type_create_alias("c_long", &t_cl, &type_c_long, type_signed_int_by_bitsize(target->width_c_long));
type_create_alias("c_longlong", &t_cll, &type_c_longlong, type_signed_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_ushort", &t_cus, type_unsigned_int_by_bitsize(target->width_c_short));
type_create_alias("c_uint", &t_cui, type_unsigned_int_by_bitsize(target->width_c_int));
type_create_alias("c_ulong", &t_cul, type_unsigned_int_by_bitsize(target->width_c_long));
type_create_alias("c_ulonglong", &t_cull, type_unsigned_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_short", &t_cs, type_signed_int_by_bitsize(target->width_c_short));
type_create_alias("c_int", &t_ci, type_signed_int_by_bitsize(target->width_c_int));
// TODO fix error size
type_create_alias("error", &t_err, type_signed_int_by_bitsize(target->width_c_int));
type_create_alias("typeid", &t_typeid, type_signed_int_by_bitsize(target->width_pointer));
type_create_alias("c_long", &t_cl, type_signed_int_by_bitsize(target->width_c_long));
type_create_alias("c_longlong", &t_cll, type_signed_int_by_bitsize(target->width_c_long_long));
}
@@ -621,6 +669,7 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:

View File

@@ -42,6 +42,7 @@ TargetInfo target_info_new()
.asm_supported = false,
.float_128 = false,
.float_16 = false,
.align_pointer = 8,
.align_byte = 8,
.align_c_int = 32,
.align_c_long = 32,

View File

@@ -267,6 +267,7 @@ static inline void* _expand(void *vec, size_t element_size)
#define VECEACH(_vec, _index) \
for (unsigned _index = 0, __vecsize = vec_size(_vec); _index < __vecsize; _index++)
#define VECNEW(_type, _capacity) ((_type *)(_vec_new(sizeof(_type), _capacity) + 1))
#define VECADD(_vec, _value) \
({ \