소스 검색

Fix slicing and add clamp

Ginger Bill 8 년 전
부모
커밋
4dd8552c32
5개의 변경된 파일132개의 추가작업 그리고 21개의 파일을 삭제
  1. 1 1
      build.bat
  2. 2 2
      core/fmt.odin
  3. 3 1
      src/checker/checker.c
  4. 99 1
      src/checker/expr.c
  5. 27 16
      src/ssa.c

+ 1 - 1
build.bat

@@ -4,7 +4,7 @@
 set exe_name=odin.exe
 
 :: Debug = 0, Release = 1
-set release_mode=0
+set release_mode=1
 
 set compiler_flags= -nologo -Oi -TC -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
 

+ 2 - 2
core/fmt.odin

@@ -359,8 +359,8 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
 	case Float:
 		match type f : arg {
 		// case f16:  print_f64_to_buffer(buf, f as f64)
-		case f32:  print_f64_to_buffer(buf, f as f64)
-		case f64:  print_f64_to_buffer(buf, f as f64)
+		case f32:  print_f32_to_buffer(buf, f)
+		case f64:  print_f64_to_buffer(buf, f)
 		// case f128: print_f64_to_buffer(buf, f as f64)
 		}
 

+ 3 - 1
src/checker/checker.c

@@ -125,6 +125,7 @@ typedef enum BuiltinProcId {
 	BuiltinProc_min,
 	BuiltinProc_max,
 	BuiltinProc_abs,
+	BuiltinProc_clamp,
 
 	BuiltinProc_enum_to_string,
 
@@ -133,7 +134,7 @@ typedef enum BuiltinProcId {
 typedef struct BuiltinProc {
 	String   name;
 	isize    arg_count;
-	bool      variadic;
+	bool     variadic;
 	ExprKind kind;
 } BuiltinProc;
 gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
@@ -169,6 +170,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT("min"),              2, false, Expr_Expr},
 	{STR_LIT("max"),              2, false, Expr_Expr},
 	{STR_LIT("abs"),              1, false, Expr_Expr},
+	{STR_LIT("clamp"),            3, false, Expr_Expr},
 
 	{STR_LIT("enum_to_string"),   1, false, Expr_Expr},
 };

+ 99 - 1
src/checker/expr.c

@@ -2572,6 +2572,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 	}
 
 	switch (id) {
+	default:
+		GB_PANIC("Implement builtin procedure: %.*s", LIT(builtin_procs[id].name));
+		break;
+
 	case BuiltinProc_new: {
 		// new :: proc(Type) -> ^Type
 		Operand op = {0};
@@ -3248,7 +3252,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		if (b.mode == Addressing_Invalid) {
 			return false;
 		}
-		if (!is_type_comparable(b.type) || !(is_type_numeric(type) || is_type_string(type))) {
+		if (!is_type_comparable(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
 			gbString type_str = type_to_string(b.type);
 			error(ast_node_token(call),
 			      "Expected a comparable numeric or string type to `max`, got `%s`",
@@ -3328,6 +3332,100 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		operand->type = type;
 	} break;
 
+	case BuiltinProc_clamp: {
+		// clamp :: proc(a, min, max: comparable) -> comparable
+		Type *type = base_type(operand->type);
+		if (!is_type_comparable(type) || !(is_type_numeric(type) || is_type_string(type))) {
+			gbString type_str = type_to_string(operand->type);
+			error(ast_node_token(call),
+			      "Expected a comparable numeric or string type to `clamp`, got `%s`",
+			      type_str);
+			gb_string_free(type_str);
+			return false;
+		}
+
+		AstNode *min_arg = ce->args.e[1];
+		AstNode *max_arg = ce->args.e[2];
+		Operand x = *operand;
+		Operand y = {0};
+		Operand z = {0};
+
+		check_expr(c, &y, min_arg);
+		if (y.mode == Addressing_Invalid) {
+			return false;
+		}
+		if (!is_type_comparable(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) {
+			gbString type_str = type_to_string(y.type);
+			error(ast_node_token(call),
+			      "Expected a comparable numeric or string type to `clamp`, got `%s`",
+			      type_str);
+			gb_string_free(type_str);
+			return false;
+		}
+
+		check_expr(c, &z, max_arg);
+		if (z.mode == Addressing_Invalid) {
+			return false;
+		}
+		if (!is_type_comparable(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) {
+			gbString type_str = type_to_string(z.type);
+			error(ast_node_token(call),
+			      "Expected a comparable numeric or string type to `clamp`, got `%s`",
+			      type_str);
+			gb_string_free(type_str);
+			return false;
+		}
+
+		if (x.mode == Addressing_Constant &&
+		    y.mode == Addressing_Constant &&
+		    z.mode == Addressing_Constant) {
+			ExactValue a = x.value;
+			ExactValue b = y.value;
+			ExactValue c = z.value;
+
+			operand->mode = Addressing_Constant;
+			if (compare_exact_values(Token_Lt, a, b)) {
+				operand->value = b;
+				operand->type = y.type;
+			} else if (compare_exact_values(Token_Gt, a, c)) {
+				operand->value = c;
+				operand->type = z.type;
+			} else {
+				operand->value = a;
+				operand->type = x.type;
+			}
+		} else {
+			operand->mode = Addressing_Value;
+			operand->type = type;
+
+			convert_to_typed(c, &x, y.type, 0);
+			if (x.mode == Addressing_Invalid) { return false; }
+			convert_to_typed(c, &y, x.type, 0);
+			if (y.mode == Addressing_Invalid) { return false; }
+			convert_to_typed(c, &x, z.type, 0);
+			if (x.mode == Addressing_Invalid) { return false; }
+			convert_to_typed(c, &z, x.type, 0);
+			if (z.mode == Addressing_Invalid) { return false; }
+			convert_to_typed(c, &y, z.type, 0);
+			if (y.mode == Addressing_Invalid) { return false; }
+			convert_to_typed(c, &z, y.type, 0);
+			if (z.mode == Addressing_Invalid) { return false; }
+
+			if (!are_types_identical(x.type, y.type) || !are_types_identical(x.type, z.type)) {
+				gbString type_x = type_to_string(x.type);
+				gbString type_y = type_to_string(y.type);
+				gbString type_z = type_to_string(z.type);
+				error(ast_node_token(call),
+				      "Mismatched types to `clamp`, `%s`, `%s`, `%s`",
+				      type_x, type_y, type_z);
+				gb_string_free(type_z);
+				gb_string_free(type_y);
+				gb_string_free(type_x);
+				return false;
+			}
+		}
+	} break;
+
 	case BuiltinProc_enum_to_string: {
 		Type *type = base_type(operand->type);
 		if (!is_type_enum(type)) {

+ 27 - 16
src/ssa.c

@@ -3012,16 +3012,18 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 				case BuiltinProc_min: {
 					ssa_emit_comment(proc, str_lit("min"));
-					ssaValue *x = ssa_build_expr(proc, ce->args.e[0]);
-					ssaValue *y = ssa_build_expr(proc, ce->args.e[1]);
+					Type *t = type_of_expr(proc->module->info, expr);
+					ssaValue *x = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[0]), t);
+					ssaValue *y = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[1]), t);
 					ssaValue *cond = ssa_emit_comp(proc, Token_Lt, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 				} break;
 
 				case BuiltinProc_max: {
 					ssa_emit_comment(proc, str_lit("max"));
-					ssaValue *x = ssa_build_expr(proc, ce->args.e[0]);
-					ssaValue *y = ssa_build_expr(proc, ce->args.e[1]);
+					Type *t = type_of_expr(proc->module->info, expr);
+					ssaValue *x = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[0]), t);
+					ssaValue *y = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[1]), t);
 					ssaValue *cond = ssa_emit_comp(proc, Token_Gt, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 				} break;
@@ -3067,6 +3069,20 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					return v;
 				} break;
 
+				case BuiltinProc_clamp: {
+					ssa_emit_comment(proc, str_lit("clamp"));
+					Type *t = type_of_expr(proc->module->info, expr);
+					ssaValue *x   = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[0]), t);
+					ssaValue *min = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[1]), t);
+					ssaValue *max = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args.e[2]), t);
+					ssaValue *cond;
+					cond = ssa_emit_comp(proc, Token_Gt, min, x);
+					x    = ssa_emit_select(proc, cond,   min, x);
+					cond = ssa_emit_comp(proc, Token_Lt, max, x);
+					x    = ssa_emit_select(proc, cond,   max, x);
+					return x;
+				} break;
+
 				case BuiltinProc_enum_to_string: {
 					ssa_emit_comment(proc, str_lit("enum_to_string"));
 					ssaValue *x = ssa_build_expr(proc, ce->args.e[0]);
@@ -3471,9 +3487,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 			ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false);
 
-			ssaValue *elem = ssa_slice_elem(proc, base);
-			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
-			ssaValue *cap  = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
+			ssaValue *elem  = ssa_emit_ptr_offset(proc, ssa_slice_elem(proc, base), low);
+			ssaValue *len   = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
+			ssaValue *cap   = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
 
 			ssaValue *gep0 = ssa_emit_struct_ep(proc, slice, 0);
@@ -3495,7 +3511,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 			ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false);
 
-			ssaValue *elem = ssa_array_elem(proc, addr);
+			ssaValue *elem = ssa_emit_ptr_offset(proc, ssa_array_elem(proc, addr), low);
 			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
 			ssaValue *cap  = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
@@ -5128,14 +5144,9 @@ void ssa_gen_tree(ssaGen *s) {
 					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), gep);
 
 					isize ez = type_size_of(m->sizes, a, t->Vector.elem);
-					ssaValue *elem_size = ssa_emit_struct_ep(proc, tag, 1);
-					ssa_emit_store(proc, elem_size, ssa_make_const_int(a, ez));
-
-					ssaValue *count = ssa_emit_struct_ep(proc, tag, 2);
-					ssa_emit_store(proc, count, ssa_make_const_int(a, t->Vector.count));
-
-					ssaValue *align = ssa_emit_struct_ep(proc, tag, 3);
-					ssa_emit_store(proc, count, ssa_make_const_int(a, type_align_of(m->sizes, a, t)));
+					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), ssa_make_const_int(a, ez));
+					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 2), ssa_make_const_int(a, t->Vector.count));
+					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 3), ssa_make_const_int(a, type_align_of(m->sizes, a, t)));
 
 				} break;
 				case Type_Record: {