Browse Source

Add array programming

gingerBill 7 years ago
parent
commit
1d4881cbbe
5 changed files with 203 additions and 64 deletions
  1. 1 2
      core/_preload.odin
  2. 65 16
      src/check_expr.cpp
  3. 122 45
      src/ir.cpp
  4. 2 0
      src/main.cpp
  5. 13 1
      src/types.cpp

+ 1 - 2
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);

+ 65 - 16
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;

+ 122 - 45
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<irValue *> 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);
 	}
 

+ 2 - 0
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)

+ 13 - 1
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: