diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-04-21 17:56:29 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-04-21 17:56:29 +0100 |
| commit | 91ed51ff5c9c49a739f6a835acf6df492690e2cd (patch) | |
| tree | 958418f9bf05865f11ece0b3a88183e25174089b /src | |
| parent | 4d0afc55c353563607206a085432c258e3dc92e1 (diff) | |
Continue work on custom SSA; Fix double declaration in `when` statements
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_decl.c | 3 | ||||
| -rw-r--r-- | src/check_expr.c | 4 | ||||
| -rw-r--r-- | src/check_stmt.c | 5 | ||||
| -rw-r--r-- | src/checker.c | 8 | ||||
| -rw-r--r-- | src/common.c | 6 | ||||
| -rw-r--r-- | src/ir.c | 2 | ||||
| -rw-r--r-- | src/main.c | 5 | ||||
| -rw-r--r-- | src/ssa.c | 642 | ||||
| -rw-r--r-- | src/ssa_op.c | 1 | ||||
| -rw-r--r-- | src/types.c | 153 |
10 files changed, 557 insertions, 272 deletions
diff --git a/src/check_decl.c b/src/check_decl.c index 5586cb904..0321f3b2e 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -1,6 +1,5 @@ bool check_is_terminating(AstNode *node); void check_stmt (Checker *c, AstNode *node, u32 flags); -void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags); // NOTE(bill): `content_name` is for debugging and error messages Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) { @@ -563,7 +562,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod push_procedure(c, type); { ast_node(bs, BlockStmt, body); - check_stmt_list(c, bs->stmts, 0); + check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls); if (type->Proc.result_count > 0) { if (!check_is_terminating(body)) { if (token.kind == Token_Ident) { diff --git a/src/check_expr.c b/src/check_expr.c index d3338f9c8..75e848903 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -5118,7 +5118,9 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t case Type_Record: { if (!is_type_struct(t) && !is_type_union(t)) { if (cl->elems.count != 0) { - error_node(node, "Illegal compound literal"); + gbString type_str = type_to_string(type); + error_node(node, "Illegal compound literal type `%s`", type_str); + gb_string_free(type_str); } break; } diff --git a/src/check_stmt.c b/src/check_stmt.c index 549383472..0660e8265 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -3,7 +3,9 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { return; } - check_scope_decls(c, stmts, 1.2*stmts.count); + if (flags&Stmt_CheckScopeDecls) { + check_scope_decls(c, stmts, 1.2*stmts.count); + } bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0; flags &= ~Stmt_FallthroughAllowed; @@ -362,6 +364,7 @@ typedef struct TypeAndToken { #include "map.c" void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) { + flags &= ~Stmt_CheckScopeDecls; Operand operand = {Addressing_Invalid}; check_expr(c, &operand, ws->cond); if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) { diff --git a/src/checker.c b/src/checker.c index 2f41f77a1..6ef7811f3 100644 --- a/src/checker.c +++ b/src/checker.c @@ -11,7 +11,8 @@ typedef enum StmtFlag { Stmt_BreakAllowed = 1<<0, Stmt_ContinueAllowed = 1<<1, Stmt_FallthroughAllowed = 1<<2, - Stmt_GiveAllowed = 1<<3, + + Stmt_CheckScopeDecls = 1<<5, } StmtFlag; typedef struct BuiltinProc { @@ -550,6 +551,10 @@ Entity *scope_lookup_entity(Scope *s, String name) { Entity *scope_insert_entity(Scope *s, Entity *entity) { String name = entity->token.string; + if (str_eq(name, str_lit("output"))) { + gb_printf_err("Here! %.*s\n", LIT(name)); + } + HashKey key = hash_string(name); Entity **found = map_entity_get(&s->elements, key); @@ -1292,7 +1297,6 @@ void check_procedure_overloading(Checker *c, Entity *e) { continue; } - String name = p->token.string; GB_ASSERT(p->kind == Entity_Procedure); diff --git a/src/common.c b/src/common.c index 3234bc59c..920e78e1c 100644 --- a/src/common.c +++ b/src/common.c @@ -1,8 +1,12 @@ +#if defined(GB_SYSTEM_UNIX) +// Required for intrinsics on GCC +#include <xmmintrin.h> +#endif + #define GB_NO_DEFER #define GB_IMPLEMENTATION #include "gb/gb.h" - #include <math.h> gbAllocator heap_allocator(void) { @@ -1138,6 +1138,8 @@ irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) { v->Block.node = node; v->Block.scope = scope; v->Block.parent = proc; + // TODO(bill): Is this correct or even needed? + v->Block.scope_index = proc->scope_index; array_init(&v->Block.instrs, heap_allocator()); array_init(&v->Block.locals, heap_allocator()); diff --git a/src/main.c b/src/main.c index 268324949..fd853dd82 100644 --- a/src/main.c +++ b/src/main.c @@ -16,11 +16,6 @@ extern "C" { #include "ir_print.c" // #include "vm.c" -#if defined(GB_SYSTEM_UNIX) -// Required for intrinsics on GCC -#include <xmmintrin.h> -#endif - #if defined(GB_SYSTEM_WINDOWS) // NOTE(bill): `name` is used in debugging and profiling modes i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) { @@ -1,6 +1,7 @@ typedef struct ssaModule ssaModule; typedef struct ssaValue ssaValue; typedef struct ssaValueArgs ssaValueArgs; +typedef struct ssaDefer ssaDefer; typedef struct ssaBlock ssaBlock; typedef struct ssaProc ssaProc; typedef struct ssaEdge ssaEdge; @@ -8,6 +9,8 @@ typedef struct ssaRegister ssaRegister; typedef struct ssaTargetList ssaTargetList; typedef enum ssaBlockKind ssaBlockKind; typedef enum ssaBranchPrediction ssaBranchPrediction; +typedef enum ssaDeferExitKind ssaDeferExitKind; + String ssa_mangle_name(ssaModule *m, String path, Entity *e); @@ -49,6 +52,7 @@ enum ssaBlockKind { // architectures, these could become conditions blocks like amd64 LT or EQ ssaBlock_Entry, // Entry point ssaBlock_Plain, + ssaBlock_Defer, // Similar to a plain block but generated by a `defer` statement ssaBlock_If, ssaBlock_Ret, ssaBlock_RetJmp, // Stores return value and jumps to Ret block @@ -63,6 +67,27 @@ enum ssaBranchPrediction { ssaBranch_Unlikely = -1, }; +typedef enum ssaDeferKind { + ssaDefer_Node, + ssaDefer_Instr, +} ssaDeferKind; + +struct ssaDefer { + ssaDeferKind kind; + i32 scope_level; + ssaBlock * block; + union { + AstNode * stmt; + ssaValue * instr; + }; +}; + +enum ssaDeferExitKind { + ssaDeferExit_Default, + ssaDeferExit_Return, + ssaDeferExit_Branch, +}; + // ssaEdge represents a control flow graph (CFG) edge struct ssaEdge { // Succs array: Block To @@ -79,6 +104,7 @@ struct ssaBlock { ssaBlockKind kind; ssaProc * proc; // Containing procedure String name; // Optional + i32 scope_level; // Likely branch direction ssaBranchPrediction likeliness; @@ -118,6 +144,9 @@ struct ssaProc { i32 block_id; i32 value_id; MapSsaValue values; // Key: Entity * + + Array(ssaDefer) defer_stmts; + i32 scope_level; }; struct ssaRegister { @@ -147,6 +176,17 @@ struct ssaModule { ssaValueArray procs_to_generate; }; +typedef enum ssaAddrKind { + ssaAddr_Default, + ssaAddr_Map, +} ssaAddrKind; + +typedef struct ssaAddr { + ssaValue * addr; + ssaAddrKind kind; +} ssaAddr; + + void ssa_push_target_list(ssaProc *p, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) { ssaTargetList *tl = gb_alloc_item(p->allocator, ssaTargetList); @@ -167,6 +207,7 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) { b->id = p->block_id++; b->kind = kind; b->proc = p; + p->scope_level = p->scope_level; if (name != NULL || name[0] != 0) { b->name = make_string_c(name); } @@ -352,6 +393,17 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) { return NULL; } + + + +ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr); +ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr); +void ssa_build_stmt (ssaProc *p, AstNode *node); +void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes); +ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel); + + + void ssa_reset_value_args(ssaValue *v) { for_array(i, v->args) { v->args.e[i]->uses--; @@ -365,6 +417,85 @@ void ssa_reset(ssaValue *v, ssaOp op) { ssa_reset_value_args(v); } +ssaValue *ssa_get_last_value(ssaBlock *b) { + if (b == NULL) { + return NULL; + } + isize len = b->values.count; + if (len <= 0) { + return 0; + } + ssaValue *v = b->values.e[len-1]; + return v; +} + +void ssa_emit_comment(ssaProc *p, String s) { + // ssa_new_value0v(p, ssaOp_Comment, NULL, exact_value_string(s)); +} + +void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) { + // ssaValue *last_instr = ssa_get_last_value(p->curr_block); + ssaBlock *b = ssa_new_block(p, ssaBlock_Plain, "defer"); + ssa_emit_jump(p, b); + ssa_start_block(p, b); + ssa_emit_comment(p, str_lit("defer")); + if (d.kind == ssaDefer_Node) { + ssa_build_stmt(p, d.stmt); + } else if (d.kind == ssaDefer_Instr) { + // NOTE(bill): Need to make a new copy + ssaValue *v = cast(ssaValue *)gb_alloc_copy(p->allocator, d.instr, gb_size_of(ssaValue)); + array_add(&p->curr_block->values, v); + } +} + +void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) { + isize count = p->defer_stmts.count; + for (isize i = count-1; i >= 0; i--) { + ssaDefer d = p->defer_stmts.e[i]; + if (kind == ssaDeferExit_Default) { + gb_printf_err("scope_level %d %d\n", p->scope_level, d.scope_level); + if (p->scope_level == d.scope_level && + d.scope_level > 1) { + ssa_build_defer_stmt(p, d); + array_pop(&p->defer_stmts); + continue; + } else { + break; + } + } else if (kind == ssaDeferExit_Return) { + ssa_build_defer_stmt(p, d); + } else if (kind == ssaDeferExit_Branch) { + GB_ASSERT(b != NULL); + i32 lower_limit = b->scope_level+1; + if (lower_limit < d.scope_level) { + ssa_build_defer_stmt(p, d); + } + } + } +} + +ssaDefer ssa_add_defer_node(ssaProc *p, i32 scope_level, AstNode *stmt) { + ssaDefer d = {ssaDefer_Node}; + d.scope_level = scope_level; + d.block = p->curr_block; + d.stmt = stmt; + array_add(&p->defer_stmts, d); + return d; +} + +void ssa_open_scope(ssaProc *p) { + p->scope_level++; +} + +void ssa_close_scope(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) { + ssa_emit_defer_stmts(p, kind, b); + GB_ASSERT(p->scope_level > 0); + p->scope_level--; +} + + + + ssaValue *ssa_emit_load(ssaProc *p, ssaValue *v) { GB_ASSERT(is_type_pointer(v->type)); return ssa_new_value1(p, ssaOp_Load, type_deref(v->type), v); @@ -411,15 +542,6 @@ bool ssa_is_blank_ident(AstNode *node) { } -typedef enum ssaAddrKind { - ssaAddr_Default, - ssaAddr_Map, -} ssaAddrKind; - -typedef struct ssaAddr { - ssaValue * addr; - ssaAddrKind kind; -} ssaAddr; ssaAddr ssa_addr(ssaValue *v) { if (v != NULL) { @@ -456,6 +578,7 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_ p->decl_info = decl_info; array_init(&p->blocks, heap_allocator()); + array_init(&p->defer_stmts, heap_allocator()); map_ssa_value_init(&p->values, heap_allocator()); return p; @@ -472,10 +595,8 @@ ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { map_ssa_value_set(&p->values, hash_pointer(e), local); map_ssa_value_set(&p->module->values, hash_pointer(e), local); local->comment_string = e->token.string; - - ssaValue *addr = ssa_new_value1(p, ssaOp_Addr, local->type, local); - ssa_new_value1(p, ssaOp_Zero, t, addr); - return ssa_addr(addr); + ssa_new_value1(p, ssaOp_Zero, t, local); + return ssa_addr(local); } ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) { Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name)); @@ -498,9 +619,7 @@ ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { return ssa_add_local(p, e, NULL); } -void ssa_emit_comment(ssaProc *p, String s) { - // ssa_new_value0v(p, ssaOp_Comment, NULL, exact_value_string(s)); -} + #define SSA_MAX_STRUCT_FIELD_COUNT 4 @@ -549,12 +668,6 @@ bool can_ssa_type(Type *t) { return true; } -ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr); -ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr); -void ssa_build_stmt (ssaProc *p, AstNode *node); -void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes); -ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel); - void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) { if (addr.addr == NULL) { return; @@ -706,10 +819,6 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) { GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); result_type = make_type_pointer(a, t->Record.fields[index]->type); - i64 offset = t->Record.offsets[index]; - ssaValue *ptr = ssa_emit_conv(p, s, t_u8_ptr); - ptr = ssa_new_value2(p, ssaOp_PtrOffset, ptr->type, ptr, ssa_const_int(p, t_int, offset)); - return ssa_emit_conv(p, ptr, result_type); } else if (is_type_tuple(t)) { GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); @@ -772,13 +881,7 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) { type_set_offsets(a, t); GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); - Type *ptr_type = make_type_pointer(a, t->Record.fields[index]->type); - i64 offset = t->Record.offsets[index]; - ssaValue *ptr = ssa_address_from_load_or_generate_local(p, s); - ptr = ssa_emit_conv(p, s, t_u8_ptr); - ptr = ssa_new_value2(p, ssaOp_PtrOffset, ptr->type, ptr, ssa_const_int(p, t_int, offset)); - ptr = ssa_emit_conv(p, ptr, ptr_type); - return ssa_emit_load(p, ptr); + result_type = t->Record.fields[index]->type; } else if (is_type_tuple(t)) { GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); @@ -1007,9 +1110,88 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) { return ssa_addr(a); } case_end; + + + case_ast_node(ce, CastExpr, expr); + switch (ce->token.kind) { + case Token_cast: { + ssa_emit_comment(p, str_lit("Cast - cast")); + // NOTE(bill): Needed for dereference of pointer conversion + Type *type = type_of_expr(p->module->info, expr); + ssaAddr addr = ssa_add_local_generated(p, type); + ssa_addr_store(p, addr, ssa_emit_conv(p, ssa_build_expr(p, ce->expr), type)); + return addr; + } + #if 0 + case Token_transmute: { + ssa_emit_comment(p, str_lit("Cast - transmute")); + // NOTE(bill): Needed for dereference of pointer conversion + Type *type = type_of_expr(p->module->info, expr); + ssaValue *v = ssa_add_local_generated(p, type); + ssa_emit_store(p, v, ssa_emit_transmute(p, ssa_build_expr(p, ce->expr), type)); + return ssa_addr(v); + } + case Token_union_cast: { + ssa_emit_comment(p, str_lit("Cast - union_cast")); + // NOTE(bill): Needed for dereference of pointer conversion + Type *type = type_of_expr(p->module->info, expr); + ssaValue *v = ssa_add_local_generated(p, type); + ssa_emit_store(p, v, ssa_emit_union_cast(p, ssa_build_expr(p, ce->expr), type, ast_node_token(expr).pos)); + return ssa_addr(v); + } + #endif + default: + GB_PANIC("Unknown cast expression"); + } + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_Pointer: { + return ssa_build_addr(p, ue->expr); + } + default: + GB_PANIC("Invalid unary expression for ssa_build_addr"); + } + case_end; + + case_ast_node(be, BinaryExpr, expr); + GB_PANIC("Invalid binary expression for ssa_build_addr: %.*s\n", LIT(be->op.string)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + GB_PANIC("TODO(bill): ssa_build_addr IndexExpr"); + case_end; + + case_ast_node(se, SliceExpr, expr); + GB_PANIC("TODO(bill): ssa_build_addr SliceExpr"); + case_end; + + case_ast_node(de, DerefExpr, expr); + ssaValue *addr = ssa_build_expr(p, de->expr); + return ssa_addr(addr); + case_end; + + case_ast_node(ce, CallExpr, expr); + ssaValue *e = ssa_build_expr(p, expr); + ssaValue *v = ssa_address_from_load_or_generate_local(p, e); + return ssa_addr(v); + case_end; + + case_ast_node(cl, CompoundLit, expr); + GB_PANIC("TODO(bill): ssa_build_addr CompoundLit"); + case_end; + } - GB_PANIC("Cannot get entity's address"); + TokenPos token_pos = ast_node_token(expr).pos; + GB_PANIC("Unexpected address expression\n" + "\tAstNode: %.*s @ " + "%.*s(%td:%td)\n", + LIT(ast_node_strings[expr->kind]), + LIT(token_pos.file), token_pos.line, token_pos.column); + + return ssa_addr(NULL); } @@ -1234,6 +1416,7 @@ ssaOp ssa_determine_op(TokenKind op, Type *t) { return ssaOp_Invalid; } + ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) { GB_ASSERT(x != NULL && y != NULL); Type *a = core_type(x->type); @@ -1278,6 +1461,130 @@ ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) { +ssaValue *ssa_emit_unary_arith(ssaProc *p, TokenKind op, ssaValue *x, Type *type) { + if (is_type_vector(x->type)) { + ssa_emit_comment(p, str_lit("vector.arith.begin")); + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + Type *tl = base_type(x->type); + ssaValue *val = ssa_address_from_load_or_generate_local(p, x); + GB_ASSERT(is_type_vector(type)); + Type *elem_type = base_type(type)->Vector.elem; + + ssaAddr res = ssa_add_local_generated(p, type); + for (i64 i = 0; i < tl->Vector.count; i++) { + ssaValue *index = ssa_const_int(p, t_int, i); + ssaValue *e = ssa_emit_load(p, ssa_emit_array_index(p, val, index)); + ssaValue *z = ssa_emit_unary_arith(p, op, e, elem_type); + ssa_emit_store(p, ssa_emit_array_index(p, res.addr, index), z); + } + ssa_emit_comment(p, str_lit("vector.arith.end")); + return ssa_addr_load(p, res); + + } + + + switch (op) { + case Token_Pointer: { + GB_PANIC("Token_Pointer should be handled elsewhere"); + } break; + + case Token_Add: + return x; + + case Token_Not: // Boolean not + return ssa_new_value1(p, ssaOp_NotB, type, x); + case Token_Xor: { // Bitwise not + isize bits = 8*type_size_of(p->allocator, x->type); + switch (bits) { + case 8: return ssa_new_value1(p, ssaOp_Not8, type, x); + case 16: return ssa_new_value1(p, ssaOp_Not16, type, x); + case 32: return ssa_new_value1(p, ssaOp_Not32, type, x); + case 64: return ssa_new_value1(p, ssaOp_Not64, type, x); + } + GB_PANIC("unknown integer size"); + } break; + + case Token_Sub: { // 0-x + isize bits = 8*type_size_of(p->allocator, x->type); + if (is_type_integer(x->type)) { + switch (bits) { + case 8: return ssa_new_value1(p, ssaOp_Neg8, type, x); + case 16: return ssa_new_value1(p, ssaOp_Neg16, type, x); + case 32: return ssa_new_value1(p, ssaOp_Neg32, type, x); + case 64: return ssa_new_value1(p, ssaOp_Neg64, type, x); + } + } else if (is_type_float(x->type)) { + switch (bits) { + case 32: return ssa_new_value1(p, ssaOp_Neg32F, type, x); + case 64: return ssa_new_value1(p, ssaOp_Neg64F, type, x); + } + } + GB_PANIC("unknown type for -x"); + } break; + } + return NULL; +} +ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) { + if (is_type_vector(x->type)) { + GB_PANIC("TODO(bill): ssa_emit_arith vector"); + } else if (is_type_complex(x->type)) { + GB_PANIC("TODO(bill): ssa_emit_arith complex"); + } else if (is_type_quaternion(x->type)) { + GB_PANIC("TODO(bill): ssa_emit_arith quaternion"); + } + + if (op == Token_Add) { + if (is_type_pointer(x->type)) { + GB_PANIC("TODO(bill): Ptr arith"); + ssaValue *ptr = ssa_emit_conv(p, x, type); + ssaValue *offset = y; + // return ssa_emit_ptr_offset(p, ptr, offset); + } else if (is_type_pointer(y->type)) { + GB_PANIC("TODO(bill): Ptr arith"); + + ssaValue *ptr = ssa_emit_conv(p, y, type); + ssaValue *offset = x; + // return ssa_emit_ptr_offset(p, ptr, offset); + } + } else if (op == Token_Sub) { + if (is_type_pointer(x->type) && is_type_integer(y->type)) { + GB_PANIC("TODO(bill): Ptr arith"); + // ptr - int + ssaValue *ptr = ssa_emit_conv(p, x, type); + ssaValue *offset = y; + // return ssa_emit_ptr_offset(p, ptr, offset); + } else if (is_type_pointer(x->type) && is_type_pointer(y->type)) { + GB_ASSERT(is_type_integer(type)); + Type *ptr_type = base_type(x->type); + GB_ASSERT(!is_type_rawptr(ptr_type)); + ssaValue *elem_size = ssa_const_int(p, t_int, type_size_of(p->allocator, ptr_type->Pointer.elem)); + ssaValue *a = ssa_emit_conv(p, x, type); + ssaValue *b = ssa_emit_conv(p, y, type); + ssaValue *diff = ssa_emit_arith(p, op, a, b, type); + return ssa_emit_arith(p, Token_Quo, diff, elem_size, type); + } + } + + switch (op) { + case Token_Add: + case Token_Sub: + case Token_Mul: + case Token_Quo: + case Token_Mod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: + GB_ASSERT(x != NULL && y != NULL); + return ssa_new_value2(p, ssa_determine_op(op, x->type), type, x, y); + } + + return NULL; +} + + + + ssaValue *ssa_build_cond(ssaProc *p, AstNode *cond, ssaBlock *yes, ssaBlock *no) { switch (cond->kind) { case_ast_node(pe, ParenExpr, cond); @@ -1439,47 +1746,12 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { case_end; case_ast_node(ue, UnaryExpr, expr); - switch (ue->op.kind) { - case Token_Pointer: { + if (ue->op.kind == Token_Pointer) { return ssa_build_addr(p, ue->expr).addr; - } break; - - case Token_Add: - return ssa_build_expr(p, ue->expr); - - case Token_Not: // Boolean not - return ssa_new_value1(p, ssaOp_NotB, tv->type, ssa_build_expr(p, ue->expr)); - case Token_Xor: { // Bitwise not - ssaValue *x = ssa_build_expr(p, ue->expr); - isize bits = 8*type_size_of(p->allocator, x->type); - switch (bits) { - case 8: return ssa_new_value1(p, ssaOp_Not8, tv->type, x); - case 16: return ssa_new_value1(p, ssaOp_Not16, tv->type, x); - case 32: return ssa_new_value1(p, ssaOp_Not32, tv->type, x); - case 64: return ssa_new_value1(p, ssaOp_Not64, tv->type, x); - } - GB_PANIC("unknown integer size"); - } break; - - case Token_Sub: { // 0-x - ssaValue *x = ssa_build_expr(p, ue->expr); - isize bits = 8*type_size_of(p->allocator, x->type); - if (is_type_integer(x->type)) { - switch (bits) { - case 8: return ssa_new_value1(p, ssaOp_Neg8, tv->type, x); - case 16: return ssa_new_value1(p, ssaOp_Neg16, tv->type, x); - case 32: return ssa_new_value1(p, ssaOp_Neg32, tv->type, x); - case 64: return ssa_new_value1(p, ssaOp_Neg64, tv->type, x); - } - } else if (is_type_float(x->type)) { - switch (bits) { - case 32: return ssa_new_value1(p, ssaOp_Neg32F, tv->type, x); - case 64: return ssa_new_value1(p, ssaOp_Neg64F, tv->type, x); - } - } - GB_PANIC("unknown type for -x"); - } break; } + ssaValue *x = ssa_build_expr(p, ue->expr); + return ssa_emit_unary_arith(p, ue->op.kind, x, tv->type); + case_end; case_ast_node(be, BinaryExpr, expr); @@ -1497,8 +1769,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { case Token_AndNot: { ssaValue *x = ssa_build_expr(p, be->left); ssaValue *y = ssa_build_expr(p, be->right); - GB_ASSERT(x != NULL && y != NULL); - return ssa_new_value2(p, ssa_determine_op(be->op.kind, x->type), tv->type, x, y); + return ssa_emit_arith(p, be->op.kind, x, y, type); } case Token_Shl: @@ -1527,8 +1798,126 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { break; } case_end; + + case_ast_node(de, DerefExpr, expr); + return ssa_addr_load(p, ssa_build_addr(p, expr)); + case_end; + + case_ast_node(se, SelectorExpr, expr); + return ssa_addr_load(p, ssa_build_addr(p, expr)); + case_end; + + case_ast_node(te, TernaryExpr, expr); + ssa_emit_comment(p, str_lit("TernaryExpr")); + + ssaValue *yes = NULL; + ssaValue *no = NULL; + + GB_ASSERT(te->y != NULL); + ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then"); + ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); // NOTE(bill): Append later + ssaBlock *else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); + + ssaBlock *v = NULL; + + ssa_build_cond(p, te->cond, then, else_); + ssa_start_block(p, then); + + // ssa_open_scope(p); + yes = ssa_build_expr(p, te->x); + // ssa_close_scope(p, ssaDeferExit_Default, NULL); + + ssa_emit_jump(p, done); + ssa_start_block(p, else_); + + // ssa_open_scope(p); + no = ssa_build_expr(p, te->y); + // ssa_close_scope(p, ssaDeferExit_Default, NULL); + + ssa_emit_jump(p, done); + ssa_start_block(p, done); + + return ssa_new_value2(p, ssaOp_Phi, tv->type, yes, no); + case_end; + + + case_ast_node(ce, CastExpr, expr); + Type *type = tv->type; + ssaValue *e = ssa_build_expr(p, ce->expr); + switch (ce->token.kind) { + case Token_cast: + ssa_emit_comment(p, str_lit("cast - cast")); + return ssa_emit_conv(p, e, type); + + // case Token_transmute: + // ssa_emit_comment(p, str_lit("cast - transmute")); + // return ssa_emit_transmute(p, e, type); + + #if 0 + case Token_down_cast: + ssa_emit_comment(p, str_lit("cast - down_cast")); + return ssa_emit_down_cast(p, e, type); + #endif + + // case Token_union_cast: + // ssa_emit_comment(p, str_lit("cast - union_cast")); + // return ssa_emit_union_cast(p, e, type, ast_node_token(expr).pos); + + default: + GB_PANIC("Unhandled cast expression %.*s", LIT(token_strings[ce->token.kind])); + } + case_end; + + case_ast_node(pl, ProcLit, expr); + GB_PANIC("TODO(bill): ssa_build_expr ProcLit"); + #if 0 + // NOTE(bill): Generate a new name + // parent$count + isize name_len = proc->name.len + 1 + 8 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)proc->children.count); + String name = make_string(name_text, name_len-1); + + Type *type = type_of_expr(proc->module->info, expr); + irValue *value = ir_value_procedure(proc->module->allocator, + proc->module, NULL, type, pl->type, pl->body, name); + + value->Proc.tags = pl->tags; + value->Proc.parent = proc; + + array_add(&proc->children, &value->Proc); + array_add(&proc->module->procs_to_generate, value); + + return value; + #endif + case_end; + + case_ast_node(cl, CompoundLit, expr); + return ssa_addr_load(p, ssa_build_addr(p, expr)); + case_end; + + + case_ast_node(ce, CallExpr, expr); + if (map_tav_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + ssaValue *x = ssa_build_expr(p, ce->args.e[0]); + return ssa_emit_conv(p, x, tv->type); + } + + AstNode *p = unparen_expr(ce->proc); + GB_PANIC("TODO(bill): ssa_build_expr CallExpr"); + case_end; + + case_ast_node(se, SliceExpr, expr); + return ssa_addr_load(p, ssa_build_addr(p, expr)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + return ssa_addr_load(p, ssa_build_addr(p, expr)); + case_end; } + GB_PANIC("Unexpected expression: %.*s", LIT(ast_node_strings[expr->kind])); return NULL; } @@ -1566,21 +1955,43 @@ void ssa_build_when_stmt(ssaProc *p, AstNodeWhenStmt *ws) { } void ssa_build_assign_op(ssaProc *p, ssaAddr lhs, ssaValue *value, TokenKind op) { - // ssaValue *old_value = ssa_addr_load(p, lhs); - // Type *type = old_value->type; + ssaValue *old_value = ssa_addr_load(p, lhs); + Type *type = old_value->type; - // ssaValue *change = value; - // if (is_type_pointer(type) && is_type_integer(value->type)) { - // change = ssa_emit_conv(p, value, default_type(value->type)); - // } else { - // change = ssa_emit_conv(p, value, type); - // } - // ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type); - // ssa_addr_store(p, lhs, new_value); + ssaValue *change = value; + if (is_type_pointer(type) && is_type_integer(value->type)) { + change = ssa_emit_conv(p, value, default_type(value->type)); + } else { + change = ssa_emit_conv(p, value, type); + } + ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type); + ssa_addr_store(p, lhs, new_value); } - +void ssa_build_stmt_internal(ssaProc *p, AstNode *node); void ssa_build_stmt(ssaProc *p, AstNode *node) { + u32 prev_stmt_state_flags = p->module->stmt_state_flags; + + if (node->stmt_state_flags != 0) { + u32 in = node->stmt_state_flags; + u32 out = p->module->stmt_state_flags; + + if (in & StmtStateFlag_bounds_check) { + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; + } else if (in & StmtStateFlag_no_bounds_check) { + out |= StmtStateFlag_no_bounds_check; + out &= ~StmtStateFlag_bounds_check; + } + + p->module->stmt_state_flags = out; + } + + ssa_build_stmt_internal(p, node); + + p->module->stmt_state_flags = prev_stmt_state_flags; +} +void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { if (p->curr_block == NULL) { ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, ""); ssa_start_block(p, dead_block); @@ -1591,7 +2002,9 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { case_end; case_ast_node(bs, BlockStmt, node); + ssa_open_scope(p); ssa_build_stmt_list(p, bs->stmts); + ssa_close_scope(p, ssaDeferExit_Default, NULL); case_end; case_ast_node(us, UsingStmt, node); @@ -1649,11 +2062,11 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { if (init == NULL) { // TODO(bill): remove this continue; } - Type *t = type_deref(init->type); - if (init->op == ssaOp_Addr && t->kind == Type_Tuple) { + Type *t = base_type(init->type); + if (t->kind == Type_Tuple) { for (isize i = 0; i < t->Tuple.variable_count; i++) { - Entity *e = t->Tuple.variables[i]; - ssaValue *v = ssa_emit_ptr_index(p, init, i); + // Entity *e = t->Tuple.variables[i]; + ssaValue *v = ssa_emit_value_index(p, init, i); array_add(&inits, v); } } else { @@ -1667,6 +2080,8 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } gb_temp_arena_memory_end(tmp); + } else { + GB_PANIC("TODO(bill): ssa_build_stmt Type/Proc Entities"); } case_end; @@ -1714,12 +2129,12 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { for_array(i, as->rhs) { ssaValue *init = ssa_build_expr(p, as->rhs.e[i]); - Type *t = type_deref(init->type); + Type *t = base_type(init->type); // TODO(bill): refactor for code reuse as this is repeated a bit - if (init->op == ssaOp_Addr && t->kind == Type_Tuple) { + if (t->kind == Type_Tuple) { for (isize i = 0; i < t->Tuple.variable_count; i++) { Entity *e = t->Tuple.variables[i]; - ssaValue *v = ssa_emit_ptr_index(p, init, i); + ssaValue *v = ssa_emit_value_index(p, init, i); array_add(&inits, v); } } else { @@ -1734,14 +2149,14 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } break; default: { - GB_PANIC("TODO(bill): assign operations"); + // GB_PANIC("TODO(bill): assign operations"); // NOTE(bill): Only 1 += 1 is allowed, no tuples // +=, -=, etc - // i32 op = cast(i32)as->op.kind; - // op += Token_Add - Token_AddEq; // Convert += to + - // ssaAddr lhs = ssa_build_addr(p, as->lhs.e[0]); - // ssaValue *value = ssa_build_expr(p, as->rhs.e[0]); - // ssa_build_assign_op(p, lhs, value, cast(TokenKind)op); + i32 op = cast(i32)as->op.kind; + op += Token_Add - Token_AddEq; // Convert += to + + ssaAddr lhs = ssa_build_addr(p, as->lhs.e[0]); + ssaValue *value = ssa_build_expr(p, as->rhs.e[0]); + ssa_build_assign_op(p, lhs, value, cast(TokenKind)op); } break; } @@ -1754,7 +2169,13 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { case_end; case_ast_node(ds, DeferStmt, node); - GB_PANIC("TODO: DeferStmt"); + // GB_PANIC("TODO: DeferStmt"); + ssa_emit_comment(p, str_lit("DeferStmt")); + i32 scope_level = p->scope_level; + if (ds->stmt->kind == AstNode_BlockStmt) { + scope_level--; + } + ssa_add_defer_node(p, scope_level, ds->stmt); case_end; case_ast_node(rs, ReturnStmt, node); @@ -1780,18 +2201,18 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { ssa_build_cond(p, is->cond, then, else_); ssa_start_block(p, then); - // ssa_open_scope(p); + ssa_open_scope(p); ssa_build_stmt(p, is->body); - // ssa_close_scope(p, ssaDeferExit_Default, NULL); + ssa_close_scope(p, ssaDeferExit_Default, NULL); ssa_emit_jump(p, done); if (is->else_stmt != NULL) { ssa_start_block(p, else_); - // ssa_open_scope(p); + ssa_open_scope(p); ssa_build_stmt(p, is->else_stmt); - // ssa_close_scope(p, ssaDeferExit_Default, NULL); + ssa_close_scope(p, ssaDeferExit_Default, NULL); ssa_emit_jump(p, done); } @@ -1829,9 +2250,9 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } ssa_push_target_list(p, done, post, NULL); - // ssa_open_scope(p); + ssa_open_scope(p); ssa_build_stmt(p, fs->body); - // ssa_close_scope(p, ssaDeferExit_Default, NULL); + ssa_close_scope(p, ssaDeferExit_Default, NULL); ssa_pop_target_list(p); ssa_emit_jump(p, post); @@ -1877,7 +2298,7 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { break; } if (b != NULL) { - // ssa_emit_defer_stmts(p, irDeferExit_Branch, b); + ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b); } switch (bs->token.kind) { case Token_break: ssa_emit_comment(p, str_lit("break")); break; @@ -1986,6 +2407,9 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { gb_fprintf(f, " b%d", pred->id); } } + if (b->name.len > 0) { + gb_fprintf(f, " ; %.*s", LIT(b->name)); + } gb_fprintf(f, "\n"); isize n = 0; @@ -2087,6 +2511,10 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) { ssa_start_block(p, p->entry); ssa_build_stmt(p, pl->body); + if (p->entity->type->Proc.result_count == 0) { + ssa_emit_defer_stmts(p, ssaDeferExit_Return, NULL); + } + p->exit = ssa_new_block(p, ssaBlock_Exit, "exit"); ssa_emit_jump(p, p->exit); diff --git a/src/ssa_op.c b/src/ssa_op.c index 22bde663d..4c1921065 100644 --- a/src/ssa_op.c +++ b/src/ssa_op.c @@ -7,7 +7,6 @@ \ SSA_OP(SP) /* Stack Pointer */\ SSA_OP(SB) /* Stack Base */\ - SSA_OP(Addr) /* Address of something - special rules for certain types when loading and storing (e.g. Maps) */\ \ SSA_OP(Local)\ SSA_OP(Global)\ diff --git a/src/types.c b/src/types.c index 22c7eea64..8c13cfb9a 100644 --- a/src/types.c +++ b/src/types.c @@ -1143,7 +1143,7 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { } } - { + if (px.params != NULL && py.params != NULL) { Entity *ex = px.params->Tuple.variables[0]; Entity *ey = py.params->Tuple.variables[0]; bool ok = are_types_identical(ex->type, ey->type); @@ -1159,18 +1159,6 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { gb_global Entity *entity__any_type_info = NULL; gb_global Entity *entity__any_data = NULL; -gb_global Entity *entity__string_data = NULL; -gb_global Entity *entity__string_count = NULL; -gb_global Entity *entity__slice_count = NULL; -gb_global Entity *entity__slice_capacity = NULL; - -gb_global Entity *entity__dynamic_array_count = NULL; -gb_global Entity *entity__dynamic_array_capacity = NULL; -gb_global Entity *entity__dynamic_array_allocator = NULL; - -gb_global Entity *entity__dynamic_map_count = NULL; -gb_global Entity *entity__dynamic_map_capacity = NULL; -gb_global Entity *entity__dynamic_map_allocator = NULL; Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel); @@ -1262,52 +1250,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } #endif } break; - case Basic_string: { - #if 0 - String data_str = str_lit("data"); - String count_str = str_lit("count"); - if (entity__string_data == NULL) { - entity__string_data = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, t_u8), false, 0); - } - - if (entity__string_count == NULL) { - entity__string_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1); - } - - if (str_eq(field_name, data_str)) { - selection_add_index(&sel, 0); - sel.entity = entity__string_data; - return sel; - } else if (str_eq(field_name, count_str)) { - selection_add_index(&sel, 1); - sel.entity = entity__string_count; - return sel; - } - #endif - } break; } return sel; - } else if (type->kind == Type_Array) { - #if 0 - String count_str = str_lit("count"); - // NOTE(bill): Underlying memory address cannot be changed - if (str_eq(field_name, count_str)) { - // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Array.count)); - return sel; - } - #endif } else if (type->kind == Type_Vector) { - #if 0 - String count_str = str_lit("count"); - // NOTE(bill): Vectors are not addressable - if (str_eq(field_name, count_str)) { - // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Vector.count)); - return sel; - } - #endif if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) { // HACK(bill): Memory leak switch (type->Vector.count) { @@ -1329,103 +1275,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n #undef _VECTOR_FIELD_CASE } } - - } else if (type->kind == Type_Slice) { - #if 0 - String data_str = str_lit("data"); - String count_str = str_lit("count"); - String capacity_str = str_lit("capacity"); - - if (str_eq(field_name, data_str)) { - selection_add_index(&sel, 0); - // HACK(bill): Memory leak - sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->Slice.elem), false, 0); - return sel; - } else if (str_eq(field_name, count_str)) { - selection_add_index(&sel, 1); - if (entity__slice_count == NULL) { - entity__slice_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1); - } - - sel.entity = entity__slice_count; - return sel; - } else if (str_eq(field_name, capacity_str)) { - selection_add_index(&sel, 2); - if (entity__slice_capacity == NULL) { - entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2); - } - - sel.entity = entity__slice_capacity; - return sel; - } - #endif - } else if (type->kind == Type_DynamicArray) { - #if 0 - String data_str = str_lit("data"); - String count_str = str_lit("count"); - String capacity_str = str_lit("capacity"); - String allocator_str = str_lit("allocator"); - - if (str_eq(field_name, data_str)) { - selection_add_index(&sel, 0); - // HACK(bill): Memory leak - sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->DynamicArray.elem), false, 0); - return sel; - } else if (str_eq(field_name, count_str)) { - selection_add_index(&sel, 1); - if (entity__dynamic_array_count == NULL) { - entity__dynamic_array_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1); - } - sel.entity = entity__dynamic_array_count; - return sel; - } else if (str_eq(field_name, capacity_str)) { - selection_add_index(&sel, 2); - if (entity__dynamic_array_capacity == NULL) { - entity__dynamic_array_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2); - } - sel.entity = entity__dynamic_array_capacity; - return sel; - } else if (str_eq(field_name, allocator_str)) { - selection_add_index(&sel, 3); - if (entity__dynamic_array_allocator == NULL) { - entity__dynamic_array_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 3); - } - sel.entity = entity__dynamic_array_allocator; - return sel; - } - #endif - } else if (type->kind == Type_Map) { - #if 0 - String count_str = str_lit("count"); - String capacity_str = str_lit("capacity"); - String allocator_str = str_lit("allocator"); - - if (str_eq(field_name, count_str)) { - selection_add_index(&sel, 0); - if (entity__dynamic_map_count == NULL) { - entity__dynamic_map_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 0); - entity__dynamic_map_count->Variable.is_immutable = true; - } - sel.entity = entity__dynamic_map_count; - return sel; - } else if (str_eq(field_name, capacity_str)) { - selection_add_index(&sel, 1); - if (entity__dynamic_map_capacity == NULL) { - entity__dynamic_map_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 1); - entity__dynamic_map_capacity->Variable.is_immutable = true; - } - sel.entity = entity__dynamic_map_capacity; - return sel; - } else if (str_eq(field_name, allocator_str)) { - selection_add_index(&sel, 2); - if (entity__dynamic_map_allocator == NULL) { - entity__dynamic_map_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 2); - entity__dynamic_map_allocator->Variable.is_immutable = true; - } - sel.entity = entity__dynamic_map_allocator; - return sel; - } - #endif } if (is_type) { |