From 78116e0ea24aef3f663832edfb5f9cd6aa7b6e57 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 15:46:54 +0100 Subject: [PATCH] Implement for in statements for array-like values --- src/tilde_expr.cpp | 26 ++-- src/tilde_proc.cpp | 2 +- src/tilde_stmt.cpp | 318 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 308 insertions(+), 38 deletions(-) diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 07e60f1a6..993270c14 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -2417,22 +2417,20 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { // break; // } - // case Type_Array: { - // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + case Type_Array: { + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + populate(p, cl->elems, &temp_data, type); - // populate(p, cl->elems, &temp_data, type); + cgValue dst_ptr = cg_addr_get_ptr(p, v); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index); + temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); + } - // cgValue dst_ptr = cg_addr_get_ptr(p, v); - // for_array(i, temp_data) { - // i32 index = cast(i32)(temp_data[i].elem_index); - // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); - // } - - // assign_array(p, temp_data); - // break; - // } + assign_array(p, temp_data); + break; + } // case Type_EnumeratedArray: { // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); @@ -2468,7 +2466,7 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { } assign_array(p, temp_data); - cg_fill_slice(p, v, data, cg_const_int(p, t_int, cl->max_count)); + cg_fill_slice(p, v, data, cg_const_int(p, t_int, count)); return v; } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index b3c81a7d5..ed28f5016 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -396,7 +396,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { if ( - // string_starts_with(p->name, str_lit("runtime@_os_write")) || + // string_starts_with(p->name, str_lit("bug@main")) || false ) { // IR Printing TB_Arena *arena = tb_default_arena(); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 7ad6a9417..f89dbdf03 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1280,6 +1280,25 @@ gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr) { } +gb_internal void cg_range_stmt_store_val(cgProcedure *p, Ast *stmt_val, cgValue const &value) { + Entity *e = entity_of_node(stmt_val); + if (e == nullptr) { + return; + } + + if (e->flags & EntityFlag_Value) { + if (value.kind == cgValue_Addr) { + cgValue ptr = cg_address_from_load_or_generate_local(p, value); + cg_add_entity(p->module, e, ptr); + return; + } + } + + cgAddr addr = cg_add_local(p, e->type, e, false); + cg_addr_store(p, addr, value); + return; +} + gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *node, AstRangeStmt *rs, Scope *scope) { bool ADD_EXTRA_WRAPPING_CHECK = true; @@ -1341,27 +1360,8 @@ gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *nod cgValue val = cg_addr_load(p, value); cgValue idx = cg_addr_load(p, index); - auto const &store_val = [](cgProcedure *p, Ast *stmt_val, cgValue const &value) { - Entity *e = entity_of_node(stmt_val); - if (e == nullptr) { - return; - } - - if (e->flags & EntityFlag_Value) { - if (value.kind == cgValue_Addr) { - cgValue ptr = cg_address_from_load_or_generate_local(p, value); - cg_add_entity(p->module, e, ptr); - return; - } - } - - cgAddr addr = cg_add_local(p, e->type, e, false); - cg_addr_store(p, addr, value); - return; - }; - - if (val0_type) store_val(p, val0, val); - if (val1_type) store_val(p, val1, idx); + if (val0_type) cg_range_stmt_store_val(p, val0, val); + if (val1_type) cg_range_stmt_store_val(p, val1, idx); { @@ -1402,6 +1402,147 @@ gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *nod } tb_inst_set_control(p->func, done); +} + +gb_internal void cg_build_range_stmt_indexed(cgProcedure *p, cgValue expr, Type *val_type, cgValue count_ptr, + cgValue *val_, cgValue *idx_, TB_Node **loop_, TB_Node **done_, + bool is_reverse) { + cgValue count = {}; + Type *expr_type = base_type(type_deref(expr.type)); + switch (expr_type->kind) { + case Type_Array: + count = cg_const_int(p, t_int, expr_type->Array.count); + break; + } + + cgValue val = {}; + cgValue idx = {}; + TB_Node *loop = nullptr; + TB_Node *done = nullptr; + TB_Node *body = nullptr; + + loop = cg_control_region(p, "for_index_loop"); + body = cg_control_region(p, "for_index_body"); + done = cg_control_region(p, "for_index_done"); + + cgAddr index = cg_add_local(p, t_int, nullptr, false); + + if (!is_reverse) { + /* + for x, i in array { + ... + } + + i := -1 + for { + i += 1 + if !(i < len(array)) { + break + } + #no_bounds_check x := array[i] + ... + } + */ + + cg_addr_store(p, index, cg_const_int(p, t_int, cast(u64)-1)); + + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + cgValue incr = cg_emit_arith(p, Token_Add, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); + cg_addr_store(p, index, incr); + + if (count.node == nullptr) { + GB_ASSERT(count_ptr.node != nullptr); + count = cg_emit_load(p, count_ptr); + } + cgValue cond = cg_emit_comp(p, Token_Lt, incr, count); + cg_emit_if(p, cond, body, done); + } else { + // NOTE(bill): REVERSED LOGIC + /* + #reverse for x, i in array { + ... + } + + i := len(array) + for { + i -= 1 + if i < 0 { + break + } + #no_bounds_check x := array[i] + ... + } + */ + + if (count.node == nullptr) { + GB_ASSERT(count_ptr.node != nullptr); + count = cg_emit_load(p, count_ptr); + } + count = cg_emit_conv(p, count, t_int); + cg_addr_store(p, index, count); + + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + cgValue incr = cg_emit_arith(p, Token_Sub, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); + cg_addr_store(p, index, incr); + + cgValue anti_cond = cg_emit_comp(p, Token_Lt, incr, cg_const_int(p, t_int, 0)); + cg_emit_if(p, anti_cond, done, body); + } + + tb_inst_set_control(p->func, body); + + idx = cg_addr_load(p, index); + switch (expr_type->kind) { + case Type_Array: { + if (val_type != nullptr) { + val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); + } + break; + } + case Type_EnumeratedArray: { + if (val_type != nullptr) { + val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); + // NOTE(bill): Override the idx value for the enumeration + Type *index_type = expr_type->EnumeratedArray.index; + if (compare_exact_values(Token_NotEq, *expr_type->EnumeratedArray.min_value, exact_value_u64(0))) { + idx = cg_emit_arith(p, Token_Add, idx, cg_const_value(p, index_type, *expr_type->EnumeratedArray.min_value), index_type); + } + } + break; + } + case Type_Slice: { + if (val_type != nullptr) { + cgValue elem = cg_builtin_raw_data(p, expr); + val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_DynamicArray: { + if (val_type != nullptr) { + cgValue elem = cg_emit_struct_ep(p, expr, 0); + elem = cg_emit_load(p, elem); + val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_Struct: { + GB_ASSERT(is_type_soa_struct(expr_type)); + break; + } + + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; } @@ -1410,13 +1551,144 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { Ast *expr = unparen_expr(rs->expr); - if (is_ast_range(expr)) { cg_build_range_stmt_interval(p, &expr->BinaryExpr, rs, rs->scope); return; } - GB_PANIC("TODO(bill): cg_build_range_stmt"); + Type *expr_type = type_of_expr(expr); + if (expr_type != nullptr) { + Type *et = base_type(type_deref(expr_type)); + if (is_type_soa_struct(et)) { + GB_PANIC("TODO(bill): #soa array range statements"); + // cg_build_range_stmt_struct_soa(p, rs, scope); + return; + } + } + + cg_scope_open(p, rs->scope); + + + Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; + Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (val0 != nullptr && !is_blank_ident(val0)) { + val0_type = type_of_expr(val0); + } + if (val1 != nullptr && !is_blank_ident(val1)) { + val1_type = type_of_expr(val1); + } + + cgValue val = {}; + cgValue key = {}; + TB_Node *loop = nullptr; + TB_Node *done = nullptr; + bool is_map = false; + TypeAndValue tav = type_and_value_of_expr(expr); + + if (tav.mode == Addressing_Type) { + GB_PANIC("TODO(bill): range statement over enum type"); + } else { + Type *expr_type = type_of_expr(expr); + Type *et = base_type(type_deref(expr_type)); + switch (et->kind) { + case Type_Map: { + is_map = true; + cgValue map = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(map.type))) { + map = cg_emit_load(p, map); + } + GB_PANIC("TODO(bill): cg_build_range_map"); + // cg_build_range_map(p, map, val1_type, &val, &key, &loop, &done); + break; + } + case Type_Array: { + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); + cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->Array.count)); + cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_EnumeratedArray: { + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); + cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->EnumeratedArray.count)); + cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_DynamicArray: { + cgValue count_ptr = {}; + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + count_ptr = cg_emit_struct_ep(p, array, 1); + GB_PANIC("TODO(bill): cg_build_range_stmt_indexed"); + // cg_build_range_stmt_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Slice: { + cgValue count_ptr = {}; + cgValue slice = cg_build_expr(p, expr); + if (is_type_pointer(slice.type)) { + count_ptr = cg_emit_struct_ep(p, slice, 1); + slice = cg_emit_load(p, slice); + } else { + count_ptr = cg_add_local(p, t_int, nullptr, false).addr; + cg_emit_store(p, count_ptr, cg_builtin_len(p, slice)); + } + cg_build_range_stmt_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Basic: { + cgValue string = cg_build_expr(p, expr); + if (is_type_pointer(string.type)) { + string = cg_emit_load(p, string); + } + if (is_type_untyped(expr_type)) { + cgAddr s = cg_add_local(p, default_type(string.type), nullptr, false); + cg_addr_store(p, s, string); + string = cg_addr_load(p, s); + } + Type *t = base_type(string.type); + GB_ASSERT(!is_type_cstring(t)); + GB_PANIC("TODO(bill): cg_build_range_string"); + // cg_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Tuple: + GB_PANIC("TODO(bill): cg_build_range_tuple"); + // cg_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); + break; + default: + GB_PANIC("Cannot range over %s", type_to_string(expr_type)); + break; + } + } + + if (is_map) { + if (val0_type) cg_range_stmt_store_val(p, val0, key); + if (val1_type) cg_range_stmt_store_val(p, val1, val); + } else { + if (val0_type) cg_range_stmt_store_val(p, val0, val); + if (val1_type) cg_range_stmt_store_val(p, val1, key); + } + + cg_push_target_list(p, rs->label, done, loop, nullptr); + + cg_build_stmt(p, rs->body); + + cg_scope_close(p, cgDeferExit_Default, nullptr); + cg_pop_target_list(p); + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, done); } gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) {