From 1d4881cbbe0da6c5f9cd4a99dd1bf65c5e00c51d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Nov 2017 14:22:18 +0000 Subject: [PATCH] Add array programming --- core/_preload.odin | 3 +- src/check_expr.cpp | 81 +++++++++++++++++----- src/ir.cpp | 167 +++++++++++++++++++++++++++++++++------------ src/main.cpp | 2 + src/types.cpp | 14 +++- 5 files changed, 203 insertions(+), 64 deletions(-) diff --git a/core/_preload.odin b/core/_preload.odin index 92458572d..4a274470e 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -331,8 +331,7 @@ append :: proc "contextless" (array: ^$T/[]$E, args: ...E) -> int { s := cast(^raw.Slice)array; data := cast(^E)s.data; assert(data != nil); - sz :: size_of(E); - __mem_copy(data + s.len, &args[0], sz*arg_len); + __mem_copy(data + s.len, &args[0], size_of(E)*arg_len); s.len += arg_len; } return len(array); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1ab7e0df0..4ad649c05 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -569,6 +569,15 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { } } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (is_type_array(dst)) { + Type *elem = base_array_type(dst); + i64 distance = check_distance_between_types(c, operand, elem); + if (distance >= 0) { + return distance + 6; + } + } +#endif if (is_type_any(dst)) { if (!is_type_polymorphic(src)) { @@ -1879,7 +1888,7 @@ bool check_transmute(Checker *c, AstNode *node, Operand *o, Type *t) { return true; } -bool check_binary_vector_expr(Checker *c, Token op, Operand *x, Operand *y) { +bool check_binary_array_vector_expr(Checker *c, Token op, Operand *x, Operand *y) { if (is_type_vector(x->type) && !is_type_vector(y->type)) { if (check_is_assignable_to(c, y, x->type)) { if (check_binary_op(c, x, op)) { @@ -1887,6 +1896,13 @@ bool check_binary_vector_expr(Checker *c, Token op, Operand *x, Operand *y) { } } } + if (is_type_array(x->type) && !is_type_array(y->type)) { + if (check_is_assignable_to(c, y, x->type)) { + if (check_binary_op(c, x, op)) { + return true; + } + } + } return false; } @@ -1954,7 +1970,6 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { } } - convert_to_typed(c, x, y->type, 0); if (x->mode == Addressing_Invalid) { return; @@ -1965,18 +1980,19 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { return; } + + if (token_is_comparison(op.kind)) { check_comparison(c, x, y, op.kind); return; } - - if (check_binary_vector_expr(c, op, x, y)) { + if (check_binary_array_vector_expr(c, op, x, y)) { x->mode = Addressing_Value; x->type = x->type; return; } - if (check_binary_vector_expr(c, op, y, x)) { + if (check_binary_array_vector_expr(c, op, y, x)) { x->mode = Addressing_Value; x->type = y->type; return; @@ -2264,6 +2280,21 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level break; } +#if defined(ALLOW_ARRAY_PROGRAMMING) + case Type_Array: { + Type *elem = base_array_type(t); + if (check_is_assignable_to(c, operand, elem)) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + return; + } + + break; + } +#endif + case Type_Union: if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); @@ -3352,20 +3383,32 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id break; case BuiltinProc_swizzle: { - // proc swizzle(v: {N}T, T..) -> {M}T - Type *vector_type = base_type(operand->type); - if (!is_type_vector(vector_type)) { + // proc swizzle(v: [N]T, ...int) -> [M]T + // proc swizzle(v: [vector N]T, ...int) -> [vector M]T + Type *type = base_type(operand->type); + if (!is_type_vector(type) && !is_type_array(type)) { gbString type_str = type_to_string(operand->type); error(call, - "You can only `swizzle` a vector, got `%s`", + "You can only `swizzle` a vector or array, got `%s`", type_str); gb_string_free(type_str); return false; } - isize max_count = vector_type->Vector.count; + Type *elem_type = nullptr; + i64 max_count = 0; + if (is_type_vector(type)) { + max_count = type->Vector.count; + elem_type = type->Vector.elem; + } + #if defined(ALLOW_ARRAY_PROGRAMMING) + else if (is_type_array(type)) { + max_count = type->Array.count; + elem_type = type->Array.elem; + } + #endif i128 max_count128 = i128_from_i64(max_count); - isize arg_count = 0; + i64 arg_count = 0; for_array(i, ce->args) { if (i == 0) { continue; @@ -3382,13 +3425,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - if (i128_lt(op.value.value_integer, I128_ZERO)) { + if (op.value.value_integer < I128_ZERO) { error(op.expr, "Negative `swizzle` index"); return false; } - if (i128_le(max_count128, op.value.value_integer)) { - error(op.expr, "`swizzle` index exceeds vector length"); + if (max_count128 <= op.value.value_integer) { + error(op.expr, "`swizzle` index exceeds length"); return false; } @@ -3400,8 +3443,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - Type *elem_type = vector_type->Vector.elem; - operand->type = make_type_vector(c->allocator, elem_type, arg_count); + if (is_type_vector(type)) { + operand->type = make_type_vector(c->allocator, elem_type, arg_count); + } + #if defined(ALLOW_ARRAY_PROGRAMMING) + else if (is_type_array(type)) { + operand->type = make_type_array(c->allocator, elem_type, arg_count); + } + #endif operand->mode = Addressing_Value; break; diff --git a/src/ir.cpp b/src/ir.cpp index e015a7056..17b02ffbc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2086,6 +2086,27 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type * return ir_emit_load(proc, res); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (is_type_array(ir_type(x))) { + ir_emit_comment(proc, str_lit("array.arith.begin")); + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + Type *tl = base_type(ir_type(x)); + irValue *val = ir_address_from_load_or_generate_local(proc, x); + GB_ASSERT(is_type_array(type)); + Type *elem_type = base_type(type)->Array.elem; + + irValue *res = ir_add_local_generated(proc, type); + for (i32 i = 0; i < tl->Array.count; i++) { + irValue *e = ir_emit_load(proc, ir_emit_array_epi(proc, val, i)); + irValue *z = ir_emit_unary_arith(proc, op, e, elem_type); + ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); + } + ir_emit_comment(proc, str_lit("array.arith.end")); + return ir_emit_load(proc, res); + + } +#endif + return ir_emit(proc, ir_instr_unary_op(proc, op, x, type)); } @@ -2117,6 +2138,30 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_load(proc, res); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (is_type_array(t_left) || is_type_array(t_right)) { + ir_emit_comment(proc, str_lit("array.arith.begin")); + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + left = ir_emit_conv(proc, left, type); + right = ir_emit_conv(proc, right, type); + irValue *lhs = ir_address_from_load_or_generate_local(proc, left); + irValue *rhs = ir_address_from_load_or_generate_local(proc, right); + GB_ASSERT(is_type_array(type)); + Type *elem_type = base_type(type)->Array.elem; + + irValue *res = ir_add_local_generated(proc, type); + i64 count = base_type(type)->Array.count; + for (i32 i = 0; i < count; i++) { + irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); + irValue *z = ir_emit_arith(proc, op, x, y, elem_type); + ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); + } + ir_emit_comment(proc, str_lit("array.arith.end")); + return ir_emit_load(proc, res); + } +#endif + if (is_type_complex(t_left)) { ir_emit_comment(proc, str_lit("complex.arith.begin")); Type *ft = base_complex_elem_type(t_left); @@ -2282,7 +2327,6 @@ irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) { return ir_emit(proc, ir_instr_union_tag_value(proc, u)); } -irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) { Type *t = ir_type(x); @@ -2386,7 +2430,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal irValue *rhs = ir_address_from_load_or_generate_local(proc, right); GB_ASSERT(is_type_vector(result)); - Type *elem_type = base_type(result)->Vector.elem; + Type *elem_type = base_vector_type(result); irValue *res = ir_add_local_generated(proc, result); for (i32 i = 0; i < tl->Vector.count; i++) { @@ -2400,6 +2444,36 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_load(proc, res); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (is_type_array(a)) { + ir_emit_comment(proc, str_lit("array.comp.begin")); + defer (ir_emit_comment(proc, str_lit("array.comp.end"))); + + Type *tl = base_type(a); + irValue *lhs = ir_address_from_load_or_generate_local(proc, left); + irValue *rhs = ir_address_from_load_or_generate_local(proc, right); + + + TokenKind cmp_op = Token_And; + irValue *res = v_true; + if (op_kind == Token_NotEq) { + res = v_false; + cmp_op = Token_Or; + } + + // IMPORTANT TODO(bill): Make this much more efficient + for (i32 i = 0; i < tl->Array.count; i++) { + irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); + irValue *cmp = ir_emit_comp(proc, op_kind, x, y); + res = ir_emit_arith(proc, cmp_op, res, cmp, result); + } + + return ir_emit_conv(proc, res, result); + } + +#endif + return ir_emit(proc, ir_instr_binary_op(proc, op_kind, left, right, result)); } @@ -3153,6 +3227,21 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return ir_emit_load(proc, v); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (is_type_array(dst)) { + Type *dst_elem = dst->Array.elem; + value = ir_emit_conv(proc, value, dst_elem); + irValue *v = ir_add_local_generated(proc, t); + isize index_count = dst->Array.count; + + for (i32 i = 0; i < index_count; i++) { + irValue *elem = ir_emit_array_epi(proc, v, i); + ir_emit_store(proc, elem, value); + } + return ir_emit_load(proc, v); + } +#endif + if (is_type_any(dst)) { irValue *result = ir_add_local_generated(proc, t_any); @@ -3162,17 +3251,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { Type *st = default_type(src_type); - irValue *data = nullptr; - if (value->kind == irValue_Instr && - value->Instr.kind == irInstr_Load) { - // NOTE(bill): Addreirble value - data = value->Instr.Load.address; - } else { - // NOTE(bill): Non-addreirble value - data = ir_add_local_generated(proc, st); - ir_emit_store(proc, data, value); - } - GB_ASSERT(is_type_pointer(ir_type(data))); + irValue *data = ir_address_from_load_or_generate_local(proc, value); + GB_ASSERT_MSG(is_type_pointer(ir_type(data)), type_to_string(ir_type(data))); GB_ASSERT_MSG(is_type_typed(st), "%s", type_to_string(st)); data = ir_emit_conv(proc, data, t_rawptr); @@ -3427,42 +3507,18 @@ irValue *ir_type_info(irProcedure *proc, Type *type) { return ir_emit_array_ep(proc, ir_global_type_info_data, ir_const_i32(proc->module->allocator, entry_index)); } - - -irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { - ast_node(be, BinaryExpr, expr); -#if 0 - irBlock *true_ = ir_new_block(proc, nullptr, "logical.cmp.true"); - irBlock *false_ = ir_new_block(proc, nullptr, "logical.cmp.false"); - irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done"); - - irValue *result = ir_add_local_generated(proc, t_bool); - ir_build_cond(proc, expr, true_, false_); - - ir_start_block(proc, true_); - ir_emit_store(proc, result, v_true); - ir_emit_jump(proc, done); - - ir_start_block(proc, false_); - ir_emit_store(proc, result, v_false); - ir_emit_jump(proc, done); - - ir_start_block(proc, done); - - return ir_emit_load(proc, result); -#else +irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, AstNode *left, AstNode *right, Type *type) { irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs"); irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done"); - Type *type = type_of_expr(proc->module->info, expr); type = default_type(type); irValue *short_circuit = nullptr; - if (be->op.kind == Token_CmpAnd) { - ir_build_cond(proc, be->left, rhs, done); + if (op == Token_CmpAnd) { + ir_build_cond(proc, left, rhs, done); short_circuit = v_false; - } else if (be->op.kind == Token_CmpOr) { - ir_build_cond(proc, be->left, done, rhs); + } else if (op == Token_CmpOr) { + ir_build_cond(proc, left, done, rhs); short_circuit = v_true; } @@ -3473,7 +3529,7 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { if (done->preds.count == 0) { ir_start_block(proc, rhs); - return ir_build_expr(proc, be->right); + return ir_build_expr(proc, right); } Array edges = {}; @@ -3483,12 +3539,22 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { } ir_start_block(proc, rhs); - array_add(&edges, ir_build_expr(proc, be->right)); + array_add(&edges, ir_build_expr(proc, right)); ir_emit_jump(proc, done); ir_start_block(proc, done); return ir_emit(proc, ir_instr_phi(proc, edges, type)); -#endif +} + +irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { + ast_node(be, BinaryExpr, expr); + irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs"); + irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done"); + + Type *type = type_of_expr(proc->module->info, expr); + type = default_type(type); + + return ir_emit_logical_binary_expr(proc, be->op.kind, be->left, be->right, type); } @@ -4633,6 +4699,17 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { return ir_emit_conv(proc, x, tv.type); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + // NOTE(bill): Edge case + if (tv.value.kind != ExactValue_Compound && + is_type_array(tv.type)) { + Type *elem = base_array_type(tv.type); + ExactValue value = convert_exact_value_for_type(tv.value, elem); + irValue *x = ir_add_module_constant(proc->module, elem, value); + return ir_emit_conv(proc, x, tv.type); + } +#endif + return ir_add_module_constant(proc->module, tv.type, tv.value); } diff --git a/src/main.cpp b/src/main.cpp index cd7215168..154fa91bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,5 @@ +#define ALLOW_ARRAY_PROGRAMMING + #define USE_CUSTOM_BACKEND 0 // #define NO_ARRAY_BOUNDS_CHECK #if !defined(USE_THREADED_PARSER) diff --git a/src/types.cpp b/src/types.cpp index 09fcc98b7..364023d7e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -662,6 +662,11 @@ bool is_type_numeric(Type *t) { if (t->kind == Type_Vector) { return is_type_numeric(t->Vector.elem); } +#if defined(ALLOW_ARRAY_PROGRAMMING) + if (t->kind == Type_Array) { + return is_type_numeric(t->Array.elem); + } +#endif return false; } bool is_type_string(Type *t) { @@ -810,6 +815,13 @@ Type *base_vector_type(Type *t) { } return t; } +Type *base_array_type(Type *t) { + if (is_type_array(t)) { + t = base_type(t); + return t->Array.elem; + } + return t; +} Type *base_complex_elem_type(Type *t) { t = core_type(t); @@ -1067,7 +1079,7 @@ bool is_type_comparable(Type *t) { case Type_Enum: return is_type_comparable(core_type(t)); case Type_Array: - return false; + return is_type_comparable(t->Array.elem); case Type_Vector: return is_type_comparable(t->Vector.elem); case Type_Proc: