From: Brendan Hansen Date: Sun, 26 Jul 2020 16:51:35 +0000 (-0500) Subject: Added 'alignof' unary operator and alignment checking on structs X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=af3399f93c9a134176ea5642f9d62cff653c67bb;p=onyx.git Added 'alignof' unary operator and alignment checking on structs --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 1beab6f6..1393417b 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -21,6 +21,7 @@ typedef struct AstDereference AstDereference; typedef struct AstArrayAccess AstArrayAccess; typedef struct AstFieldAccess AstFieldAccess; typedef struct AstSizeOf AstSizeOf; +typedef struct AstAlignOf AstAlignOf; typedef struct AstReturn AstReturn; typedef struct AstBreak AstBreak; @@ -103,6 +104,7 @@ typedef enum AstKind { Ast_Kind_Array_Access, Ast_Kind_Field_Access, Ast_Kind_Size_Of, + Ast_Kind_Align_Of, Ast_Kind_If, Ast_Kind_For, @@ -253,6 +255,7 @@ struct AstDereference { AstTyped_base; AstTyped *expr; }; struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; }; struct AstFieldAccess { AstTyped_base; AstTyped *expr; u64 offset; }; struct AstSizeOf { AstTyped_base; AstType *so_type; u64 size; }; +struct AstAlignOf { AstTyped_base; AstType *ao_type; u64 alignment; }; // Intruction Node struct AstReturn { AstNode_base; AstTyped* expr; }; diff --git a/include/onyxlex.h b/include/onyxlex.h index c81ab399..be2f1510 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -26,6 +26,7 @@ typedef enum TokenType { Token_Type_Keyword_Break, Token_Type_Keyword_Continue, Token_Type_Keyword_Sizeof, + Token_Type_Keyword_Alignof, Token_Type_Right_Arrow, Token_Type_Left_Arrow, diff --git a/include/onyxtypes.h b/include/onyxtypes.h index b87f91e2..12d06a75 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -39,7 +39,7 @@ enum BasicFlag { typedef struct TypeBasic { enum BasicKind kind; u32 flags; - i64 size; // NOTE: In bytes + u32 size, alignment; // NOTE: In bytes const char* name; } TypeBasic; @@ -62,7 +62,7 @@ typedef struct StructMember { TYPE_KIND(Struct, struct { \ char* name; \ u32 size; \ - u32 mem_count; \ + u16 aligment, mem_count; \ bh_table(StructMember) members; \ bh_arr(StructMember *) memarr; \ }) \ @@ -106,6 +106,7 @@ struct AstFunction; b32 types_are_compatible(Type* t1, Type* t2); u32 type_size_of(Type* type); +u32 type_alignment_of(Type* type); Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node); Type* type_build_function_type(bh_allocator alloc, struct AstFunction* func, struct AstType* return_type); diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index acc867e7..457791a6 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -23,7 +23,7 @@ contexts: # strings in YAML. When using single quoted strings, only single quotes # need to be escaped: this is done by using two single quotes next to each # other. - - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|sizeof)\b' + - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|sizeof|alignof)\b' scope: keyword.control.onyx - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b' diff --git a/misc/onyx.vim b/misc/onyx.vim index 95e53595..5a6bfbf1 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -14,7 +14,7 @@ syn keyword onyxKeyword package struct proc use global syn keyword onyxKeyword if elseif else syn keyword onyxKeyword for while do syn keyword onyxKeyword break continue return -syn keyword onyxKeyword as sizeof +syn keyword onyxKeyword as sizeof alignof syn keyword onyxType bool void syn keyword onyxType i8 u8 diff --git a/onyx b/onyx index a46eafd4..5aad47df 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/ez.onyx b/progs/ez.onyx index 5df021ff..47784d99 100644 --- a/progs/ez.onyx +++ b/progs/ez.onyx @@ -37,6 +37,7 @@ proc #export "main" { foo.x = 123; foo.y = 321; foo.st = st; + print(alignof Foo); print(sizeof Foo); print(foo.foo_sum()); print_st(foo.st); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index cf6960b1..eb943630 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -20,6 +20,7 @@ CHECK(dereference, AstDereference* deref); CHECK(array_access, AstArrayAccess* expr); CHECK(field_access, AstFieldAccess** pfield); CHECK(size_of, AstSizeOf* so); +CHECK(align_of, AstAlignOf* ao); CHECK(global, AstGlobal* global); CHECK(function, AstFunction* func); CHECK(overloaded_function, AstOverloadedFunction* func); @@ -574,6 +575,12 @@ CHECK(size_of, AstSizeOf* so) { return 0; } +CHECK(align_of, AstAlignOf* ao) { + ao->alignment = type_alignment_of(type_build_from_ast(semstate.allocator, ao->ao_type)); + + return 0; +} + CHECK(expression, AstTyped** pexpr) { AstTyped* expr = *pexpr; if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) { @@ -623,6 +630,7 @@ CHECK(expression, AstTyped** pexpr) { case Ast_Kind_Array_Access: retval = check_array_access((AstArrayAccess *) expr); break; case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess **) pexpr); break; case Ast_Kind_Size_Of: retval = check_size_of((AstSizeOf *) expr); break; + case Ast_Kind_Align_Of: retval = check_align_of((AstAlignOf *) expr); break; case Ast_Kind_Global: if (expr->type == NULL) { diff --git a/src/onyxlex.c b/src/onyxlex.c index 01db3fee..8012a6ff 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -24,6 +24,7 @@ static const char* token_type_names[] = { "break", "continue", "sizeof", + "alignof", "->", "<-", @@ -158,6 +159,7 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) { LITERAL_TOKEN("break", 1, Token_Type_Keyword_Break); LITERAL_TOKEN("continue", 1, Token_Type_Keyword_Continue); LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof); + LITERAL_TOKEN("alignof", 1, Token_Type_Keyword_Alignof); LITERAL_TOKEN("true", 1, Token_Type_Literal_True); LITERAL_TOKEN("false", 1, Token_Type_Literal_False); LITERAL_TOKEN("->", 0, Token_Type_Right_Arrow); diff --git a/src/onyxparser.c b/src/onyxparser.c index 608e3f2a..10b93d0e 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -198,6 +198,16 @@ static AstTyped* parse_factor(OnyxParser* parser) { break; } + case Token_Type_Keyword_Alignof: { + AstAlignOf* ao_node = make_node(AstAlignOf, Ast_Kind_Align_Of); + ao_node->token = expect_token(parser, Token_Type_Keyword_Alignof); + ao_node->ao_type = (AstType *) parse_type(parser); + ao_node->type_node = (AstType *) &basic_type_i32; + + retval = (AstTyped *) ao_node; + break; + } + case Token_Type_Symbol: { OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol); AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index a17ad421..c7a04c41 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -48,6 +48,7 @@ static AstType* symres_type(AstType* type); static void symres_local(AstLocal** local); static void symres_call(AstCall* call); static void symres_size_of(AstSizeOf* so); +static void symres_align_of(AstAlignOf* so); static void symres_field_access(AstFieldAccess** fa); static void symres_expression(AstTyped** expr); static void symres_return(AstReturn* ret); @@ -174,6 +175,11 @@ static void symres_size_of(AstSizeOf* so) { so->so_type = symres_type(so->so_type); } +static void symres_align_of(AstAlignOf* ao) { + ao->type_node = symres_type(ao->type_node); + ao->ao_type = symres_type(ao->ao_type); +} + static void symres_field_access(AstFieldAccess** fa) { if ((*fa)->expr == NULL) return; symres_expression(&(*fa)->expr); @@ -234,6 +240,7 @@ static void symres_expression(AstTyped** expr) { case Ast_Kind_Dereference: symres_expression(&((AstDereference *)(*expr))->expr); break; case Ast_Kind_Field_Access: symres_field_access((AstFieldAccess **) expr); break; case Ast_Kind_Size_Of: symres_size_of((AstSizeOf *)*expr); break; + case Ast_Kind_Align_Of: symres_align_of((AstAlignOf *)*expr); break; case Ast_Kind_Array_Access: symres_expression(&((AstArrayAccess *)(*expr))->addr); diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 37271b48..85664e2c 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -4,23 +4,23 @@ // NOTE: These have to be in the same order as Basic Type basic_types[] = { - { Type_Kind_Basic, 0, { Basic_Kind_Void, 0, 0, "void" } }, + { Type_Kind_Basic, 0, { Basic_Kind_Void, 0, 0, 1, "void" } }, - { Type_Kind_Basic, 0, { Basic_Kind_Bool, Basic_Flag_Boolean, 1, "bool" } }, + { Type_Kind_Basic, 0, { Basic_Kind_Bool, Basic_Flag_Boolean, 1, 1, "bool" } }, - { Type_Kind_Basic, 0, { Basic_Kind_I8, Basic_Flag_Integer, 1, "i8" } }, - { Type_Kind_Basic, 0, { Basic_Kind_U8, Basic_Flag_Integer | Basic_Flag_Unsigned, 1, "u8" } }, - { Type_Kind_Basic, 0, { Basic_Kind_I16, Basic_Flag_Integer, 2, "i16" } }, - { Type_Kind_Basic, 0, { Basic_Kind_U16, Basic_Flag_Integer | Basic_Flag_Unsigned, 2, "u16" } }, - { Type_Kind_Basic, 0, { Basic_Kind_I32, Basic_Flag_Integer, 4, "i32" } }, - { Type_Kind_Basic, 0, { Basic_Kind_U32, Basic_Flag_Integer | Basic_Flag_Unsigned, 4, "u32" } }, - { Type_Kind_Basic, 0, { Basic_Kind_I64, Basic_Flag_Integer, 8, "i64" } }, - { Type_Kind_Basic, 0, { Basic_Kind_U64, Basic_Flag_Integer | Basic_Flag_Unsigned, 8, "u64" } }, + { Type_Kind_Basic, 0, { Basic_Kind_I8, Basic_Flag_Integer, 1, 1, "i8" } }, + { Type_Kind_Basic, 0, { Basic_Kind_U8, Basic_Flag_Integer | Basic_Flag_Unsigned, 1, 1, "u8" } }, + { Type_Kind_Basic, 0, { Basic_Kind_I16, Basic_Flag_Integer, 2, 2, "i16" } }, + { Type_Kind_Basic, 0, { Basic_Kind_U16, Basic_Flag_Integer | Basic_Flag_Unsigned, 2, 2, "u16" } }, + { Type_Kind_Basic, 0, { Basic_Kind_I32, Basic_Flag_Integer, 4, 4, "i32" } }, + { Type_Kind_Basic, 0, { Basic_Kind_U32, Basic_Flag_Integer | Basic_Flag_Unsigned, 4, 4, "u32" } }, + { Type_Kind_Basic, 0, { Basic_Kind_I64, Basic_Flag_Integer, 8, 8, "i64" } }, + { Type_Kind_Basic, 0, { Basic_Kind_U64, Basic_Flag_Integer | Basic_Flag_Unsigned, 8, 8, "u64" } }, - { Type_Kind_Basic, 0, { Basic_Kind_F32, Basic_Flag_Float, 4, "f32" } }, - { Type_Kind_Basic, 0, { Basic_Kind_F64, Basic_Flag_Float, 8, "f64" } }, + { Type_Kind_Basic, 0, { Basic_Kind_F32, Basic_Flag_Float, 4, 4, "f32" } }, + { Type_Kind_Basic, 0, { Basic_Kind_F64, Basic_Flag_Float, 8, 4, "f64" } }, - { Type_Kind_Basic, 0, { Basic_Kind_Rawptr, Basic_Flag_Pointer, 4, "rawptr" } }, + { Type_Kind_Basic, 0, { Basic_Kind_Rawptr, Basic_Flag_Pointer, 4, 4, "rawptr" } }, }; b32 types_are_surface_compatible(Type* t1, Type* t2) { @@ -170,6 +170,20 @@ u32 type_size_of(Type* type) { } } +u32 type_alignment_of(Type* type) { + if (type == NULL) return 1; + + switch (type->kind) { + case Type_Kind_Basic: return type->Basic.alignment; + case Type_Kind_Pointer: return 4; + case Type_Kind_Function: return 1; + case Type_Kind_Array: return type_alignment_of(type->Array.elem); + case Type_Kind_Struct: return type->Struct.aligment; + case Type_Kind_Enum: return type_alignment_of(type->Enum.backing); + default: return 1; + } +} + Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { if (type_node == NULL) return NULL; @@ -238,12 +252,17 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count); u32 offset = 0; - u32 min_alignment = 1; + u32 alignment = 1, mem_alignment; u32 idx = 0; bh_arr_each(AstStructMember *, member, s_node->members) { (*member)->type = type_build_from_ast(alloc, (*member)->type_node); // TODO: Add alignment checking here + mem_alignment = type_alignment_of((*member)->type); + if (mem_alignment > alignment) alignment = mem_alignment; + if (offset % alignment != 0) { + offset += alignment - (offset % alignment); + } StructMember smem = { .offset = offset, @@ -260,7 +279,11 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { idx++; } - // TODO: Again, add alignment + s_type->Struct.aligment = alignment; + + if (offset % alignment != 0) { + offset += alignment - (offset % alignment); + } s_type->Struct.size = offset; return s_type; diff --git a/src/onyxutils.c b/src/onyxutils.c index 14e35c5a..8c53165b 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -50,6 +50,7 @@ static const char* ast_node_names[] = { "ARRAY_ACCESS", "FIELD_ACCESS", "SIZE OF", + "ALIGN OF" "IF", "FOR", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index bc29901d..1a0f5e98 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -425,7 +425,7 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) { COMPILE_FUNC(load_instruction, Type* type, u32 offset) { bh_arr(WasmInstruction) code = *pcode; - + if (type->kind == Type_Kind_Enum) { type = type->Enum.backing; } @@ -969,6 +969,12 @@ COMPILE_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_Align_Of: { + AstAlignOf* ao = (AstAlignOf *) expr; + WID(WI_I32_CONST, ao->alignment); + break; + } + case Ast_Kind_Enum_Value: { AstEnumValue* ev = (AstEnumValue *) expr; WasmType backing_type = onyx_type_to_wasm_type(ev->type);