diff --git a/code/demo.odin b/code/demo.odin index 905ae53d8..305638d52 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -9,10 +9,10 @@ #import "sync.odin"; main :: proc() { - x := 2; - y := 3; - z := x+y; - fmt.println(z); + a: i8 = -1; + fmt.println(a, cast(u64)a, cast(i64)a); + b: i64 = -1; + fmt.println(b, cast(u64)b, cast(i64)b); when false { s := new_slice(int, 0, 10); diff --git a/core/fmt.odin b/core/fmt.odin index abc0d1ac7..56fde40dc 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -102,7 +102,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { default: write_string(buf, info.signed ? "i" : "u"); fi := Fmt_Info{buf = buf}; - fmt_int(^fi, cast(u64)(8*info.size), false, 'd'); + fmt_int(^fi, cast(u64)(8*info.size), false, 64, 'd'); } case Float: @@ -155,7 +155,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { case Array: write_string(buf, "["); fi := Fmt_Info{buf = buf}; - fmt_int(^fi, cast(u64)info.count, false, 'd'); + fmt_int(^fi, cast(u64)info.count, false, 64, 'd'); write_string(buf, "]"); write_type(buf, info.elem); case Dynamic_Array: @@ -168,7 +168,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { case Vector: write_string(buf, "[vector "); fi := Fmt_Info{buf = buf}; - fmt_int(^fi, cast(u64)info.count, false, 'd'); + fmt_int(^fi, cast(u64)info.count, false, 64, 'd'); write_string(buf, "]"); write_type(buf, info.elem); @@ -185,7 +185,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { if info.custom_align { write_string(buf, "#align "); fi := Fmt_Info{buf = buf}; - fmt_int(^fi, cast(u64)info.align, false, 'd'); + fmt_int(^fi, cast(u64)info.align, false, 64, 'd'); write_byte(buf, ' '); } write_byte(buf, '{'); @@ -435,16 +435,47 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { } } -_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string) { - if neg { - u = -u; + +is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) { + neg := false; + if is_signed { + match bit_size { + case 8: + i := cast(i8)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 16: + i := cast(i16)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 32: + i := cast(i32)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 64: + i := cast(i64)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + default: + panic("is_integer_negative: Unknown integer size"); + } } + return u, neg; +} + +_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, is_signed: bool, bit_size: int, digits: string) { + _, neg := is_integer_negative(u, is_signed, bit_size); + BUF_SIZE :: 256; if fi.width_set || fi.prec_set { width := fi.width + fi.prec + 3; // 3 extra bytes for sign and prefix if width > BUF_SIZE { // TODO(bill):???? - panic("_write_int buffer overrun. Width and precision too big"); + panic("_write_int: buffer overrun. Width and precision too big"); } } @@ -475,10 +506,10 @@ _write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string) buf: [256]byte; flags: strconv.Int_Flag; - if fi.hash { flags |= strconv.Int_Flag.PREFIX; } - if fi.plus { flags |= strconv.Int_Flag.PLUS; } - if fi.space { flags |= strconv.Int_Flag.SPACE; } - s := strconv.append_bits(buf[..0], u, base, neg, digits, flags); + if fi.hash { flags |= strconv.Int_Flag.PREFIX; } + if fi.plus { flags |= strconv.Int_Flag.PLUS; } + if fi.space { flags |= strconv.Int_Flag.SPACE; } + s := strconv.append_bits(buf[..0], u, base, is_signed, bit_size, digits, flags); prev_zero := fi.zero; defer fi.zero = prev_zero; @@ -493,14 +524,14 @@ fmt_rune :: proc(fi: ^Fmt_Info, r: rune) { write_rune(fi.buf, r); } -fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) { +fmt_int :: proc(fi: ^Fmt_Info, u: u64, is_signed: bool, bit_size: int, verb: rune) { match verb { - case 'v': _write_int(fi, u, 10, neg, __DIGITS_LOWER); - case 'b': _write_int(fi, u, 2, neg, __DIGITS_LOWER); - case 'o': _write_int(fi, u, 8, neg, __DIGITS_LOWER); - case 'd': _write_int(fi, u, 10, neg, __DIGITS_LOWER); - case 'x': _write_int(fi, u, 16, neg, __DIGITS_LOWER); - case 'X': _write_int(fi, u, 16, neg, __DIGITS_UPPER); + case 'v': _write_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER); + case 'b': _write_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER); + case 'o': _write_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER); + case 'd': _write_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER); + case 'x': _write_int(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER); + case 'X': _write_int(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER); case 'c', 'r': fmt_rune(fi, cast(rune)u); case 'U': @@ -509,7 +540,7 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) { fmt_bad_verb(fi, verb); } else { write_string(fi.buf, "U+"); - _write_int(fi, u, 16, false, __DIGITS_UPPER); + _write_int(fi, u, 16, false, bit_size, __DIGITS_UPPER); } default: @@ -598,7 +629,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { if !fi.hash || verb == 'v' { write_string(fi.buf, "0x"); } - _write_int(fi, u, 16, false, __DIGITS_UPPER); + _write_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER); } fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { @@ -876,16 +907,16 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { case f32: fmt_float(fi, cast(f64)a, 32, verb); case f64: fmt_float(fi, a, 64, verb); - case int: fmt_int(fi, cast(u64)a, a < 0, verb); - case i8: fmt_int(fi, cast(u64)a, a < 0, verb); - case i16: fmt_int(fi, cast(u64)a, a < 0, verb); - case i32: fmt_int(fi, cast(u64)a, a < 0, verb); - case i64: fmt_int(fi, cast(u64)a, a < 0, verb); - case uint: fmt_int(fi, cast(u64)a, false, verb); - case u8: fmt_int(fi, cast(u64)a, false, verb); - case u16: fmt_int(fi, cast(u64)a, false, verb); - case u32: fmt_int(fi, cast(u64)a, false, verb); - case u64: fmt_int(fi, cast(u64)a, false, verb); + case int: fmt_int(fi, cast(u64)a, true, 8*size_of(int), verb); + case i8: fmt_int(fi, cast(u64)a, true, 8, verb); + case i16: fmt_int(fi, cast(u64)a, true, 16, verb); + case i32: fmt_int(fi, cast(u64)a, true, 32, verb); + case i64: fmt_int(fi, cast(u64)a, true, 64, verb); + case uint: fmt_int(fi, cast(u64)a, false, 8*size_of(uint), verb); + case u8: fmt_int(fi, cast(u64)a, false, 8, verb); + case u16: fmt_int(fi, cast(u64)a, false, 16, verb); + case u32: fmt_int(fi, cast(u64)a, false, 32, verb); + case u64: fmt_int(fi, cast(u64)a, false, 64, verb); case string: fmt_string(fi, a, verb); default: fmt_value(fi, arg, verb); } diff --git a/core/strconv.odin b/core/strconv.odin index 2d618855a..e21104819 100644 --- a/core/strconv.odin +++ b/core/strconv.odin @@ -25,10 +25,10 @@ append_bool :: proc(buf: []byte, b: bool) -> string { } append_uint :: proc(buf: []byte, u: u64, base: int) -> string { - return append_bits(buf, u, base, false, digits, 0); + return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0); } append_int :: proc(buf: []byte, i: i64, base: int) -> string { - return append_bits(buf, cast(u64)i, base, i < 0, digits, 0); + return append_bits(buf, cast(u64)i, base, true, 8*size_of(int), digits, 0); } itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, cast(i64)i, 10); @@ -265,7 +265,39 @@ MAX_BASE :: 32; immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz"; -append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string { +is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) { + neg := false; + if is_signed { + match bit_size { + case 8: + i := cast(i8)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 16: + i := cast(i16)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 32: + i := cast(i32)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + case 64: + i := cast(i64)u; + neg = i < 0; + if neg { i = -i; } + u = cast(u64)i; + default: + panic("is_integer_negative: Unknown integer size"); + } + } + return u, neg; +} + + +append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string { is_pow2 :: proc(x: i64) -> bool { if (x <= 0) { return false; @@ -279,9 +311,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f a: [65]byte; i := a.count; - if neg { - u = -u; - } + + neg: bool; + u, neg = is_integer_negative(u, is_signed, bit_size); if is_pow2(cast(i64)base) { b := cast(u64)base; diff --git a/src/build_settings.c b/src/build_settings.c index d1dcecf6e..7f0da2c10 100644 --- a/src/build_settings.c +++ b/src/build_settings.c @@ -209,7 +209,7 @@ String get_fullpath_core(gbAllocator a, String path) { void init_build_context(void) { BuildContext *bc = &build_context; bc->ODIN_VENDOR = str_lit("odin"); - bc->ODIN_VERSION = str_lit("0.1.1"); + bc->ODIN_VERSION = str_lit("0.1.2"); bc->ODIN_ROOT = odin_root_dir(); #if defined(GB_SYSTEM_WINDOWS) diff --git a/src/check_expr.c b/src/check_expr.c index d2796611d..3f6e591c0 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1917,6 +1917,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { } else { x->mode = Addressing_Value; + update_expr_type(c, x->expr, default_type(x->type), true); update_expr_type(c, y->expr, default_type(y->type), true); } diff --git a/src/ir.c b/src/ir.c index 9678cfeef..a5bb58111 100644 --- a/src/ir.c +++ b/src/ir.c @@ -2261,22 +2261,18 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { i64 sz = type_size_of(proc->module->allocator, src); i64 dz = type_size_of(proc->module->allocator, dst); irConvKind kind = irConv_trunc; - if (dz == sz) { + + if (dz < sz) { + kind = irConv_trunc; + } else if (dz == sz) { // NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment // NOTE(bill): Copy the value just for type correctness kind = irConv_bitcast; } else if (dz > sz) { - kind = irConv_zext; - - // TODO(bill): figure out the rules completely - bool ss = !is_type_unsigned(src); - bool ds = !is_type_unsigned(dst); - if (ss && ds) { - kind = irConv_sext; - } else if (ss) { - kind = irConv_sext; + if (is_type_unsigned(src)) { + kind = irConv_zext; // zero extent } else { - kind = irConv_zext; + kind = irConv_sext; // sign extent } } @@ -4900,9 +4896,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { for_array(i, inits) { - if (lvals.e[i].addr == NULL) { - continue; - } ir_addr_store(proc, lvals.e[i], inits.e[i]); } } diff --git a/src/main.c b/src/main.c index 5cb6e6e7c..d44f28b75 100644 --- a/src/main.c +++ b/src/main.c @@ -4,7 +4,6 @@ extern "C" { #define USE_CUSTOM_BACKEND false - #include "common.c" #include "timings.c" #include "build_settings.c" diff --git a/src/ssa.c b/src/ssa.c index 70723f098..2448ffdd9 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -6,7 +6,7 @@ typedef struct ssaProc ssaProc; typedef struct ssaEdge ssaEdge; typedef struct ssaRegister ssaRegister; typedef enum ssaBlockKind ssaBlockKind; -typedef enum ssaBranchPredicition ssaBranchPredicition; +typedef enum ssaBranchPrediction ssaBranchPrediction; String ssa_mangle_name(ssaModule *m, String path, Entity *e); @@ -22,6 +22,8 @@ enum ssaOp { ssaOp_Unknown, + ssaOp_Comment, // Does nothing + ssaOp_SP, // Stack Pointer ssaOp_SB, // Stack Base ssaOp_Addr, // Address of something - special rules for certain types when loading and storing (e.g. Maps) @@ -38,6 +40,7 @@ enum ssaOp { ssaOp_ArrayIndex, // Index for a fixed array ssaOp_PtrIndex, // Index for a struct/tuple/etc ssaOp_OffsetPtr, + ssaOp_ValueIndex, // Extract for a value from a register ssaOp_Phi, ssaOp_Copy, @@ -309,7 +312,7 @@ enum ssaBlockKind { ssaBlock_Count, }; -enum ssaBranchPredicition { +enum ssaBranchPrediction { ssaBranch_Unknown = 0, ssaBranch_Likely = +1, ssaBranch_Unlikely = -1, @@ -332,7 +335,7 @@ struct ssaBlock { ssaProc * proc; // Containing procedure // Likely branch direction - ssaBranchPredicition likeliness; + ssaBranchPrediction likeliness; ssaValueArray values; ssaEdgeArray preds; @@ -428,7 +431,7 @@ void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) { ssaEdge s = {c, j}; ssaEdge p = {b, i}; array_add(&b->succs, s); - array_add(&b->preds, p); + array_add(&c->preds, p); } @@ -522,6 +525,24 @@ bool ssa_is_blank_ident(AstNode *node) { } +typedef enum ssaAddrKind { + ssaAddr_Default, +} ssaAddrKind; + +typedef struct ssaAddr { + ssaValue * addr; + ssaAddrKind kind; +} ssaAddr; + +ssaAddr ssa_addr(ssaValue *v) { + if (v != NULL) { + GB_ASSERT(is_type_pointer(v->type)); + } + ssaAddr addr = {0}; + addr.addr = v; + return addr; +} + ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) { @@ -537,7 +558,9 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_ return p; } -ssaValue *ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { +ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { + ssaAddr result = {0}; + Type *t = make_type_pointer(p->module->allocator, e->type); ssaValue *local = ssa_new_value0(p->entry, ssaOp_Local, t); map_ssa_value_set(&p->values, hash_pointer(e), local); @@ -545,18 +568,21 @@ ssaValue *ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { ssaValue *addr = ssa_new_value1(p->curr_block, ssaOp_Addr, local->type, local); ssa_new_value1(p->curr_block, ssaOp_Zero, t, addr); - return addr; + result.addr = addr; + return result; } -ssaValue *ssa_add_local_for_ident(ssaProc *p, AstNode *name) { +ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) { + ssaAddr result = {0}; + Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name)); if (found) { Entity *e = *found; return ssa_add_local(p, e, name); } - return NULL; + return result; } -ssaValue *ssa_add_local_generated(ssaProc *p, Type *t) { +ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { GB_ASSERT(t != NULL); Scope *scope = NULL; @@ -567,8 +593,9 @@ ssaValue *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->curr_block, ssaOp_Comment, NULL, exact_value_string(s)); +} @@ -576,9 +603,14 @@ ssaValue *ssa_add_local_generated(ssaProc *p, Type *t) { void ssa_build_stmt(ssaProc *p, AstNode *node); void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes); +void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) { + if (addr.addr == NULL) { + return; + } +} -ssaValue *ssa_build_addr(ssaProc *p, AstNode *node) { - return NULL; +ssaAddr ssa_build_addr(ssaProc *p, AstNode *node) { + return ssa_addr(NULL); } ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { @@ -633,10 +665,6 @@ void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) { } } -void ssa_addr_store(ssaProc *p, ssaValue *addr, ssaValue *value) { - -} - ssaValue *ssa_emit_struct_ep(ssaProc *p, ssaValue *ptr, i32 index) { GB_ASSERT(ptr->type != NULL); @@ -659,6 +687,13 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { ssa_build_stmt_list(p, bs->stmts); case_end; + case_ast_node(us, UsingStmt, node); + AstNode *decl = unparen_expr(us->node); + if (decl->kind == AstNode_ValueDecl) { + ssa_build_stmt(p, decl); + } + case_end; + case_ast_node(vd, ValueDecl, node); if (vd->is_var) { ssaModule *m = p->module; @@ -671,14 +706,14 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } } } else { - ssaValueArray lvals = {0}; - ssaValueArray inits = {0}; + Array(ssaAddr) lvals = {0}; + ssaValueArray inits = {0}; array_init_reserve(&lvals, m->tmp_allocator, vd->names.count); array_init_reserve(&inits, m->tmp_allocator, vd->names.count); for_array(i, vd->names) { AstNode *name = vd->names.e[i]; - ssaValue *lval = NULL; + ssaAddr lval = ssa_addr(NULL); if (!ssa_is_blank_ident(name)) { lval = ssa_add_local_for_ident(p, name); } @@ -688,11 +723,10 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { for_array(i, vd->values) { ssaValue *init = ssa_build_expr(p, vd->values.e[i]); - if (init == NULL || init->type == NULL) { - // TODO(bill): remove this + if (init == NULL) { // TODO(bill): remove this continue; } - Type *t = base_type(init->type); + Type *t = type_deref(init->type); if (init->op == ssaOp_Addr && t->kind == Type_Tuple) { for (isize i = 0; i < t->Tuple.variable_count; i++) { Entity *e = t->Tuple.variables[i]; @@ -704,11 +738,7 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } } - for_array(i, inits) { - if (lvals.e[i] == NULL) { - continue; - } ssa_addr_store(p, lvals.e[i], inits.e[i]); } } @@ -716,6 +746,89 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { gb_temp_arena_memory_end(tmp); } case_end; + + case_ast_node(as, AssignStmt, node); + ssa_emit_comment(p, str_lit("AssignStmt")); + + ssaModule *m = p->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + + switch (as->op.kind) { + case Token_Eq: { + Array(ssaAddr) lvals = {0}; + array_init(&lvals, m->tmp_allocator); + + for_array(i, as->lhs) { + AstNode *lhs = as->lhs.e[i]; + ssaAddr lval = {0}; + if (!ssa_is_blank_ident(lhs)) { + lval = ssa_build_addr(p, lhs); + } + array_add(&lvals, lval); + } + + if (as->lhs.count == as->rhs.count) { + if (as->lhs.count == 1) { + AstNode *rhs = as->rhs.e[0]; + ssaValue *init = ssa_build_expr(p, rhs); + ssa_addr_store(p, lvals.e[0], init); + } else { + ssaValueArray inits; + array_init_reserve(&inits, m->tmp_allocator, lvals.count); + + for_array(i, as->rhs) { + ssaValue *init = ssa_build_expr(p, as->rhs.e[i]); + array_add(&inits, init); + } + + for_array(i, inits) { + ssa_addr_store(p, lvals.e[i], inits.e[i]); + } + } + } else { + ssaValueArray inits; + array_init_reserve(&inits, m->tmp_allocator, lvals.count); + + for_array(i, as->rhs) { + ssaValue *init = ssa_build_expr(p, as->rhs.e[i]); + Type *t = type_deref(init->type); + // TODO(bill): refactor for code reuse as this is repeated a bit + if (init->op == ssaOp_Addr && t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + ssaValue *v = ssa_emit_struct_ep(p, init, i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + for_array(i, inits) { + ssa_addr_store(p, lvals.e[i], inits.e[i]); + } + } + } break; + + default: { + 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); + } break; + } + + gb_temp_arena_memory_end(tmp); + case_end; + + case_ast_node(es, ExprStmt, node); + // NOTE(bill): No need to use return value + ssa_build_expr(p, es->expr); + case_end; } }