diff --git a/examples/test.ll b/examples/test.ll index 295c13666..e69de29bb 100644 --- a/examples/test.ll +++ b/examples/test.ll @@ -1,23 +0,0 @@ -define void @main() { -"entry - 0": - %0 = alloca [16 x i64], align 8 ; a - store [16 x i64] zeroinitializer, [16 x i64]* %0 - %1 = alloca {i64*, i64, i64}, align 8 ; b - store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %1 - %2 = sub i64 1, 0 - %3 = sub i64 2, 0 - %4 = getelementptr inbounds [16 x i64], [16 x i64]* %0, i64 0, i64 0 - %5 = getelementptr i64, i64* %4, i64 0 - %6 = alloca {i64*, i64, i64}, align 8 - store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %6 - %7 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 0 - store i64* %5, i64** %7 - %8 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 1 - store i64 %2, i64* %8 - %9 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 2 - store i64 %3, i64* %9 - %10 = load {i64*, i64, i64}, {i64*, i64, i64}* %6 - store {i64*, i64, i64} %10, {i64*, i64, i64}* %1 - ret void -} - diff --git a/examples/test.odin b/examples/test.odin index a2054dcff..47090bfc0 100644 --- a/examples/test.odin +++ b/examples/test.odin @@ -1,5 +1,7 @@ +add :: proc(x, y : int) -> (int, int) { + return x+y, 1; +} + main :: proc() { - a : [16]int; - b := a[0:1:2]; } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 884032ba9..53ce8ac18 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -427,7 +427,6 @@ void add_untyped(CheckerInfo *i, AstNode *expression, b32 lhs, AddressingMode mo void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) { GB_ASSERT(expression != NULL); - GB_ASSERT(type != NULL); if (mode == Addressing_Invalid) return; @@ -530,8 +529,8 @@ void add_curr_ast_file(Checker *c, AstFile *file) { -#include "expression.cpp" -#include "statements.cpp" +#include "expr.cpp" +#include "stmt.cpp" diff --git a/src/checker/expression.cpp b/src/checker/expr.cpp similarity index 98% rename from src/checker/expression.cpp rename to src/checker/expr.cpp index 37fa071e3..7a1fdb70e 100644 --- a/src/checker/expression.cpp +++ b/src/checker/expr.cpp @@ -8,9 +8,9 @@ Type * check_type (Checker *c, AstNode *expression, Type *n void check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); void convert_to_typed (Checker *c, Operand *operand, Type *target_type); -gbString expr_to_string (AstNode *expression); +gbString expr_to_string (AstNode *expression); void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); -void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); +void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { @@ -1880,12 +1880,10 @@ ExpressionKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type break; } - if (type != NULL) { - if (is_type_untyped(type)) { - add_untyped(&c->info, node, false, o->mode, type, value); - } else { - add_type_and_value(&c->info, node, o->mode, type, value); - } + if (type != NULL && is_type_untyped(type)) { + add_untyped(&c->info, node, false, o->mode, type, value); + } else { + add_type_and_value(&c->info, node, o->mode, type, value); } return kind; } @@ -1972,7 +1970,9 @@ gbString write_field_list_to_string(gbString str, AstNode *field_list, char *sep } gbString string_append_token(gbString str, Token token) { - return gb_string_append_length(str, token.string.text, token.string.len); + if (token.string.len > 0) + return gb_string_append_length(str, token.string.text, token.string.len); + return str; } @@ -1980,9 +1980,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (node == NULL) return str; + if (is_ast_node_stmt(node)) { + GB_ASSERT("stmt passed to write_expr_to_string"); + } + switch (node->kind) { default: - str = gb_string_appendc(str, "(bad expression)"); + str = gb_string_appendc(str, "(BadExpr)"); break; case_ast_node(i, Ident, node); @@ -2000,7 +2004,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(cl, CompoundLit, node); str = gb_string_appendc(str, "("); str = write_expr_to_string(str, cl->type); - str = gb_string_appendc(str, " literal)"); + str = gb_string_appendc(str, " lit)"); case_end; case_ast_node(te, TagExpr, node); @@ -2061,7 +2065,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, ce->expr); case_end; - case_ast_node(pt, PointerType, node); str = gb_string_appendc(str, "^"); str = write_expr_to_string(str, pt->type); @@ -2079,7 +2082,9 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "("); isize i = 0; for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) { - if (i > 0) gb_string_appendc(str, ", "); + if (i > 0) { + str = gb_string_appendc(str, ", "); + } str = write_expr_to_string(str, arg); i++; } diff --git a/src/checker/statements.cpp b/src/checker/stmt.cpp similarity index 92% rename from src/checker/statements.cpp rename to src/checker/stmt.cpp index b1acd7cd5..676e74fa9 100644 --- a/src/checker/statements.cpp +++ b/src/checker/stmt.cpp @@ -265,31 +265,34 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNode *in if ((lhs == NULL || lhs_count == 0) && init_count == 0) return; - isize i = 0; - AstNode *rhs = init_list; - for (; - i < lhs_count && i < init_count && rhs != NULL; - i++, rhs = rhs->next) { - Operand operand = {}; - check_multi_expr(c, &operand, rhs); - if (operand.type->kind != Type_Tuple) { - check_init_variable(c, lhs[i], &operand, context_name); + // TODO(bill): Do not use heap allocation here if I can help it + gbArray(Operand) operands; + gb_array_init(operands, gb_heap_allocator()); + defer (gb_array_free(operands)); + + for (AstNode *rhs = init_list; rhs != NULL; rhs = rhs->next) { + Operand o = {}; + check_multi_expr(c, &o, rhs); + if (o.type->kind != Type_Tuple) { + gb_array_append(operands, o); } else { - auto *tuple = &operand.type->tuple; - for (isize j = 0; - j < tuple->variable_count && i < lhs_count && i < init_count; - j++, i++) { - Type *type = tuple->variables[j]->type; - operand.type = type; - check_init_variable(c, lhs[i], &operand, context_name); + auto *tuple = &o.type->tuple; + for (isize j = 0; j < tuple->variable_count; j++) { + o.type = tuple->variables[j]->type; + gb_array_append(operands, o); } } } - if (i < lhs_count && lhs[i]->type == NULL) { - error(&c->error_collector, lhs[i]->token, "Too few values on the right hand side of the declaration"); - } else if (rhs != NULL) { - error(&c->error_collector, ast_node_token(rhs), "Too many values on the right hand side of the declaration"); + isize rhs_count = gb_array_count(operands); + + isize max = gb_min(lhs_count, rhs_count); + for (isize i = 0; i < max; i++) { + check_init_variable(c, lhs[i], &operands[i], context_name); + } + + if (rhs_count > 0 && lhs_count != rhs_count) { + error(&c->error_collector, lhs[0]->token, "Assignment count mismatch `%td` := `%td`", lhs_count, rhs_count); } } @@ -599,36 +602,37 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { return; } - Operand operand = {}; - AstNode *lhs = as->lhs_list; - AstNode *rhs = as->rhs_list; - isize i = 0; - for (; - lhs != NULL && rhs != NULL; - lhs = lhs->next, rhs = rhs->next) { - check_multi_expr(c, &operand, rhs); - if (operand.type->kind != Type_Tuple) { - check_assignment_variable(c, &operand, lhs); - i++; + // TODO(bill): Do not use heap allocation here if I can help it + gbArray(Operand) operands; + gb_array_init(operands, gb_heap_allocator()); + defer (gb_array_free(operands)); + + for (AstNode *rhs = as->rhs_list; rhs != NULL; rhs = rhs->next) { + Operand o = {}; + check_multi_expr(c, &o, rhs); + if (o.type->kind != Type_Tuple) { + gb_array_append(operands, o); } else { - auto *tuple = &operand.type->tuple; - for (isize j = 0; - j < tuple->variable_count && lhs != NULL; - j++, i++, lhs = lhs->next) { - // TODO(bill): More error checking - operand.type = tuple->variables[j]->type; - check_assignment_variable(c, &operand, lhs); + auto *tuple = &o.type->tuple; + for (isize j = 0; j < tuple->variable_count; j++) { + o.type = tuple->variables[j]->type; + gb_array_append(operands, o); } - if (lhs == NULL) - break; } } - if (i < as->lhs_count && i < as->rhs_count) { - if (lhs == NULL) - error(&c->error_collector, ast_node_token(lhs), "Too few values on the right hand side of the declaration"); - } else if (rhs != NULL) { - error(&c->error_collector, ast_node_token(rhs), "Too many values on the right hand side of the declaration"); + isize lhs_count = as->lhs_count; + isize rhs_count = gb_array_count(operands); + + isize operand_index = 0; + for (AstNode *lhs = as->lhs_list; + lhs != NULL; + lhs = lhs->next, operand_index++) { + check_assignment_variable(c, &operands[operand_index], lhs); + + } + if (lhs_count != rhs_count) { + error(&c->error_collector, ast_node_token(as->lhs_list), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); } } break; diff --git a/src/checker/type.cpp b/src/checker/type.cpp index e2506b3a2..04eefbcdd 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -268,6 +268,8 @@ gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_pointer = &basic_types[Basic_UntypedPointer]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; +gb_global Type *t_byte = &basic_type_aliases[Basic_byte]; +gb_global Type *t_rune = &basic_type_aliases[Basic_rune]; b32 is_type_named(Type *t) { diff --git a/src/codegen/print.cpp b/src/codegen/print.cpp index d8e43766c..f6f1afe42 100644 --- a/src/codegen/print.cpp +++ b/src/codegen/print.cpp @@ -157,17 +157,13 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type ssa_fprintf(f, (value.value_bool ? "true" : "false")); break; case ExactValue_String: { - ssa_fprintf(f, "{"); - ssa_print_type(f, m->sizes, t_i8); - ssa_fprintf(f, "* c\""); + ssa_fprintf(f, "c\""); // TODO(bill): Make unquote string function String unquoted = value.value_string; unquoted.text++; unquoted.len -= 2; ssa_print_escape_string(f, unquoted); - ssa_fprintf(f, "\", "); - ssa_print_type(f, m->sizes, t_int); - ssa_fprintf(f, " %td}", value.value_string.len); + ssa_fprintf(f, "\""); } break; case ExactValue_Integer: ssa_fprintf(f, "%lld", value.value_integer); @@ -417,6 +413,36 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { } break; + case ssaInstr_Call: { + auto *call = &instr->call; + if (call->type) { + ssa_fprintf(f, "%%%d = ", value->id); + } + ssa_fprintf(f, "call "); + if (call->type) { + ssa_print_type(f, m->sizes, call->type); + } else { + ssa_fprintf(f, "void"); + } + ssa_fprintf(f, " "); + ssa_print_value(f, m, call->value, call->type); + + + ssa_fprintf(f, "("); + for (isize i = 0; i < call->arg_count; i++) { + ssaValue *arg = call->args[i]; + Type *t = ssa_value_type(arg); + if (i > 0) { + ssa_fprintf(f, ", "); + } + ssa_print_type(f, m->sizes, t); + ssa_fprintf(f, " "); + ssa_print_value(f, m, arg, t); + } + ssa_fprintf(f, ")\n"); + + } break; + default: ssa_fprintf(f, "; %d\n", instr->kind); break; @@ -442,11 +468,17 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { case ssaValue_Global: { auto *g = &v->global; ssa_print_encoded_global(f, g->entity->token.string); - ssa_fprintf(f, " = global "); + ssa_fprintf(f, " = "); + if (g->is_constant) { + ssa_fprintf(f, "private constant "); + } else { + ssa_fprintf(f, "global "); + } + ssa_print_type(f, m->sizes, get_base_type(g->entity->type)); ssa_fprintf(f, " "); ssa_print_value(f, m, g->value, g->entity->type); - ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type)); + ssa_fprintf(f, "\n"); } break; case ssaValue_Proc: { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 4d0dd29a5..b387df1fc 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -64,6 +64,7 @@ struct ssaProcedure { SSA_INSTR_KIND(Ret), \ SSA_INSTR_KIND(Unreachable), \ SSA_INSTR_KIND(BinaryOp), \ + SSA_INSTR_KIND(Call), \ SSA_INSTR_KIND(Count), enum ssaInstrKind { @@ -122,6 +123,11 @@ struct ssaInstr { isize index_count; b32 inbounds; } get_element_ptr; + struct { + ssaConversionKind kind; + ssaValue *value; + Type *from, *to; + } conversion; struct { ssaValue *cond; ssaBlock *true_block; @@ -129,18 +135,17 @@ struct ssaInstr { } br; struct { ssaValue *value; } ret; struct {} unreachable; - struct { Type *type; Token op; ssaValue *left, *right; } binary_op; - struct { - ssaConversionKind kind; + Type *type; // return type ssaValue *value; - Type *from, *to; - } conversion; + ssaValue **args; + isize arg_count; + } call; }; }; @@ -152,6 +157,7 @@ enum ssaValueKind { ssaValue_TypeName, ssaValue_Global, ssaValue_Param, + ssaValue_GlobalString, ssaValue_Proc, ssaValue_Block, @@ -174,7 +180,7 @@ struct ssaValue { Type * type; } type_name; struct { - b32 is_gen; + b32 is_constant; Entity * entity; Type * type; ssaValue *value; @@ -463,6 +469,18 @@ ssaValue *ssa_make_instr_ret(ssaProcedure *p, ssaValue *value) { return v; } +ssaValue *ssa_make_instr_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count, Type *result_type) { + ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Call); + v->instr.call.value = value; + v->instr.call.args = args; + v->instr.call.arg_count = arg_count; + v->instr.call.type = result_type; + if (p->curr_block) { + gb_array_append(p->curr_block->values, v); + } + return v; +} + @@ -497,35 +515,6 @@ ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope, } - -ssaValue *ssa_add_global_string(ssaProcedure *proc, ExactValue value) { - GB_ASSERT(value.kind == ExactValue_String); - gbAllocator a = gb_heap_allocator(); - - - isize max_len = 4+8+1; - u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); - isize len = gb_snprintf(cast(char *)str, max_len, ".str%x", proc->module->global_string_index); - proc->module->global_string_index++; - - String name = make_string(str, len-1); - Token token = {Token_String}; - token.string = name; - Type *type = &basic_types[Basic_string]; - Entity *entity = make_entity_constant(a, NULL, token, type, value); - ssaValue *v = ssa_make_value_constant(a, type, value); - - - ssaValue *g = ssa_make_value_global(a, entity, v); - g->global.is_gen = true; - - map_set(&proc->module->values, hash_pointer(entity), g); - map_set(&proc->module->members, hash_string(name), g); - - return g; -} - - b32 ssa_is_blank_ident(AstNode *node) { if (node->kind == AstNode_Ident) { ast_node(i, Ident, node); @@ -565,6 +554,14 @@ ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name) { return NULL; } +ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) { + Entity *entity = make_entity_variable(proc->module->allocator, + proc->curr_block->scope, + empty_token, + type); + return ssa_emit(proc, ssa_make_instr_local(proc, entity)); +} + 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); @@ -706,6 +703,11 @@ void ssa_end_procedure_body(ssaProcedure *proc) { case ssaInstr_Ret: case ssaInstr_Unreachable: continue; + case ssaInstr_Call: + if (instr->call.type == NULL) { + continue; + } + break; } value->id = reg_id; reg_id++; @@ -789,7 +791,7 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue * } ssaValue *v = ssa_make_instr_binary_op(proc, op, left, right); - ssa_value_set_type(v, &basic_types[Basic_bool]); + ssa_value_set_type(v, t_bool); return ssa_emit(proc, v); } @@ -852,7 +854,26 @@ ssaValue *ssa_slice_cap(ssaProcedure *proc, ssaValue *slice) { return ssa_emit_load(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int)); } +ssaValue *ssa_string_elem(ssaProcedure *proc, ssaValue *string) { + Type *t = ssa_value_type(string); + GB_ASSERT(t->kind == Type_Basic && t->basic.kind == Basic_string); + Type *base_type = t_u8; + ssaValue *elem = ssa_make_instr_get_element_ptr(proc, string, v_zero, v_zero32, 2, true); + Type *result_type = make_type_pointer(proc->module->allocator, base_type); + elem->instr.get_element_ptr.element_type = t; + elem->instr.get_element_ptr.result_type = result_type; + ssa_emit(proc, elem); + return ssa_emit_load(proc, elem); +} +ssaValue *ssa_string_len(ssaProcedure *proc, ssaValue *string) { + Type *t = ssa_value_type(string); + GB_ASSERT(t->kind == Type_Basic && t->basic.kind == Basic_string); + return ssa_emit_load(proc, ssa_emit_struct_gep(proc, string, v_one32, t_int)); +} +ssaValue *ssa_string_cap(ssaProcedure *proc, ssaValue *string) { + return ssa_string_len(proc, string); +} @@ -894,13 +915,7 @@ ssaValue *ssa_emit_slice(ssaProcedure *proc, Type *slice_type, ssaValue *base, s elem = ssa_emit_ptr_offset(proc, elem, low); - // NOTE(bill): Just used as dummy entity - never to be used really - Entity *slice_entity = make_entity_variable(proc->module->allocator, - proc->curr_block->scope, - empty_token, - slice_type); - - ssaValue *slice = ssa_emit(proc, ssa_make_instr_local(proc, slice_entity)); + ssaValue *slice = ssa_add_local_generated(proc, slice_type); ssaValue *gep = NULL; gep = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_value_type(elem)); @@ -916,6 +931,80 @@ ssaValue *ssa_emit_slice(ssaProcedure *proc, Type *slice_type, ssaValue *base, s } + +ssaValue *ssa_add_global_string_array(ssaProcedure *proc, ExactValue value) { + GB_ASSERT(value.kind == ExactValue_String); + gbAllocator a = gb_heap_allocator(); + + isize max_len = 4+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, ".str%x", proc->module->global_string_index); + proc->module->global_string_index++; + + String name = make_string(str, len-1); + Token token = {Token_String}; + token.string = name; + // TODO(bill): unquote function + Type *type = make_type_array(a, t_u8, value.value_string.len-2); + Entity *entity = make_entity_constant(a, NULL, token, type, value); + ssaValue *v = ssa_make_value_constant(a, type, value); + + ssaValue *g = ssa_make_value_global(a, entity, v); + g->global.is_constant = true; + + map_set(&proc->module->values, hash_pointer(entity), g); + map_set(&proc->module->members, hash_string(name), g); + + return g; +} + +ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) { + Type *t_u8_ptr = ssa_value_type(elem); + GB_ASSERT(t_u8_ptr->kind == Type_Pointer); + GB_ASSERT(t_u8_ptr->pointer.element == t_u8); + + ssaValue *str = ssa_add_local_generated(proc, t_string); + ssaValue *str_elem = ssa_emit_struct_gep(proc, str, v_zero32, t_u8_ptr); + ssaValue *str_len = ssa_emit_struct_gep(proc, str, v_one32, t_int); + ssa_emit_store(proc, str_elem, elem); + ssa_emit_store(proc, str_len, len); + return ssa_emit_load(proc, str); +} + +ssaValue *ssa_emit_call(ssaProcedure *proc, AstNode *expr, Type *result_type) { + ast_node(ce, CallExpr, expr); + + ssaValue *value = ssa_build_expr(proc, ce->proc); + Type *proc_type_ = ssa_value_type(value); + GB_ASSERT(proc_type_->kind == Type_Procedure); + auto *type = &proc_type_->procedure; + + isize arg_index = 0; + isize arg_count = type->param_count; + ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, arg_count); + + for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) { + ssaValue *a = ssa_build_expr(proc, arg); + Type *at = ssa_value_type(a); + if (at->kind == Type_Tuple) { + GB_PANIC("TODO(bill): tuple call arguments"); + } else { + args[arg_index++] = a; + } + } + + for (isize i = 0; i < arg_count; i++) { + Entity *e = type->params->tuple.variables[i]; + args[i] = ssa_emit_conv(proc, args[i], e->type); + } + + ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, result_type); + return ssa_emit(proc, call); +} + + + + ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) { switch (expr->kind) { case_ast_node(bl, BasicLit, expr); @@ -1011,16 +1100,24 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } case_end; - case_ast_node(se, ProcLit, expr); + case_ast_node(pl, ProcLit, expr); GB_PANIC("TODO(bill): ssa_build_single_expr ProcLit"); case_end; - case_ast_node(se, CastExpr, expr); + case_ast_node(ce, CastExpr, expr); GB_PANIC("TODO(bill): ssa_build_single_expr CastExpr"); case_end; - case_ast_node(se, CallExpr, expr); - GB_PANIC("TODO(bill): ssa_build_single_expr CallExpr"); + case_ast_node(ce, CallExpr, expr); + AstNode *p = unparen_expr(ce->proc); + if (p->kind == AstNode_Ident) { + Entity **found = map_get(&proc->module->info->uses, hash_pointer(p)); + if (found && (*found)->kind == Entity_Builtin) { + GB_PANIC("TODO(bill): CallExpr Builtin"); + } + } + + return ssa_emit_call(proc, expr, tv->type); case_end; case_ast_node(se, SliceExpr, expr); @@ -1046,20 +1143,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(ie, IndexExpr, expr); - Type *t = type_of_expr(proc->module->info, ie->expr); - t = get_base_type(t); - switch (t->kind) { - case Type_Basic: { - // TODO(bill): Strings AstNode_IndexExpression - } 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); - } break; - } + return ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, expr), proc)); case_end; } @@ -1075,8 +1159,9 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) { if (tv) { if (tv->value.kind != ExactValue_Invalid) { if (tv->value.kind == ExactValue_String) { - ssaValue *global_str = ssa_add_global_string(proc, tv->value); - return ssa_emit_load(proc, global_str); + ssaValue *array = ssa_add_global_string_array(proc, tv->value); + ssaValue *elem = ssa_array_elem(proc, array); + return ssa_emit_string(proc, elem, ssa_array_len(proc, array)); } return ssa_make_value_constant(proc->module->allocator, tv->type, tv->value); } @@ -1114,27 +1199,22 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_end; case_ast_node(se, SelectorExpr, expr); - AstNode *selector = unparen_expr(se->selector); Type *type = type_of_expr(proc->module->info, se->expr); - isize index = 0; - Entity *entity = lookup_field(type, selector, &index); + isize field_index = 0; + Entity *entity = lookup_field(type, unparen_expr(se->selector), &field_index); GB_ASSERT(entity != NULL); - ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc); + ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc); if (type->kind == Type_Pointer) { // NOTE(bill): Allow x^.y and x.y to be the same type = type_deref(type); - v = ssa_emit_load(proc, v); + e = ssa_emit_load(proc, e); } - ssaValue *i0 = v_zero32; - ssaValue *i1 = ssa_make_value_constant(proc->module->allocator, t_i32, make_exact_value_integer(index)); - ssaValue *gep = ssa_make_instr_get_element_ptr(proc, v, i0, i1, 2, true); - gep->instr.get_element_ptr.result_type = entity->type; - gep->instr.get_element_ptr.element_type = type; - v = ssa_emit(proc, gep); + ssaValue *index = ssa_make_value_constant(proc->module->allocator, t_i32, make_exact_value_integer(field_index)); + ssaValue *v = ssa_emit_struct_gep(proc, e, index, entity->type); return ssa_make_lvalue_address(v, expr); case_end; @@ -1148,15 +1228,21 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue *elem = ssa_array_elem(proc, array); v = ssa_emit_ptr_offset(proc, elem, index); } break; + case Type_Slice: { + ssaValue *slice = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc); + ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); + ssaValue *elem = ssa_slice_elem(proc, slice); + v = ssa_emit_ptr_offset(proc, elem, index); + } break; case Type_Pointer: { ssaValue *ptr = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc)); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); v = ssa_emit_ptr_offset(proc, ptr, index); } break; - case Type_Slice: { - ssaValue *slice = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc); + case Type_Basic: { // string + ssaValue *str = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); - ssaValue *elem = ssa_slice_elem(proc, slice); + ssaValue *elem = ssa_string_elem(proc, str); v = ssa_emit_ptr_offset(proc, elem, index); } break; } @@ -1167,13 +1253,13 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_end; case_ast_node(de, DerefExpr, expr); - ssaValue *load = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc)); - ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, NULL, NULL, 0, false); - Type *t = ssa_value_type(load); - t = type_deref(get_base_type(t)); + ssaValue *e = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc)); + ssaValue *gep = ssa_make_instr_get_element_ptr(proc, e, NULL, NULL, 0, false); + Type *t = type_deref(get_base_type(ssa_value_type(e))); 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); + ssaValue *v = ssa_emit(proc, gep); + return ssa_make_lvalue_address(v, expr); case_end; } @@ -1206,13 +1292,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) { - ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-true")); + ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp-and")); 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) { - ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-false")); + ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp-or")); ssa_build_cond(proc, be->left, true_block, block); proc->curr_block = block; ssa_build_cond(proc, be->right, true_block, false_block); @@ -1270,7 +1356,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { } else if (vd->value_count == 0) { // declared and zero-initialized for (AstNode *name = vd->name_list; name != NULL; name = name->next) { if (!ssa_is_blank_ident(name)) { - // TODO(bill): add local ssa_add_local_for_identifier(proc, name); } } @@ -1351,7 +1436,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { case_end; case_ast_node(es, ExprStmt, s); - ssa_build_expr(proc, es->expr); + ssaValue *value = ssa_build_expr(proc, es->expr); case_end; case_ast_node(bs, BlockStmt, s) @@ -1359,7 +1444,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { case_end; case_ast_node(bs, DeferStmt, s); - // NOTE(bill): is already handled with scope + GB_PANIC("DeferStmt"); case_end; case_ast_node(rs, ReturnStmt, s); @@ -1370,11 +1455,27 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { 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); + v = ssa_build_expr(proc, rs->result_list); + ssa_value_set_type(v, e->type); } else if (return_count == 0) { // No return values } else { // 1:1 multiple return values + Type *ret_type = proc->type->procedure.results; + v = ssa_add_local_generated(proc, ret_type); + isize i = 0; + AstNode *r = rs->result_list; + for (; + i < return_count && r != NULL; + i++, r = r->next) { + Entity *e = return_type_tuple->variables[i]; + ssaValue *res = ssa_build_expr(proc, r); + ssa_value_set_type(res, e->type); + ssaValue *index = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(i)); + ssaValue *field = ssa_emit_struct_gep(proc, v, index, e->type); + ssa_emit_store(proc, field, res); + } + v = ssa_emit_load(proc, v); } ssa_emit_ret(proc, v); @@ -1386,7 +1487,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { ssa_build_stmt(proc, is->init); } ssaBlock *then = ssa_add_block(proc, s, make_string("if.then")); - ssaBlock *done = ssa__make_block(proc, s, make_string("if.done")); + ssaBlock *done = ssa__make_block(proc, s, make_string("if.done")); // NOTE(bill): Append later ssaBlock *else_ = done; if (is->else_stmt != NULL) { else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else")); @@ -1447,27 +1548,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) { case_ast_node(bs, BranchStmt, s); 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; + #define BRANCH_GET_BLOCK(kind_) \ + case GB_JOIN2(Token_, kind_): { \ + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { \ + block = GB_JOIN3(t->, kind_, _); \ + } \ + } break + BRANCH_GET_BLOCK(break); + BRANCH_GET_BLOCK(continue); + BRANCH_GET_BLOCK(fallthrough); } ssa_emit_jump(proc, block); ssa_emit_unreachable(proc); @@ -1495,14 +1584,3 @@ void ssa_build_proc(ssaValue *value) { ssa_end_procedure_body(proc); } } - - - - - - - - - - - diff --git a/src/gb/gb.h b/src/gb/gb.h index af63b68c1..cd14c6be1 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6352,16 +6352,17 @@ gb_inline void gb_string_clear(gbString str) { gb__set_string_length(str, 0); st gb_inline gbString gb_string_append(gbString str, gbString const other) { return gb_string_append_length(str, other, gb_string_length(other)); } gbString gb_string_append_length(gbString str, void const *other, isize other_len) { - isize curr_len = gb_string_length(str); + if (other_len > 0) { + isize curr_len = gb_string_length(str); - str = gb_string_make_space_for(str, other_len); - if (str == NULL) - return NULL; - - gb_memcopy(str + curr_len, other, other_len); - str[curr_len + other_len] = '\0'; - gb__set_string_length(str, curr_len + other_len); + str = gb_string_make_space_for(str, other_len); + if (str == NULL) + return NULL; + gb_memcopy(str + curr_len, other, other_len); + str[curr_len + other_len] = '\0'; + gb__set_string_length(str, curr_len + other_len); + } return str; } diff --git a/src/main.cpp b/src/main.cpp index 64db9cbe8..c892d051a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,8 @@ int main(int argc, char **argv) { return 1; } + int success = 1; + init_universal_scope(); for (int arg_index = 1; arg_index < argc; arg_index++) { @@ -31,14 +33,16 @@ int main(int argc, char **argv) { check_parsed_files(&checker); ssaGen ssa = {}; - if (ssa_gen_init(&ssa, &checker)) { + if (false && ssa_gen_init(&ssa, &checker)) { defer (ssa_gen_destroy(&ssa)); ssa_gen_code(&ssa); + + success = 0; } } } } - return 0; + return success; } diff --git a/src/parser.cpp b/src/parser.cpp index ddf63d93c..184668c4b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1232,7 +1232,8 @@ AstNode *parse_expr_list(AstFile *f, b32 lhs, isize *list_count_) { isize list_count = 0; do { - DLIST_APPEND(list_root, list_curr, parse_expr(f, lhs)); + AstNode *e = parse_expr(f, lhs); + DLIST_APPEND(list_root, list_curr, e); list_count++; if (f->cursor[0].kind != Token_Comma || f->cursor[0].kind == Token_EOF) @@ -1259,6 +1260,7 @@ AstNode *parse_simple_stmt(AstFile *f) { isize lhs_count = 0, rhs_count = 0; AstNode *lhs_expr_list = parse_lhs_expr_list(f, &lhs_count); + AstNode *statement = NULL; Token token = f->cursor[0]; switch (token.kind) {