diff --git a/examples/test.c b/examples/test.c index bf1d9fafe..49a4a64da 100644 --- a/examples/test.c +++ b/examples/test.c @@ -1,11 +1,8 @@ +void test(void) { +} + int main() { - int x = 15; - int y = 4; - x = x & (~y); - if (x > 0) { - x = 123; - } else { - x = 321; - } + void (*f)(void) = test; + return 0; } diff --git a/examples/test.ll b/examples/test.ll index c8d5f46ee..a66808824 100644 --- a/examples/test.ll +++ b/examples/test.ll @@ -1,17 +1,6 @@ +; ModuleID = '..\examples/test.bc' + define void @main() { -entry: - %0 = alloca i64, align 8 ; x - store i64 zeroinitializer, i64* %0 - store i64 15, i64* %0 - %1 = load i64, i64* %0 - %2 = icmp sgt i64 %1, 0 - br i1 %2, label %if-then, label %if-else -if-then: - store i64 123, i64* %0 - br label %if-end -if-else: - store i64 321, i64* %0 - br label %if-end -if-end: - ret void +"entry - 0": + ret void } diff --git a/examples/test.odin b/examples/test.odin index 1f1de7750..fd7194210 100644 --- a/examples/test.odin +++ b/examples/test.odin @@ -1,8 +1,2 @@ main :: proc() { - x : int = 15; - if x > 0 { - x = 123; - } else { - x = 321; - } } diff --git a/run.bat b/run.bat index 3f25c6ca1..2ed5d13f0 100644 --- a/run.bat +++ b/run.bat @@ -2,8 +2,7 @@ rem del "..\examples\test.bc" -call ..\bin\odin.exe ..\examples/test.odin -call lli ..\examples/test.ll -rem call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc -rem call llvm-dis ..\examples/test.bc -o ..\examples/test.ll +call ..\bin\odin.exe ..\examples/test.odin && lli ..\examples/test.ll +call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc +call llvm-dis ..\examples/test.bc -o ..\examples/test.ll call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index e6bf8b2ff..5a03baa76 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -101,6 +101,7 @@ struct Scope { Scope *prev, *next; Scope *first_child, *last_child; Map elements; // Key: String + gbArray(AstNode *) deferred_stmts; }; enum ExpressionKind { @@ -154,13 +155,14 @@ struct CheckerContext { DeclInfo *decl; }; +// NOTE(bill): Symbol tables struct CheckerInfo { Map types; // Key: AstNode * | Expression -> Type (and value) Map definitions; // Key: AstNode * | Identifier -> Entity Map uses; // Key: AstNode * | Identifier -> Entity Map scopes; // Key: AstNode * | Node -> Scope Map untyped; // Key: AstNode * | Expression -> ExpressionInfo - Map entities; // Key: Entity * + Map entities; // Key: Entity * }; struct Checker { @@ -190,6 +192,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); s->parent = parent; map_init(&s->elements, gb_heap_allocator()); + gb_array_init(s->deferred_stmts, gb_heap_allocator()); if (parent != NULL && parent != universal_scope) { DLIST_APPEND(parent->first_child, parent->last_child, s); } @@ -504,6 +507,12 @@ void check_close_scope(Checker *c) { c->context.scope = c->context.scope->parent; } +void check_add_deferred_stmt(Checker *c, AstNode *stmt) { + GB_ASSERT(stmt != NULL); + GB_ASSERT(is_ast_node_stmt(stmt)); + gb_array_append(c->context.scope->deferred_stmts, stmt); +} + void push_procedure(Checker *c, Type *procedure_type) { gb_array_append(c->procedure_stack, procedure_type); } @@ -512,7 +521,6 @@ void pop_procedure(Checker *c) { gb_array_pop(c->procedure_stack); } - void add_curr_ast_file(Checker *c, AstFile *file) { gb_zero_item(&c->error_collector); c->curr_ast_file = file; diff --git a/src/checker/statements.cpp b/src/checker/statements.cpp index bf6f0d87b..8910e7d3d 100644 --- a/src/checker/statements.cpp +++ b/src/checker/statements.cpp @@ -724,7 +724,6 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(fs, ForStmt, node); - flags |= Statement_BreakAllowed | Statement_ContinueAllowed; check_open_scope(c, node); defer (check_close_scope(c)); @@ -739,9 +738,9 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { "Non-boolean condition in `for` statement"); } } - if (fs->end != NULL) - check_stmt(c, fs->end, 0); - check_stmt(c, fs->body, flags); + if (fs->post != NULL) + check_stmt(c, fs->post, 0); + check_stmt(c, fs->body, flags | Statement_BreakAllowed | Statement_ContinueAllowed); case_end; case_ast_node(ds, DeferStmt, node); @@ -752,6 +751,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { c->in_defer = true; check_stmt(c, ds->stmt, 0); c->in_defer = out_in_defer; + check_add_deferred_stmt(c, ds->stmt); } case_end; diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 94ccabe0f..7e9397580 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -36,6 +36,7 @@ void ssa_gen_code(ssaGen *s) { ssaModule *m = &s->module; CheckerInfo *info = m->info; gbAllocator a = m->allocator; + gb_for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key; @@ -66,8 +67,8 @@ void ssa_gen_code(ssaGen *s) { gb_for_array(i, m->members.entries) { auto *entry = &m->members.entries[i]; ssaValue *v = entry->value; - if (v->kind == ssaValue_Procedure) - ssa_build_procedure(v); + if (v->kind == ssaValue_Proc) + ssa_build_proc(v); } ssa_print_llvm_ir(&s->output_file, &s->module); diff --git a/src/codegen/print.cpp b/src/codegen/print.cpp index c51a88de5..7991c9310 100644 --- a/src/codegen/print.cpp +++ b/src/codegen/print.cpp @@ -146,7 +146,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) { if (i > 0) ssa_fprintf(f, ", "); ssa_print_type(f, s, &t->procedure.params[i]); } - ssa_fprintf(f, ") "); + ssa_fprintf(f, ")*"); break; } } @@ -201,6 +201,12 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type } } +void ssa_print_block_name(gbFile *f, ssaBlock *b) { + ssa_fprintf(f, "\""); + ssa_print_escape_string(f, b->label); + ssa_fprintf(f, " - %d", b->id); + ssa_fprintf(f, "\""); +} void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) { if (value == NULL) { @@ -208,18 +214,21 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) return; } switch (value->kind) { + case ssaValue_Constant: + ssa_print_exact_value(f, m, value->constant.value, type_hint); + break; case ssaValue_TypeName: ssa_print_encoded_local(f, value->type_name.entity->token.string); break; case ssaValue_Global: ssa_print_encoded_global(f, value->global.entity->token.string); break; - case ssaValue_Procedure: + case ssaValue_Param: + ssa_print_encoded_local(f, value->param.entity->token.string); + break; + case ssaValue_Proc: ssa_print_encoded_global(f, value->proc.entity->token.string); break; - case ssaValue_Constant: { - ssa_print_exact_value(f, m, value->constant.value, type_hint); - } break; case ssaValue_Instr: ssa_fprintf(f, "%%%d", value->id); break; @@ -301,14 +310,34 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, ", ", instr->br.cond->id); } ssa_fprintf(f, "label "); - ssa_print_encoded_local(f, instr->br.true_block->label); + ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.true_block); if (instr->br.false_block != NULL) { ssa_fprintf(f, ", label "); - ssa_print_encoded_local(f, instr->br.false_block->label); + ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.false_block); } ssa_fprintf(f, "\n"); } break; + case ssaInstr_Ret: { + auto *ret = &instr->ret; + ssa_fprintf(f, "ret "); + if (ret->value == NULL) { + ssa_fprintf(f, "void"); + } else { + Type *t = ssa_value_type(ret->value); + ssa_print_type(f, m->sizes, t); + ssa_fprintf(f, " "); + ssa_print_value(f, m, ret->value, t); + } + + ssa_fprintf(f, "\n"); + + } break; + + case ssaInstr_Unreachable: { + ssa_fprintf(f, "unreachable\n"); + } break; + case ssaInstr_BinaryOp: { auto *bo = &value->instr.binary_op; Type *type = ssa_value_type(bo->left); @@ -391,6 +420,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { } void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { + if (m->layout.len > 0) { + ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout)); + } + gb_for_array(member_index, m->members.entries) { auto *entry = &m->members.entries[member_index]; ssaValue *v = entry->value; @@ -412,7 +445,7 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type)); } break; - case ssaValue_Procedure: { + case ssaValue_Proc: { ssaProcedure *proc = &v->proc; if (proc->body == NULL) { ssa_fprintf(f, "declare "); @@ -450,19 +483,20 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { ssa_fprintf(f, "\n"); } else { ssa_fprintf(f, "{\n"); - gb_for_array(i, proc->blocks.entries) { - ssaBlock *block = &proc->blocks.entries[i].value->block; - ssa_fprintf(f, "%.*s:\n", LIT(block->label)); + gb_for_array(i, proc->blocks) { + ssaBlock *block = proc->blocks[i]; + + if (i > 0) ssa_fprintf(f, "\n"); + ssa_print_block_name(f, block); + ssa_fprintf(f, ":\n"); + gb_for_array(j, block->instrs) { ssaValue *value = block->instrs[j]; ssa_print_instr(f, m, value); } } - if (proc_type->result_count == 0) { - ssa_fprintf(f, "\tret void\n"); - } - ssa_fprintf(f, "}\n"); + ssa_fprintf(f, "}\n\n"); } } break; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index a21d8fd67..d587000b5 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -9,6 +9,8 @@ struct ssaModule { BaseTypeSizes sizes; gbAllocator allocator; + String layout; + Map values; // Key: Entity * Map members; // Key: String i32 global_string_index; @@ -26,6 +28,13 @@ struct ssaBlock { gbArray(ssaValue *) values; }; +struct ssaTargetList { + ssaTargetList *prev; + ssaBlock *break_; + ssaBlock *continue_; + ssaBlock *fallthrough_; +}; + struct ssaProcedure { ssaModule *module; String name; @@ -35,8 +44,10 @@ struct ssaProcedure { AstNode *type_expr; AstNode *body; - Map blocks; + gbArray(ssaBlock *) blocks; ssaBlock *curr_block; + ssaTargetList *target_list; + gbArray(ssaValue *) anonymous_procedures; }; @@ -50,6 +61,8 @@ struct ssaProcedure { SSA_INSTR_KIND(GetElementPtr), \ SSA_INSTR_KIND(Convert), \ SSA_INSTR_KIND(Br), \ + SSA_INSTR_KIND(Ret), \ + SSA_INSTR_KIND(Unreachable), \ SSA_INSTR_KIND(BinaryOp), \ SSA_INSTR_KIND(Count), @@ -109,12 +122,13 @@ struct ssaInstr { isize index_count; b32 inbounds; } get_element_ptr; - struct { ssaValue *cond; ssaBlock *true_block; ssaBlock *false_block; } br; + struct { ssaValue *value; } ret; + struct {} unreachable; struct { Type *type; @@ -137,8 +151,9 @@ enum ssaValueKind { ssaValue_Constant, ssaValue_TypeName, ssaValue_Global, - ssaValue_Procedure, + ssaValue_Param, + ssaValue_Proc, ssaValue_Block, ssaValue_Instr, @@ -164,9 +179,14 @@ struct ssaValue { Type * type; ssaValue *value; } global; - ssaProcedure proc; - ssaBlock block; - ssaInstr instr; + struct { + ssaProcedure *parent; + Entity *entity; + Type * type; + } param; + ssaProcedure proc; + ssaBlock block; + ssaInstr instr; }; }; @@ -256,14 +276,16 @@ void ssa_instr_set_type(ssaInstr *instr, Type *type) { Type *ssa_value_type(ssaValue *value) { switch (value->kind) { + case ssaValue_Constant: + return value->constant.type; case ssaValue_TypeName: return value->type_name.type; case ssaValue_Global: return value->global.type; - case ssaValue_Procedure: + case ssaValue_Param: + return value->param.type; + case ssaValue_Proc: return value->proc.type; - case ssaValue_Constant: - return value->constant.type; case ssaValue_Instr: return ssa_instr_type(&value->instr); } @@ -279,7 +301,7 @@ void ssa_value_set_type(ssaValue *value, Type *type) { case ssaValue_Global: value->global.type = type; break; - case ssaValue_Procedure: + case ssaValue_Proc: value->proc.type = type; break; case ssaValue_Constant: @@ -329,7 +351,13 @@ ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value) { v->global.value = value; return v; } - +ssaValue *ssa_make_value_param(gbAllocator a, ssaProcedure *parent, Entity *e) { + ssaValue *v = ssa_alloc_value(a, ssaValue_Param); + v->param.parent = parent; + v->param.entity = e; + v->param.type = e->type; + return v; +} ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e) { @@ -408,6 +436,25 @@ ssaValue *ssa_make_instr_br(ssaProcedure *p, ssaValue *cond, ssaBlock *true_bloc return v; } +ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) { + ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Unreachable); + if (p->curr_block) { + gb_array_append(p->curr_block->values, v); + } + return v; +} + +ssaValue *ssa_make_instr_ret(ssaProcedure *p, ssaValue *value) { + ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Ret); + v->instr.ret.value = value; + if (p->curr_block) { + gb_array_append(p->curr_block->values, v); + } + return v; +} + + + ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) { ssaValue *v = ssa_alloc_value(a, ssaValue_Constant); v->constant.type = type; @@ -416,7 +463,7 @@ ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) { } ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclInfo *decl, ssaModule *m) { - ssaValue *v = ssa_alloc_value(a, ssaValue_Procedure); + ssaValue *v = ssa_alloc_value(a, ssaValue_Proc); v->proc.module = m; v->proc.entity = e; v->proc.type = e->type; @@ -433,7 +480,7 @@ ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope, v->block.parent = proc; gb_array_init(v->block.instrs, gb_heap_allocator()); - gb_array_init(v->block.values, gb_heap_allocator()); + gb_array_init(v->block.values, gb_heap_allocator()); return v; } @@ -467,48 +514,6 @@ ssaValue *ssa_add_global_string(ssaProcedure *proc, ExactValue value) { return g; } -ssaValue *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) { - Scope *scope = NULL; - Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); - if (found) scope = *found; - - // IMPORTANT TODO(bill): Check for duplicate labels and replace in a sane way - // if (map_get(&proc->blocks, hash_string(label)) != NULL) { - // GB_PANIC("Block of name `%.*s` already exists", LIT(label)); - // } - - ssaValue *block = ssa_make_value_block(proc, node, scope, label); - map_set(&proc->blocks, hash_string(label), block); - return block; -} - - -void ssa_begin_procedure_body(ssaProcedure *proc) { - map_init(&proc->blocks, gb_heap_allocator()); - ssaValue *b = ssa_add_block(proc, proc->body, make_string("entry")); - proc->curr_block = &b->block; -} - - -void ssa_end_procedure_body(ssaProcedure *proc) { -// Number registers - i32 reg_id = 0; - gb_for_array(i, proc->blocks.entries) { - ssaBlock *b = &proc->blocks.entries[i].value->block; - gb_for_array(j, b->instrs) { - ssaValue *value = b->instrs[j]; - ssaInstr *instr = &value->instr; - switch (instr->kind) { - case ssaInstr_Store: - case ssaInstr_Br: - continue; - } - value->id = reg_id; - reg_id++; - } - } -} - b32 ssa_is_blank_ident(AstNode *node) { if (node->kind == AstNode_Ident) { @@ -519,15 +524,25 @@ b32 ssa_is_blank_ident(AstNode *node) { } + ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) { instr->instr.parent = b; - gb_array_append(b->instrs, instr); + if (b) { + gb_array_append(b->instrs, instr); + } return instr; -} +} ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) { return ssa_block_emit(proc->curr_block, instr); } +ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) { + return ssa_emit(p, ssa_make_instr_store(p, address, value)); +} +ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) { + return ssa_emit(p, ssa_make_instr_load(p, address)); +} + ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e) { @@ -542,14 +557,13 @@ ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name) { return NULL; } - -ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) { - return ssa_emit(p, ssa_make_instr_store(p, address, value)); +ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { + ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e); + ssaValue *l = ssa_add_local(proc, e); + ssa_emit_store(proc, l, v); + return v; } -ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) { - return ssa_emit(p, ssa_make_instr_load(p, address)); -} ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) { switch (lval.kind) { @@ -585,6 +599,128 @@ Type *ssa_lvalue_type(ssaLvalue lval) { return NULL; } + +void ssa_build_stmt(ssaProcedure *proc, AstNode *s); + +void ssa_emit_defer_stmts(ssaProcedure *proc, ssaBlock *block) { + if (block == NULL) + return; + + // IMPORTANT TODO(bill): ssa defer - Place where needed!!! + + Scope *curr_scope = block->scope; + if (curr_scope == NULL) { + GB_PANIC("No scope found for deferred statements"); + } + + for (Scope *s = curr_scope; s != NULL; s = s->parent) { + isize count = gb_array_count(s->deferred_stmts); + for (isize i = count-1; i >= 0; i--) { + ssa_build_stmt(proc, s->deferred_stmts[i]); + } + } +} + +void ssa_emit_unreachable(ssaProcedure *proc) { + ssa_emit(proc, ssa_make_instr_unreachable(proc)); +} + +void ssa_emit_ret(ssaProcedure *proc, ssaValue *v) { + ssa_emit_defer_stmts(proc, proc->curr_block); + ssa_emit(proc, ssa_make_instr_ret(proc, v)); +} + +void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) { + ssa_emit(proc, ssa_make_instr_br(proc, NULL, block, NULL)); + proc->curr_block = NULL; +} + +void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) { + ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block); + ssa_emit(proc, br); + proc->curr_block = NULL; +} + + + + +ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) { + Scope *scope = NULL; + Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); + if (found) { + scope = *found; + } else { + GB_PANIC("Block scope not found"); + } + + ssaValue *block = ssa_make_value_block(proc, node, scope, label); + return &block->block; +} + +ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) { + ssaBlock *block = ssa__make_block(proc, node, label); + gb_array_append(proc->blocks, block); + return block; +} + + +void ssa_begin_procedure_body(ssaProcedure *proc) { + gb_array_init(proc->blocks, gb_heap_allocator()); + proc->curr_block = ssa_add_block(proc, proc->type_expr, make_string("entry")); + + if (proc->type->procedure.params != NULL) { + auto *params = &proc->type->procedure.params->tuple; + for (isize i = 0; i < params->variable_count; i++) { + Entity *e = params->variables[i]; + ssa_add_param(proc, e); + } + } +} + +void ssa_end_procedure_body(ssaProcedure *proc) { + if (proc->type->procedure.result_count == 0) { + ssa_emit_ret(proc, NULL); + } + +// Number blocks and registers + i32 reg_id = 0; + gb_for_array(i, proc->blocks) { + ssaBlock *b = proc->blocks[i]; + b->id = i; + gb_for_array(j, b->instrs) { + ssaValue *value = b->instrs[j]; + GB_ASSERT(value->kind == ssaValue_Instr); + ssaInstr *instr = &value->instr; + // NOTE(bill): Ignore non-returning instructions + switch (instr->kind) { + case ssaInstr_Store: + case ssaInstr_Br: + case ssaInstr_Ret: + case ssaInstr_Unreachable: + continue; + } + value->id = reg_id; + reg_id++; + } + } +} + +void ssa_push_target_list(ssaProcedure *proc, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) { + ssaTargetList *tl = gb_alloc_item(proc->module->allocator, ssaTargetList); + tl->prev = proc->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + proc->target_list = tl; +} + +void ssa_pop_target_list(ssaProcedure *proc) { + proc->target_list = proc->target_list->prev; +} + + + + ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { Type *src_type = ssa_value_type(value); if (are_types_identical(t, src_type)) @@ -632,18 +768,10 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue return ssa_emit(proc, v); } -ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) { +ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) { Type *a = get_base_type(ssa_value_type(left)); Type *b = get_base_type(ssa_value_type(right)); - if (op.kind == Token_CmpEq && - left->kind == ssaValue_Constant && left->constant.value.kind == ExactValue_Bool) { - if (left->constant.value.value_bool) { - if (is_type_boolean(b)) - return right; - } - } - if (are_types_identical(a, b)) { // NOTE(bill): No need for a conversion } else if (left->kind == ssaValue_Constant) { @@ -658,21 +786,6 @@ ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValu } -void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) { - ssaValue *br = ssa_make_instr_br(proc, NULL, block, NULL); - ssa_emit(proc, br); - proc->curr_block = NULL; -} - -void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) { - ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block); - ssa_emit(proc, br); - proc->curr_block = NULL; -} - - - - ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) { @@ -690,7 +803,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue auto *found = map_get(&proc->module->values, hash_pointer(e)); if (found) { - return ssa_emit_load(proc, *found); + ssaValue *v = *found; + if (v->kind == ssaValue_Proc) + return v; + return ssa_emit_load(proc, v); } case_end; @@ -699,9 +815,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(de, DerefExpr, expr); - ssaValue *load = ssa_lvalue_load(ssa_build_addr(proc, expr), proc); - ssa_value_set_type(load, type_deref(ssa_value_type(load))); - return load; + return ssa_lvalue_load(ssa_build_addr(proc, expr), proc); case_end; case_ast_node(ue, UnaryExpr, expr); @@ -754,9 +868,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case Token_LtEq: case Token_Gt: case Token_GtEq: { - ssaValue *cmp = ssa_emit_compare(proc, be->op, - ssa_build_expr(proc, be->left), - ssa_build_expr(proc, be->right)); + ssaValue *left = ssa_build_expr(proc, be->left); + ssaValue *right = ssa_build_expr(proc, be->right); + ssaValue *cmp = ssa_emit_comp(proc, be->op, left, right); return ssa_emit_conv(proc, cmp, default_type(tv->type)); } break; @@ -789,16 +903,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue // TODO(bill): Strings AstNode_IndexExpression } break; - case Type_Slice: { - ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc); - return ssa_emit_load(proc, v); - } break; - - case Type_Array: { - ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc); - return ssa_emit_load(proc, v); - } break; - + case Type_Slice: + case Type_Array: case Type_Pointer: { ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc); return ssa_emit_load(proc, v); @@ -807,6 +913,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(se, SelectorExpr, expr); + return ssa_build_expr(proc, se->selector); case_end; } @@ -846,6 +953,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(i, Ident, expr); if (ssa_is_blank_ident(expr)) { ssaLvalue val = {ssaLvalue_Blank}; + return val; } Entity *e = entity_of_ident(proc->module->info, expr); @@ -855,18 +963,10 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { return ssa_make_lvalue_address(v, expr); case_end; - case_ast_node(cl, CompoundLit, expr); - case_end; - case_ast_node(pe, ParenExpr, expr); return ssa_build_addr(proc, unparen_expr(expr)); case_end; - case_ast_node(de, DerefExpr, expr); - ssaValue *v = ssa_build_expr(proc, de->expr); - return ssa_make_lvalue_address(v, expr); - case_end; - case_ast_node(se, SelectorExpr, expr); case_end; @@ -889,6 +989,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case Type_Pointer: { ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc); ssaValue *load = ssa_emit_load(proc, e); + gb_printf("load: %s\n", type_to_string(ssa_value_type(load))); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, index, NULL, 1, false); @@ -896,6 +997,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { gep->instr.get_element_ptr.result_type = t->pointer.element; gep->instr.get_element_ptr.element_type = t->pointer.element; v = gep; + gb_printf("gep: %s\n", type_to_string(ssa_value_type(gep))); } break; case Type_Slice: { GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice"); @@ -906,6 +1008,18 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { return ssa_make_lvalue_address(ssa_emit(proc, v), expr); case_end; + case_ast_node(de, DerefExpr, expr); + // TODO(bill): Clean up + Type *t = type_of_expr(proc->module->info, de->expr); + t = type_deref(get_base_type(t)); + ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc); + ssaValue *load = ssa_emit_load(proc, e); + ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, NULL, NULL, 0, false); + gep->instr.get_element_ptr.result_type = t; + gep->instr.get_element_ptr.element_type = t; + return ssa_make_lvalue_address(ssa_emit(proc, gep), expr); + case_end; + // TODO(bill): Others address } @@ -938,15 +1052,13 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa case_ast_node(be, BinaryExpr, cond); if (be->op.kind == Token_CmpAnd) { - ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-true")); - ssaBlock *block = &b->block; + ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-true")); ssa_build_cond(proc, be->left, block, false_block); proc->curr_block = block; ssa_build_cond(proc, be->right, true_block, false_block); return; } else if (be->op.kind == Token_CmpOr) { - ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-false")); - ssaBlock *block = &b->block; + ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-false")); ssa_build_cond(proc, be->left, true_block, block); proc->curr_block = block; ssa_build_cond(proc, be->right, true_block, false_block); @@ -960,7 +1072,6 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa } -void ssa_build_stmt(ssaProcedure *proc, AstNode *s); void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) { for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next) @@ -1090,64 +1201,133 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { ssa_build_expr(proc, es->expr); case_end; - case_ast_node(bs, BlockStmt, s); + case_ast_node(bs, BlockStmt, s) ssa_build_stmt_list(proc, bs->list); case_end; + case_ast_node(bs, DeferStmt, s); + // NOTE(bill): is already handled with scope + case_end; + + case_ast_node(rs, ReturnStmt, s); + ssaValue *v = NULL; + auto *return_type_tuple = &proc->type->procedure.results->tuple; + isize return_count = proc->type->procedure.result_count; + if (rs->result_count == 1 && return_count > 1) { + GB_PANIC("ReturnStmt tuple return statement"); + } else if (return_count == 1) { + Entity *e = return_type_tuple->variables[0]; + v = ssa_emit_conv(proc, ssa_build_expr(proc, rs->result_list), e->type); + } else if (return_count == 0) { + // No return values + } else { + // 1:1 multiple return values + } + + ssa_emit_ret(proc, v); + + case_end; + case_ast_node(is, IfStmt, s); if (is->init != NULL) { ssa_build_stmt(proc, is->init); } - ssaValue *then_block = ssa_add_block(proc, is->body, make_string("if-then")); - ssaValue *else_block = NULL; + ssaBlock *then = ssa_add_block(proc, s, make_string("if.then")); + ssaBlock *done = ssa__make_block(proc, s, make_string("if.done")); + ssaBlock *else_ = done; if (is->else_stmt != NULL) { - else_block = ssa_add_block(proc, is->else_stmt, make_string("if-else")); - } - ssaValue *end_block = ssa_add_block(proc, is->body, make_string("if-end")); - if (else_block == NULL) { - else_block = end_block; + else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else")); } - ssa_build_cond(proc, is->cond, &then_block->block, &else_block->block); - proc->curr_block = &then_block->block; + ssa_build_cond(proc, is->cond, then, else_); + proc->curr_block = then; ssa_build_stmt(proc, is->body); - ssa_emit_jump(proc, &end_block->block); + ssa_emit_jump(proc, done); if (is->else_stmt != NULL) { - proc->curr_block = &else_block->block; + proc->curr_block = else_; ssa_build_stmt(proc, is->else_stmt); - ssa_emit_jump(proc, &end_block->block); + ssa_emit_jump(proc, done); } - - proc->curr_block = &end_block->block; - case_end; - - case_ast_node(rs, ReturnStmt, s); - GB_PANIC("AstNode_ReturnStmt"); + gb_array_append(proc->blocks, done); + proc->curr_block = done; case_end; case_ast_node(fs, ForStmt, s); - GB_PANIC("AstNode_ForStmt"); - case_end; + if (fs->init != NULL) { + ssa_build_stmt(proc, fs->init); + } + ssaBlock *body = ssa_add_block(proc, s, make_string("for.body")); + ssaBlock *done = ssa__make_block(proc, s, make_string("for.done")); // NOTE(bill): Append later + + ssaBlock *loop = body; + + if (fs->cond != NULL) { + loop = ssa_add_block(proc, fs->cond, make_string("for.loop")); + } + ssaBlock *cont = loop; + if (fs->post != NULL) { + cont = ssa_add_block(proc, fs->cond, make_string("for.post")); + } + ssa_emit_jump(proc, loop); + proc->curr_block = loop; + if (loop != body) { + ssa_build_cond(proc, fs->cond, body, done); + proc->curr_block = body; + } + + ssa_push_target_list(proc, done, cont, NULL); + ssa_build_stmt(proc, fs->body); + ssa_pop_target_list(proc); + ssa_emit_jump(proc, cont); + + if (fs->post != NULL) { + proc->curr_block = cont; + ssa_build_stmt(proc, fs->post); + ssa_emit_jump(proc, loop); + } + gb_array_append(proc->blocks, done); + proc->curr_block = done; - case_ast_node(bs, DeferStmt, s); - GB_PANIC("AstNode_DeferStmt"); case_end; case_ast_node(bs, BranchStmt, s); - GB_PANIC("AstNode_BranchStmt"); + ssaBlock *block = NULL; + switch (bs->token.kind) { + case Token_break: { + for (ssaTargetList *t = proc->target_list; + t != NULL && block == NULL; + t = t->prev) { + block = t->break_; + } + } break; + case Token_continue: { + for (ssaTargetList *t = proc->target_list; + t != NULL && block == NULL; + t = t->prev) { + block = t->continue_; + } + } break; + case Token_fallthrough: { + for (ssaTargetList *t = proc->target_list; + t != NULL && block == NULL; + t = t->prev) { + block = t->fallthrough_; + } + } break; + } + ssa_emit_jump(proc, block); + ssa_emit_unreachable(proc); case_end; + } } -void ssa_build_procedure(ssaValue *value) { +void ssa_build_proc(ssaValue *value) { ssaProcedure *proc = &value->proc; - // gb_printf("Building %.*s: %.*s\n", LIT(entity_strings[proc->entity->kind]), LIT(proc->name)); - - AstNode *proc_decl = proc->decl->proc_decl; switch (proc_decl->kind) { case_ast_node(pd, ProcDecl, proc_decl); @@ -1158,16 +1338,11 @@ void ssa_build_procedure(ssaValue *value) { return; } - if (proc->body == NULL) { - // TODO(bill): External procedure - return; + if (proc->body != NULL) { + ssa_begin_procedure_body(proc); + ssa_build_stmt(proc, proc->body); + ssa_end_procedure_body(proc); } - - - ssa_begin_procedure_body(proc); - ssa_build_stmt(proc, proc->body); - ssa_end_procedure_body(proc); - } diff --git a/src/parser.cpp b/src/parser.cpp index 39c7a4fe7..ddf63d93c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -144,7 +144,7 @@ AST_NODE_KIND(_ComplexStmtBegin, struct{}) \ }) \ AST_NODE_KIND(ForStmt, struct { \ Token token; \ - AstNode *init, *cond, *end; \ + AstNode *init, *cond, *post; \ AstNode *body; \ }) \ AST_NODE_KIND(DeferStmt, struct { Token token; AstNode *stmt; }) \ @@ -638,12 +638,12 @@ gb_inline AstNode *make_return_stmt(AstFile *f, Token token, AstNode *result_lis return result; } -gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *end, AstNode *body) { +gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) { AstNode *result = make_node(f, AstNode_ForStmt); result->ForStmt.token = token; result->ForStmt.init = init; result->ForStmt.cond = cond; - result->ForStmt.end = end; + result->ForStmt.post = post; result->ForStmt.body = body; return result; } diff --git a/src/printer.cpp b/src/printer.cpp index 143635cf7..cba9f0ddc 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -124,7 +124,7 @@ void print_ast(AstNode *node, isize indent) { gb_printf("(for)\n"); print_ast(node->ForStmt.init, indent+1); print_ast(node->ForStmt.cond, indent+1); - print_ast(node->ForStmt.end, indent+1); + print_ast(node->ForStmt.post, indent+1); print_ast(node->ForStmt.body, indent+1); break; case AstNode_DeferStmt: