From 4dd8552c32e4f599992e50f965bab213c4ead1ad Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 28 Nov 2016 22:17:27 +0000 Subject: [PATCH] Fix slicing and add clamp --- build.bat | 2 +- core/fmt.odin | 4 +- src/checker/checker.c | 4 +- src/checker/expr.c | 100 +++++++++++++++++++++++++++++++++++++++++- src/ssa.c | 43 +++++++++++------- 5 files changed, 132 insertions(+), 21 deletions(-) diff --git a/build.bat b/build.bat index bd97782128b..53db822077f 100644 --- a/build.bat +++ b/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- diff --git a/core/fmt.odin b/core/fmt.odin index abc2bae8f99..f05d01e343b 100644 --- a/core/fmt.odin +++ b/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) } diff --git a/src/checker/checker.c b/src/checker/checker.c index e42e6126eb8..a5c3b534a21 100644 --- a/src/checker/checker.c +++ b/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}, }; diff --git a/src/checker/expr.c b/src/checker/expr.c index de6011a7980..9823f535f13 100644 --- a/src/checker/expr.c +++ b/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)) { diff --git a/src/ssa.c b/src/ssa.c index 42437d7e739..a97a5c9ae03 100644 --- a/src/ssa.c +++ b/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: {