From 77734ea967d620541eadc770280477cf1550892e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 11:59:50 +0100 Subject: Improve the performance of simple array comparisons --- src/types.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index dc7ecb946..5cf86d6b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1037,6 +1037,29 @@ Type *core_array_type(Type *t) { return t; } +// NOTE(bill): type can be easily compared using memcmp +bool is_type_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_simple_compare(t->Array.elem); + + case Type_Basic: + if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) { + return true; + } + return false; + + case Type_Pointer: + case Type_Proc: + case Type_BitSet: + case Type_BitField: + return true; + } + + return false; +} + Type *base_complex_elem_type(Type *t) { t = core_type(t); if (is_type_complex(t)) { -- cgit v1.2.3 From 37633c1d2a9cc2ab5ae659ffb359f7f56f0457a2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2019 11:02:00 +0100 Subject: `intrinsics.type_*` constant evaluation procedures --- src/check_expr.cpp | 412 +++++++++++++++++++++++++++++++++++++++++- src/checker.hpp | 214 +--------------------- src/checker_builtin_procs.hpp | 312 ++++++++++++++++++++++++++++++++ src/exact_value.cpp | 10 +- src/types.cpp | 13 ++ 5 files changed, 740 insertions(+), 221 deletions(-) create mode 100644 src/checker_builtin_procs.hpp (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 36304bf65..6a789bc33 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3178,7 +3178,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 /*fallthrough*/ } default: - if (ce->args.count > 0) { + if (BuiltinProc__type_begin < id && id < BuiltinProc__type_end) { + check_expr_or_type(c, operand, ce->args[0]); + } else if (ce->args.count > 0) { check_multi_expr(c, operand, ce->args[0]); } break; @@ -4445,6 +4447,414 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } break; + + case BuiltinProc_type_base_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->type = base_type(operand->type); + } + operand->mode = Addressing_Type; + break; + case BuiltinProc_type_core_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->type = core_type(operand->type); + } + operand->mode = Addressing_Type; + break; + + case BuiltinProc_type_is_boolean: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_boolean(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_integer: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_integer(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_rune: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_rune(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_float: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_complex: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_complex(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_string: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_string(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_typeid: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_typeid(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_any: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_any(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_is_endian_little: + operand->value = exact_value_bool(false); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_integer(operand->type)) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(is_type_integer_endian_little(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_endian_big: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else if (!is_type_integer(operand->type)) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(is_type_integer_endian_big(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_numeric: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_numeric(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_ordered: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_ordered(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_ordered_numeric: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_numeric(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_indexable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_indexable(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_sliceable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_sliceable(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_simple_compare: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_simple_compare(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_dereferenceable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + if (is_type_rawptr(operand->type)) { + operand->value = exact_value_bool(false); + } else if (is_type_pointer(operand->type)) { + operand->value = exact_value_bool(true); + } else { + operand->value = exact_value_bool(false); + } + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_is_named: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_named(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_pointer: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_pointer(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_opaque: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_opaque(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_array: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_array(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_slice: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_slice(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_dynamic_array: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_dynamic_array(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_map: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_map(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_struct: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_struct(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_union: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_union(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_enum: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_enum(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_proc: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_proc(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_field: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_field(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_field_value: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_field_value(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_set: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_set(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_simd_vector: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_simd_vector(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_has_nil: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(type_has_nil(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_elem_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_complex64: operand->type = t_f32; break; + case Basic_complex128: operand->type = t_f64; break; + } + break; + case Type_Pointer: operand->type = bt->Pointer.elem; break; + case Type_Opaque: operand->type = bt->Opaque.elem; break; + case Type_Array: operand->type = bt->Array.elem; break; + case Type_Slice: operand->type = bt->Slice.elem; break; + case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break; + } + } + operand->mode = Addressing_Type; + break; + + case BuiltinProc_type_proc_parameter_count: + operand->value = exact_value_i64(0); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_proc(operand->type)) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + operand->value = exact_value_i64(bt->Proc.param_count); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + break; + case BuiltinProc_type_proc_return_count: + operand->value = exact_value_i64(0); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_proc(operand->type)) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + operand->value = exact_value_i64(bt->Proc.result_count); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + break; } return true; diff --git a/src/checker.hpp b/src/checker.hpp index 66b68c35c..4e4a8cfe1 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -59,218 +59,8 @@ struct BuiltinProc { BuiltinProcPkg pkg; }; -enum BuiltinProcId { - BuiltinProc_Invalid, - - BuiltinProc_len, - BuiltinProc_cap, - - BuiltinProc_size_of, - BuiltinProc_align_of, - BuiltinProc_offset_of, - BuiltinProc_type_of, - BuiltinProc_type_info_of, - BuiltinProc_typeid_of, - - BuiltinProc_swizzle, - - BuiltinProc_complex, - BuiltinProc_real, - BuiltinProc_imag, - BuiltinProc_conj, - - BuiltinProc_expand_to_tuple, - - BuiltinProc_min, - BuiltinProc_max, - BuiltinProc_abs, - BuiltinProc_clamp, - - BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures - - // "Intrinsics" - BuiltinProc_vector, - - BuiltinProc_atomic_fence, - BuiltinProc_atomic_fence_acq, - BuiltinProc_atomic_fence_rel, - BuiltinProc_atomic_fence_acqrel, - - BuiltinProc_atomic_store, - BuiltinProc_atomic_store_rel, - BuiltinProc_atomic_store_relaxed, - BuiltinProc_atomic_store_unordered, - - BuiltinProc_atomic_load, - BuiltinProc_atomic_load_acq, - BuiltinProc_atomic_load_relaxed, - BuiltinProc_atomic_load_unordered, - - BuiltinProc_atomic_add, - BuiltinProc_atomic_add_acq, - BuiltinProc_atomic_add_rel, - BuiltinProc_atomic_add_acqrel, - BuiltinProc_atomic_add_relaxed, - BuiltinProc_atomic_sub, - BuiltinProc_atomic_sub_acq, - BuiltinProc_atomic_sub_rel, - BuiltinProc_atomic_sub_acqrel, - BuiltinProc_atomic_sub_relaxed, - BuiltinProc_atomic_and, - BuiltinProc_atomic_and_acq, - BuiltinProc_atomic_and_rel, - BuiltinProc_atomic_and_acqrel, - BuiltinProc_atomic_and_relaxed, - BuiltinProc_atomic_nand, - BuiltinProc_atomic_nand_acq, - BuiltinProc_atomic_nand_rel, - BuiltinProc_atomic_nand_acqrel, - BuiltinProc_atomic_nand_relaxed, - BuiltinProc_atomic_or, - BuiltinProc_atomic_or_acq, - BuiltinProc_atomic_or_rel, - BuiltinProc_atomic_or_acqrel, - BuiltinProc_atomic_or_relaxed, - BuiltinProc_atomic_xor, - BuiltinProc_atomic_xor_acq, - BuiltinProc_atomic_xor_rel, - BuiltinProc_atomic_xor_acqrel, - BuiltinProc_atomic_xor_relaxed, - - BuiltinProc_atomic_xchg, - BuiltinProc_atomic_xchg_acq, - BuiltinProc_atomic_xchg_rel, - BuiltinProc_atomic_xchg_acqrel, - BuiltinProc_atomic_xchg_relaxed, - - BuiltinProc_atomic_cxchg, - BuiltinProc_atomic_cxchg_acq, - BuiltinProc_atomic_cxchg_rel, - BuiltinProc_atomic_cxchg_acqrel, - BuiltinProc_atomic_cxchg_relaxed, - BuiltinProc_atomic_cxchg_failrelaxed, - BuiltinProc_atomic_cxchg_failacq, - BuiltinProc_atomic_cxchg_acq_failrelaxed, - BuiltinProc_atomic_cxchg_acqrel_failrelaxed, - - BuiltinProc_atomic_cxchgweak, - BuiltinProc_atomic_cxchgweak_acq, - BuiltinProc_atomic_cxchgweak_rel, - BuiltinProc_atomic_cxchgweak_acqrel, - BuiltinProc_atomic_cxchgweak_relaxed, - BuiltinProc_atomic_cxchgweak_failrelaxed, - BuiltinProc_atomic_cxchgweak_failacq, - BuiltinProc_atomic_cxchgweak_acq_failrelaxed, - BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed, - - BuiltinProc_COUNT, -}; -gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { - {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin}, - - {STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE - - - // "Intrinsics" - {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type - - - {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -}; + +#include "checker_builtin_procs.hpp" // Operand is used as an intermediate value whilst checking diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp new file mode 100644 index 000000000..f6e3aee7e --- /dev/null +++ b/src/checker_builtin_procs.hpp @@ -0,0 +1,312 @@ +// checker_builtin_procs.hpp + +enum BuiltinProcId { + BuiltinProc_Invalid, + + BuiltinProc_len, + BuiltinProc_cap, + + BuiltinProc_size_of, + BuiltinProc_align_of, + BuiltinProc_offset_of, + BuiltinProc_type_of, + BuiltinProc_type_info_of, + BuiltinProc_typeid_of, + + BuiltinProc_swizzle, + + BuiltinProc_complex, + BuiltinProc_real, + BuiltinProc_imag, + BuiltinProc_conj, + + BuiltinProc_expand_to_tuple, + + BuiltinProc_min, + BuiltinProc_max, + BuiltinProc_abs, + BuiltinProc_clamp, + + BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures + + // "Intrinsics" + BuiltinProc_vector, + + BuiltinProc_atomic_fence, + BuiltinProc_atomic_fence_acq, + BuiltinProc_atomic_fence_rel, + BuiltinProc_atomic_fence_acqrel, + + BuiltinProc_atomic_store, + BuiltinProc_atomic_store_rel, + BuiltinProc_atomic_store_relaxed, + BuiltinProc_atomic_store_unordered, + + BuiltinProc_atomic_load, + BuiltinProc_atomic_load_acq, + BuiltinProc_atomic_load_relaxed, + BuiltinProc_atomic_load_unordered, + + BuiltinProc_atomic_add, + BuiltinProc_atomic_add_acq, + BuiltinProc_atomic_add_rel, + BuiltinProc_atomic_add_acqrel, + BuiltinProc_atomic_add_relaxed, + BuiltinProc_atomic_sub, + BuiltinProc_atomic_sub_acq, + BuiltinProc_atomic_sub_rel, + BuiltinProc_atomic_sub_acqrel, + BuiltinProc_atomic_sub_relaxed, + BuiltinProc_atomic_and, + BuiltinProc_atomic_and_acq, + BuiltinProc_atomic_and_rel, + BuiltinProc_atomic_and_acqrel, + BuiltinProc_atomic_and_relaxed, + BuiltinProc_atomic_nand, + BuiltinProc_atomic_nand_acq, + BuiltinProc_atomic_nand_rel, + BuiltinProc_atomic_nand_acqrel, + BuiltinProc_atomic_nand_relaxed, + BuiltinProc_atomic_or, + BuiltinProc_atomic_or_acq, + BuiltinProc_atomic_or_rel, + BuiltinProc_atomic_or_acqrel, + BuiltinProc_atomic_or_relaxed, + BuiltinProc_atomic_xor, + BuiltinProc_atomic_xor_acq, + BuiltinProc_atomic_xor_rel, + BuiltinProc_atomic_xor_acqrel, + BuiltinProc_atomic_xor_relaxed, + + BuiltinProc_atomic_xchg, + BuiltinProc_atomic_xchg_acq, + BuiltinProc_atomic_xchg_rel, + BuiltinProc_atomic_xchg_acqrel, + BuiltinProc_atomic_xchg_relaxed, + + BuiltinProc_atomic_cxchg, + BuiltinProc_atomic_cxchg_acq, + BuiltinProc_atomic_cxchg_rel, + BuiltinProc_atomic_cxchg_acqrel, + BuiltinProc_atomic_cxchg_relaxed, + BuiltinProc_atomic_cxchg_failrelaxed, + BuiltinProc_atomic_cxchg_failacq, + BuiltinProc_atomic_cxchg_acq_failrelaxed, + BuiltinProc_atomic_cxchg_acqrel_failrelaxed, + + BuiltinProc_atomic_cxchgweak, + BuiltinProc_atomic_cxchgweak_acq, + BuiltinProc_atomic_cxchgweak_rel, + BuiltinProc_atomic_cxchgweak_acqrel, + BuiltinProc_atomic_cxchgweak_relaxed, + BuiltinProc_atomic_cxchgweak_failrelaxed, + BuiltinProc_atomic_cxchgweak_failacq, + BuiltinProc_atomic_cxchgweak_acq_failrelaxed, + BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed, + + + // Constant type tests +BuiltinProc__type_begin, + + BuiltinProc_type_base_type, + BuiltinProc_type_core_type, + + BuiltinProc_type_is_boolean, + BuiltinProc_type_is_integer, + BuiltinProc_type_is_rune, + BuiltinProc_type_is_float, + BuiltinProc_type_is_complex, + BuiltinProc_type_is_string, + BuiltinProc_type_is_typeid, + BuiltinProc_type_is_any, + + BuiltinProc_type_is_endian_little, + BuiltinProc_type_is_endian_big, + BuiltinProc_type_is_numeric, + BuiltinProc_type_is_ordered, + BuiltinProc_type_is_ordered_numeric, + BuiltinProc_type_is_indexable, + BuiltinProc_type_is_sliceable, + BuiltinProc_type_is_simple_compare, // easily compared using memcmp + BuiltinProc_type_is_dereferenceable, + + BuiltinProc_type_is_named, + BuiltinProc_type_is_pointer, + BuiltinProc_type_is_opaque, + BuiltinProc_type_is_array, + BuiltinProc_type_is_slice, + BuiltinProc_type_is_dynamic_array, + BuiltinProc_type_is_map, + BuiltinProc_type_is_struct, + BuiltinProc_type_is_union, + BuiltinProc_type_is_enum, + BuiltinProc_type_is_proc, + BuiltinProc_type_is_bit_field, + BuiltinProc_type_is_bit_field_value, + BuiltinProc_type_is_bit_set, + BuiltinProc_type_is_simd_vector, + + BuiltinProc_type_has_nil, + + BuiltinProc_type_elem_type, + + BuiltinProc_type_proc_parameter_count, + BuiltinProc_type_proc_return_count, + +BuiltinProc__type_end, + + BuiltinProc_COUNT, +}; +gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin}, + + {STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE + + + // "Intrinsics" + {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type + + {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_endian_little"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_endian_big"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_ordered_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_indexable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics,}, + {STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_opaque"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_map"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_struct"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, +}; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 428690291..7d822512b 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -53,14 +53,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_integer(u64(v.value_bool)); case ExactValue_String: return hash_string(v.value_string); - case ExactValue_Integer: { - u64 *d = big_int_ptr(&v.value_integer); - u64 x = 0; - for (i32 i = 0; i < v.value_integer.len; i++) { - x |= d[i]; - } - return hash_integer(x); - } + case ExactValue_Integer: + return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64)); case ExactValue_Float: return hash_f64(v.value_float); case ExactValue_Pointer: diff --git a/src/types.cpp b/src/types.cpp index 5cf86d6b6..76126f17f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1307,6 +1307,19 @@ bool is_type_indexable(Type *t) { return false; } +bool is_type_sliceable(Type *t) { + Type *bt = base_type(t); + switch (bt->kind) { + case Type_Basic: + return bt->Basic.kind == Basic_string; + case Type_Array: + case Type_Slice: + case Type_DynamicArray: + return true; + } + return false; +} + bool is_type_polymorphic_record(Type *t) { t = base_type(t); -- cgit v1.2.3 From b04231dd95b6a80789b5e8762a51db4506948da1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2019 14:54:23 +0100 Subject: Improve implementation of `intrinsics.type_*` procedures --- src/check_expr.cpp | 401 +++++++++--------------------------------- src/checker_builtin_procs.hpp | 6 +- src/types.cpp | 20 ++- 3 files changed, 98 insertions(+), 329 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a789bc33..99fe6695b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3131,6 +3131,55 @@ bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **o return false; } +typedef bool (BuiltinTypeIsProc)(Type *t); + +BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__type_begin - 1] = { + nullptr, // BuiltinProc_type_base_type + nullptr, // BuiltinProc_type_core_type + nullptr, // BuiltinProc_type_elem_type + + is_type_boolean, + is_type_integer, + is_type_rune, + is_type_float, + is_type_complex, + is_type_string, + is_type_typeid, + is_type_any, + is_type_endian_little, + is_type_endian_big, + is_type_numeric, + is_type_ordered, + is_type_ordered_numeric, + is_type_indexable, + is_type_sliceable, + is_type_simple_compare, + is_type_dereferenceable, + + is_type_named, + is_type_pointer, + is_type_opaque, + is_type_array, + is_type_slice, + is_type_dynamic_array, + + is_type_map, + is_type_struct, + is_type_union, + is_type_enum, + is_type_proc, + is_type_bit_field, + is_type_bit_field_value, + is_type_bit_set, + is_type_simd_vector, + + type_has_nil, + + nullptr, // BuiltinProc_type_proc_parameter_count + nullptr, // BuiltinProc_type_proc_return_count +}; + + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) { ast_node(ce, CallExpr, call); @@ -4464,371 +4513,78 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } operand->mode = Addressing_Type; break; - - case BuiltinProc_type_is_boolean: + case BuiltinProc_type_elem_type: if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); } else { - operand->value = exact_value_bool(is_type_boolean(operand->type)); + Type *bt = base_type(operand->type); + switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_complex64: operand->type = t_f32; break; + case Basic_complex128: operand->type = t_f64; break; + } + break; + case Type_Pointer: operand->type = bt->Pointer.elem; break; + case Type_Opaque: operand->type = bt->Opaque.elem; break; + case Type_Array: operand->type = bt->Array.elem; break; + case Type_Slice: operand->type = bt->Slice.elem; break; + case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break; + } } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; + operand->mode = Addressing_Type; break; + + + case BuiltinProc_type_is_boolean: case BuiltinProc_type_is_integer: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_integer(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_rune: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_rune(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_float: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - } else { - - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_complex: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_complex(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_string: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_string(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_typeid: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_typeid(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_any: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_any(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_endian_little: - operand->value = exact_value_bool(false); - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else if (!is_type_integer(operand->type)) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else { - operand->value = exact_value_bool(is_type_integer_endian_little(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_endian_big: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else if (!is_type_integer(operand->type)) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else { - operand->value = exact_value_bool(is_type_integer_endian_big(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_numeric: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_numeric(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_ordered: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_ordered(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_ordered_numeric: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_numeric(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_indexable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_indexable(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_sliceable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_sliceable(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_simple_compare: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_simple_compare(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_dereferenceable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - if (is_type_rawptr(operand->type)) { - operand->value = exact_value_bool(false); - } else if (is_type_pointer(operand->type)) { - operand->value = exact_value_bool(true); - } else { - operand->value = exact_value_bool(false); - } - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_named: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_named(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_pointer: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_pointer(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_opaque: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_opaque(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_array: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_array(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_slice: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_slice(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_dynamic_array: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_dynamic_array(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_map: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_map(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_struct: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_struct(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_union: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_union(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_enum: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_enum(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_proc: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_proc(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_bit_field: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_field(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_bit_field_value: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_field_value(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_bit_set: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_set(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; case BuiltinProc_type_is_simd_vector: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_simd_vector(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_has_nil: + GB_ASSERT(BuiltinProc__type_begin < id && id < BuiltinProc__type_end); + operand->value = exact_value_bool(false); if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + gbString str = expr_to_string(ce->args[0]); + error(operand->expr, "Expected a type for '%.*s', got '%s'", LIT(builtin_name), str); + gb_string_free(str); } else { - operand->value = exact_value_bool(type_has_nil(operand->type)); + i32 i = id - (BuiltinProc__type_begin+1); + auto procedure = builtin_type_is_procs[i]; + GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name)); + operand->value = exact_value_bool(procedure(operand->type)); } operand->mode = Addressing_Constant; operand->type = t_untyped_bool; break; - case BuiltinProc_type_elem_type: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - } else { - Type *bt = base_type(operand->type); - switch (bt->kind) { - case Type_Basic: - switch (bt->Basic.kind) { - case Basic_complex64: operand->type = t_f32; break; - case Basic_complex128: operand->type = t_f64; break; - } - break; - case Type_Pointer: operand->type = bt->Pointer.elem; break; - case Type_Opaque: operand->type = bt->Opaque.elem; break; - case Type_Array: operand->type = bt->Array.elem; break; - case Type_Slice: operand->type = bt->Slice.elem; break; - case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break; - } - } - operand->mode = Addressing_Type; - break; - case BuiltinProc_type_proc_parameter_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { @@ -7527,6 +7283,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Ast_UnionType: case Ast_EnumType: case Ast_MapType: + case Ast_OpaqueType: + case Ast_BitSetType: + case Ast_BitFieldType: o->mode = Addressing_Type; o->type = check_type(c, node); break; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index f6e3aee7e..536d47616 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -110,6 +110,7 @@ BuiltinProc__type_begin, BuiltinProc_type_base_type, BuiltinProc_type_core_type, + BuiltinProc_type_elem_type, BuiltinProc_type_is_boolean, BuiltinProc_type_is_integer, @@ -148,8 +149,6 @@ BuiltinProc__type_begin, BuiltinProc_type_has_nil, - BuiltinProc_type_elem_type, - BuiltinProc_type_proc_parameter_count, BuiltinProc_type_proc_return_count, @@ -266,6 +265,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -304,8 +304,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/types.cpp b/src/types.cpp index 76126f17f..e5d2509e0 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1122,12 +1122,11 @@ bool is_type_integer_endian_big(Type *t) { return is_type_integer_endian_big(bit_set_to_int(t)); } else if (t->kind == Type_Pointer) { return is_type_integer_endian_big(&basic_types[Basic_uintptr]); - } else { - GB_PANIC("Unsupported type: %s", type_to_string(t)); } return build_context.endian_kind == TargetEndian_Big; } + bool is_type_integer_endian_little(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1141,11 +1140,24 @@ bool is_type_integer_endian_little(Type *t) { return is_type_integer_endian_little(bit_set_to_int(t)); } else if (t->kind == Type_Pointer) { return is_type_integer_endian_little(&basic_types[Basic_uintptr]); - } else { - GB_PANIC("Unsupported type: %s", type_to_string(t)); } return build_context.endian_kind == TargetEndian_Little; } +bool is_type_endian_big(Type *t) { + return is_type_integer_endian_big(t); +} +bool is_type_endian_little(Type *t) { + return is_type_integer_endian_little(t); +} + +bool is_type_dereferenceable(Type *t) { + if (is_type_rawptr(t)) { + return false; + } + return is_type_pointer(t); +} + + bool is_type_different_to_arch_endianness(Type *t) { switch (build_context.endian_kind) { -- cgit v1.2.3 From 9c632128245e9a51bb63273d0d4531ba28773629 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 21:59:58 +0100 Subject: Struct field tags --- core/odin/ast/ast.odin | 20 ++++++++++++-------- core/odin/parser/parser.odin | 24 +++++++++++++++++------- core/runtime/core.odin | 5 +++-- examples/demo/demo.odin | 25 +++++++++++++++++++++++++ src/check_type.cpp | 6 ++++-- src/ir.cpp | 37 +++++++++++++++++++++++++++++++++---- src/parser.cpp | 37 +++++++++++++++++++++++++++++-------- src/parser.hpp | 4 +++- src/types.cpp | 1 + 9 files changed, 127 insertions(+), 32 deletions(-) (limited to 'src/types.cpp') diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index c0d2948ee..3655a601d 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -435,7 +435,9 @@ Field_Flag :: enum { C_Vararg, Auto_Cast, In, + Results, + Tags, Default_Parameters, Typeid_Token, } @@ -443,18 +445,19 @@ Field_Flag :: enum { Field_Flags :: distinct bit_set[Field_Flag]; Field_Flags_Struct :: Field_Flags{ - Field_Flag.Using, + .Using, + .Tags, }; Field_Flags_Record_Poly_Params :: Field_Flags{ - Field_Flag.Typeid_Token, + .Typeid_Token, }; Field_Flags_Signature :: Field_Flags{ - Field_Flag.Ellipsis, - Field_Flag.Using, - Field_Flag.No_Alias, - Field_Flag.C_Vararg, - Field_Flag.Auto_Cast, - Field_Flag.Default_Parameters, + .Ellipsis, + .Using, + .No_Alias, + .C_Vararg, + .Auto_Cast, + .Default_Parameters, }; Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token}; @@ -483,6 +486,7 @@ Field :: struct { names: []^Expr, // Could be polymorphic type: ^Expr, default_value: ^Expr, + tag: token.Token, flags: Field_Flags, comment: ^Comment_Group, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 0c011e07e..2d8e42720 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1388,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se for flag in ast.Field_Flag { if flag notin allowed_flags && flag in flags { - using ast.Field_Flag; #complete switch flag { - case Using: + case .Using: error(p, p.curr_tok.pos, "'using' is not allowed within this field list"); - case No_Alias: + case .No_Alias: error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list"); - case C_Vararg: + case .C_Vararg: error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list"); - case Auto_Cast: + case .Auto_Cast: error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list"); - case In: + case .In: error(p, p.curr_tok.pos, "'in' is not allowed within this field list"); - case Ellipsis, Results, Default_Parameters, Typeid_Token: + case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token: panic("Impossible prefixes"); } flags &~= {flag}; @@ -1540,6 +1539,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel type: ^ast.Expr; default_value: ^ast.Expr; + tag: token.Token; expect_token_after(p, token.Colon, "field list"); if p.curr_tok.kind != token.Eq { @@ -1579,9 +1579,19 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value"); } + if type != nil && default_value == nil { + if p.curr_tok.kind == token.String { + tag = expect_token(p, token.String); + if .Tags notin allowed_flags { + error(p, tag.pos, "Field tags are only allowed within structures"); + } + } + } + ok := expect_field_separator(p, type); field := new_ast_field(names, type, default_value); + field.tag = tag; field.docs = docs; field.flags = flags; field.comment = p.line_comment; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 02578da3b..28767cc2d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -79,8 +79,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures Type_Info_Struct :: struct { types: []^Type_Info, names: []string, - offsets: []uintptr, // offsets may not be used in tuples - usings: []bool, // usings may not be used in tuples + offsets: []uintptr, + usings: []bool, + tags: []string, is_packed: bool, is_raw_union: bool, custom_align: bool, diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 206fa4a2d..21f889746 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -3,6 +3,7 @@ package main import "core:fmt" import "core:mem" import "core:os" +import "core:runtime" when os.OS == "windows" { import "core:thread" @@ -945,6 +946,29 @@ deferred_procedure_associations :: proc() { } } +struct_field_tags :: proc() { + fmt.println("# struct_field_tags"); + + Foo :: struct { + x: int `tag1`, + y: string `tag2`, + z: bool, // no tag + } + + f: Foo; + ti := runtime.type_info_base(type_info_of(Foo)); + s := ti.variant.(runtime.Type_Info_Struct); + fmt.println("Foo :: struct {"); + for _, i in s.names { + if tag := s.tags[i]; tag != "" { + fmt.printf("\t%s: %T `%s`,\n", s.names[i], s.types[i], tag); + } else { + fmt.printf("\t%s: %T,\n", s.names[i], s.types[i]); + } + } + fmt.println("}"); +} + main :: proc() { when true { general_stuff(); @@ -963,5 +987,6 @@ main :: proc() { bit_set_type(); diverging_procedures(); deferred_procedure_associations(); + struct_field_tags(); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 36d8cf0f8..a9c1d3fe3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) { return false; } -void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array const ¶ms, +void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array *tags, Array const ¶ms, isize init_field_capacity, Type *struct_type, String context) { *fields = array_make(heap_allocator(), 0, init_field_capacity); + *tags = array_make(heap_allocator(), 0, init_field_capacity); GB_ASSERT(node->kind == Ast_StructType); GB_ASSERT(struct_type->kind == Type_Struct); @@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); add_entity(ctx->checker, ctx->scope, name, field); array_add(fields, field); + array_add(tags, p->tag.string); field_src_index += 1; } @@ -504,7 +506,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< if (!is_polymorphic) { - check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context); + check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); } if (st->align != nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index ee67c0ea8..2499b848f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -174,6 +174,7 @@ gbAllocator ir_allocator(void) { #define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data" #define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" #define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" #define IR_INSTR_KINDS \ @@ -5271,12 +5272,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr; gb_global irValue *ir_global_type_info_member_names = nullptr; gb_global irValue *ir_global_type_info_member_offsets = nullptr; gb_global irValue *ir_global_type_info_member_usings = nullptr; +gb_global irValue *ir_global_type_info_member_tags = nullptr; gb_global i32 ir_global_type_info_data_index = 0; gb_global i32 ir_global_type_info_member_types_index = 0; gb_global i32 ir_global_type_info_member_names_index = 0; gb_global i32 ir_global_type_info_member_offsets_index = 0; gb_global i32 ir_global_type_info_member_usings_index = 0; +gb_global i32 ir_global_type_info_member_tags_index = 0; isize ir_type_info_count(CheckerInfo *info) { return info->minimum_dependency_type_info_set.entries.count+1; @@ -9587,6 +9590,16 @@ void ir_init_module(irModule *m, Checker *c) { map_set(&m->members, hash_string(name), g); ir_global_type_info_member_usings = g; } + + { + String name = str_lit(IR_TYPE_INFO_TAGS_NAME); + Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), + alloc_type_array(t_string, count), false); + irValue *g = ir_value_global(e, nullptr); + ir_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); + ir_global_type_info_member_tags = g; + } } } } @@ -9720,6 +9733,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) { ir_global_type_info_member_usings_index += cast(i32)count; return offset; } +irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index); + ir_global_type_info_member_tags_index += cast(i32)count; + return offset; +} @@ -10065,9 +10083,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *is_packed = ir_const_bool(t->Struct.is_packed); irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union); irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); } isize count = t->Struct.fields.count; @@ -10076,6 +10094,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *memory_names = ir_type_info_member_names_offset (proc, count); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count); irValue *memory_usings = ir_type_info_member_usings_offset (proc, count); + irValue *memory_tags = ir_type_info_member_tags_offset (proc, count); type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet for (isize source_index = 0; source_index < count; source_index++) { @@ -10091,7 +10110,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *index = ir_const_int(source_index); irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index); - irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); + irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); if (f->token.string.len > 0) { @@ -10100,6 +10119,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info } ir_emit_store(proc, offset, ir_const_uintptr(foffset)); ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0)); + + if (t->Struct.tags.count > 0) { + String tag_string = t->Struct.tags[source_index]; + if (tag_string.len > 0) { + irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index); + ir_emit_store(proc, tag_ptr, ir_const_string(tag_string)); + } + } + } irValue *cv = ir_const_int(count); @@ -10107,6 +10135,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv); } break; } diff --git a/src/parser.cpp b/src/parser.cpp index d1fd94c1d..9aebc78d6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -805,13 +805,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, - CommentGroup *docs, CommentGroup *comment) { +Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, Token tag, + CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_Field); result->Field.names = names; result->Field.type = type; result->Field.default_value = default_value; result->Field.flags = flags; + result->Field.tag = tag; result->Field.docs = docs; result->Field.comment = comment; return result; @@ -2740,7 +2741,8 @@ Ast *parse_results(AstFile *f, bool *diverging) { Array empty_names = {}; auto list = array_make(heap_allocator(), 0, 1); Ast *type = parse_type(f); - array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr)); + Token tag = {}; + array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr)); return ast_field_list(f, begin_token, list); } @@ -3095,6 +3097,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi Ast *type = nullptr; Ast *default_value = nullptr; + Token tag = {}; expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { @@ -3132,16 +3135,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + parse_expect_field_separator(f, type); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); while (f->curr_token.kind != follow && f->curr_token.kind != Token_EOF) { CommentGroup *docs = f->lead_comment; - u32 set_flags = parse_field_prefixes(f); + Token tag = {}; Array names = parse_ident_list(f, allow_poly_names); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); @@ -3184,9 +3196,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + bool ok = parse_expect_field_separator(f, param); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); if (!ok) { @@ -3210,8 +3231,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi token.pos = ast_token(type).pos; names[0] = ast_ident(f, token); u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags); - - Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment); + Token tag = {}; + Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment); array_add(¶ms, param); } diff --git a/src/parser.hpp b/src/parser.hpp index 9f4f68a7b..3489f1a9b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -186,11 +186,12 @@ enum FieldFlag { FieldFlag_c_vararg = 1<<3, FieldFlag_auto_cast = 1<<4, + FieldFlag_Tags = 1<<10, FieldFlag_Results = 1<<16, FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast, - FieldFlag_Struct = FieldFlag_using, + FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags, }; enum StmtAllowFlag { @@ -412,6 +413,7 @@ AST_KIND(_DeclEnd, "", bool) \ Array names; \ Ast * type; \ Ast * default_value; \ + Token tag; \ u32 flags; \ CommentGroup * docs; \ CommentGroup * comment; \ diff --git a/src/types.cpp b/src/types.cpp index e5d2509e0..1197ba974 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -107,6 +107,7 @@ struct BasicType { struct TypeStruct { Array fields; + Array tags; Ast *node; Scope * scope; -- cgit v1.2.3 From 2d26278a658211a9ce6cf6c9d1a8be16ba0e23cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 22:52:19 +0100 Subject: Make structs with the same fields but with different tags distinct types --- examples/demo/demo.odin | 1 - src/types.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/types.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 21f889746..e07eea7c7 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -955,7 +955,6 @@ struct_field_tags :: proc() { z: bool, // no tag } - f: Foo; ti := runtime.type_info_base(type_info_of(Foo)); s := ti.variant.(runtime.Type_Info_Struct); fmt.println("Foo :: struct {"); diff --git a/src/types.cpp b/src/types.cpp index 1197ba974..4404882a9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1712,6 +1712,12 @@ bool are_types_identical(Type *x, Type *y) { if (xf_is_using ^ yf_is_using) { return false; } + if (x->Struct.tags.count != y->Struct.tags.count) { + return false; + } + if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) { + return false; + } } return true; } -- cgit v1.2.3 From cf23954297993b3e574c295f95f75b294fdca4ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Aug 2019 11:51:04 +0100 Subject: Improve #assert to show the procedure and signature it was called with; Allow the ability to print ExactValue correct now. --- src/check_expr.cpp | 9 +++++- src/exact_value.cpp | 46 +++++++++++++++++++++++++++++ src/string.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/types.cpp | 65 ++++++++++++++++++++++++++--------------- 4 files changed, 179 insertions(+), 25 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6c252b9b6..24a130d62 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3360,6 +3360,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (!operand->value.value_bool) { gbString arg = expr_to_string(ce->args[0]); error(call, "Compile time assertion: %s", arg); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } gb_string_free(arg); } @@ -3744,7 +3749,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) { - operand->value = exact_binary_operator_value(Token_Add, x.value, y.value); + f64 r = exact_value_to_float(x.value).value_float; + f64 i = exact_value_to_float(y.value).value_float; + operand->value = exact_value_complex(r, i); operand->mode = Addressing_Constant; } else { operand->mode = Addressing_Value; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 7d822512b..be034ecc5 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -718,3 +718,49 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { GB_PANIC("Invalid comparison"); return false; } + + +gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) { + switch (v.kind) { + case ExactValue_Invalid: + return str; + case ExactValue_Bool: + return gb_string_appendc(str, v.value_bool ? "true" : "false"); + case ExactValue_String: { + String s = quote_to_ascii(heap_allocator(), v.value_string); + string_limit = gb_max(string_limit, 36); + if (s.len <= string_limit) { + str = gb_string_append_length(str, s.text, s.len); + } else { + isize n = string_limit/5; + str = gb_string_append_length(str, s.text, n); + str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n)); + str = gb_string_append_length(str, s.text+s.len-n, n); + } + gb_free(heap_allocator(), s.text); + return str; + } + case ExactValue_Integer: { + String s = big_int_to_string(heap_allocator(), &v.value_integer); + str = gb_string_append_length(str, s.text, s.len); + gb_free(heap_allocator(), s.text); + return str; + } + case ExactValue_Float: + return gb_string_append_fmt(str, "%f", v.value_float); + case ExactValue_Complex: + return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag); + + case ExactValue_Pointer: + return str; + case ExactValue_Compound: + return str; + case ExactValue_Procedure: + return str; + } + return str; +}; + +gbString exact_value_to_string(ExactValue const &v, isize string_limit=35) { + return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit); +} diff --git a/src/string.cpp b/src/string.cpp index 774061edf..a29f3bd77 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) { +bool is_printable(Rune r) { + if (r <= 0xff) { + if (0x20 <= r && r <= 0x7e) { + return true; + } + if (0xa1 <= r && r <= 0xff) { + return r != 0xad; + } + return false; + } + return false; +} +gb_global char const lower_hex[] = "0123456789abcdef"; + +String quote_to_ascii(gbAllocator a, String str, u8 quote='"') { + u8 *s = str.text; + isize n = str.len; + auto buf = array_make(a, 0, n); + array_add(&buf, quote); + for (isize width = 0; n > 0; s += width, n -= width) { + Rune r = cast(Rune)s[0]; + width = 1; + if (r >= 0x80) { + width = gb_utf8_decode(s, n, &r); + } + if (width == 1 && r == GB_RUNE_INVALID) { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[s[0]>>4]); + array_add(&buf, cast(u8)lower_hex[s[0]&0xf]); + continue; + } + if (r == quote || r == '\\') { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, u8(r)); + continue; + } + if (r < 0x80 && is_printable(r)) { + array_add(&buf, u8(r)); + continue; + } + switch (r) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + default: + if (r < ' ') { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[b>>4]); + array_add(&buf, cast(u8)lower_hex[b&0xf]); + } + if (r > GB_RUNE_MAX) { + r = 0XFFFD; + } + if (r < 0x10000) { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'u'); + for (isize i = 12; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } else { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'U'); + for (isize i = 28; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } + } + } - + array_add(&buf, quote); + String res = {}; + res.text = buf.data; + res.len = buf.count; + return res; +} diff --git a/src/types.cpp b/src/types.cpp index 4404882a9..b5c9152b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2968,35 +2968,54 @@ gbString write_type_to_string(gbString str, Type *type) { isize comma_index = 0; for_array(i, type->Tuple.variables) { Entity *var = type->Tuple.variables[i]; - if (var != nullptr) { - if (var->kind == Entity_Constant) { - // Ignore - continue; + if (var == nullptr) { + continue; + } + String name = var->token.string; + if (var->kind == Entity_Constant) { + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + if (!is_type_untyped(var->type)) { + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, var->type); + str = gb_string_appendc(str, " = "); + str = write_exact_value_to_string(str, var->Constant.value); + } else { + str = gb_string_appendc(str, "="); + str = write_exact_value_to_string(str, var->Constant.value); } + continue; + } - if (comma_index++ > 0) { - str = gb_string_appendc(str, ", "); - } + if (comma_index++ > 0) { + str = gb_string_appendc(str, ", "); + } - if (var->kind == Entity_Variable) { - if (var->flags&EntityFlag_CVarArg) { - str = gb_string_appendc(str, "#c_vararg "); - } - if (var->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(var->type); - str = gb_string_appendc(str, ".."); - GB_ASSERT(var->type->kind == Type_Slice); - str = write_type_to_string(str, slice->Slice.elem); - } else { - str = write_type_to_string(str, var->type); - } + if (var->kind == Entity_Variable) { + if (var->flags&EntityFlag_CVarArg) { + str = gb_string_appendc(str, "#c_vararg "); + } + if (var->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(var->type); + str = gb_string_appendc(str, ".."); + GB_ASSERT(var->type->kind == Type_Slice); + str = write_type_to_string(str, slice->Slice.elem); + } else { + str = write_type_to_string(str, var->type); + } + } else { + GB_ASSERT(var->kind == Entity_TypeName); + if (var->type->kind == Type_Generic) { + str = gb_string_appendc(str, "typeid/"); + str = write_type_to_string(str, var->type); } else { - GB_ASSERT(var->kind == Entity_TypeName); - if (var->type->kind == Type_Generic) { - str = gb_string_appendc(str, "type/"); + if (var->kind == Entity_TypeName) { + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + str = gb_string_appendc(str, "="); str = write_type_to_string(str, var->type); } else { - str = gb_string_appendc(str, "type"); + str = gb_string_appendc(str, "typeid"); } } } -- cgit v1.2.3 From 7bc146e6fde909298a7184fdf00cec91868ffc00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 11:33:05 +0100 Subject: Built-in Quaternions (Not just an April Fool's Joke any more) --- core/fmt/fmt.odin | 29 +++++ core/reflect/reflect.odin | 2 + core/runtime/core.odin | 23 ++-- core/runtime/internal.odin | 70 +++++++++++- examples/demo/demo.odin | 60 +++++++++-- src/check_expr.cpp | 242 +++++++++++++++++++++++++++++++++++++++-- src/checker.cpp | 6 ++ src/checker_builtin_procs.hpp | 6 ++ src/exact_value.cpp | 184 +++++++++++++++++++++++++++++-- src/ir.cpp | 245 ++++++++++++++++++++++++++++++++++++++++-- src/ir_print.cpp | 53 +++++++-- src/tokenizer.cpp | 5 +- src/types.cpp | 50 +++++++-- 13 files changed, 909 insertions(+), 66 deletions(-) (limited to 'src/types.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 5dbebf972..a2f1166ac 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1129,6 +1129,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Rune: fmt_arg(fi, v, verb); case runtime.Type_Info_Float: fmt_arg(fi, v, verb); case runtime.Type_Info_Complex: fmt_arg(fi, v, verb); + case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb); case runtime.Type_Info_String: fmt_arg(fi, v, verb); case runtime.Type_Info_Pointer: @@ -1386,6 +1387,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { } } +fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) { + switch verb { + case 'f', 'F', 'v', 'h', 'H': + r, i, j, k := real(q), imag(q), jmag(q), kmag(q); + + fmt_float(fi, r, bits/4, verb); + + if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, i, bits/4, verb); + strings.write_rune(fi.buf, 'i'); + + if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, j, bits/4, verb); + strings.write_rune(fi.buf, 'j'); + + if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, k, bits/4, verb); + strings.write_rune(fi.buf, 'k'); + + case: + fmt_bad_verb(fi, verb); + return; + } +} + fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { if arg == nil { strings.write_string(fi.buf, ""); @@ -1434,6 +1460,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case complex64: fmt_complex(fi, complex128(a), 64, verb); case complex128: fmt_complex(fi, a, 128, verb); + case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb); + case quaternion256: fmt_quaternion(fi, a, 256, verb); + case i8: fmt_int(fi, u64(a), true, 8, verb); case u8: fmt_int(fi, u64(a), false, 8, verb); case i16: fmt_int(fi, u64(a), true, 16, verb); diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index a4450490f..4bc9a2225 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -12,6 +12,7 @@ Type_Kind :: enum { Rune, Float, Complex, + Quaternion, String, Boolean, Any, @@ -42,6 +43,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case runtime.Type_Info_Rune: return .Rune; case runtime.Type_Info_Float: return .Float; case runtime.Type_Info_Complex: return .Complex; + case runtime.Type_Info_Quaternion: return .Quaternion; case runtime.Type_Info_String: return .String; case runtime.Type_Info_Boolean: return .Boolean; case runtime.Type_Info_Any: return .Any; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 047281b10..022a84e9e 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -47,16 +47,17 @@ Type_Info_Endianness :: enum u8 { } // Variant Types -Type_Info_Named :: struct {name: string, base: ^Type_Info}; -Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; -Type_Info_Rune :: struct {}; -Type_Info_Float :: struct {}; -Type_Info_Complex :: struct {}; -Type_Info_String :: struct {is_cstring: bool}; -Type_Info_Boolean :: struct {}; -Type_Info_Any :: struct {}; -Type_Info_Type_Id :: struct {}; -Type_Info_Pointer :: struct { +Type_Info_Named :: struct {name: string, base: ^Type_Info}; +Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; +Type_Info_Rune :: struct {}; +Type_Info_Float :: struct {}; +Type_Info_Complex :: struct {}; +Type_Info_Quaternion :: struct {}; +Type_Info_String :: struct {is_cstring: bool}; +Type_Info_Boolean :: struct {}; +Type_Info_Any :: struct {}; +Type_Info_Type_Id :: struct {}; +Type_Info_Pointer :: struct { elem: ^Type_Info // nil -> rawptr }; Type_Info_Procedure :: struct { @@ -135,6 +136,7 @@ Type_Info :: struct { Type_Info_Rune, Type_Info_Float, Type_Info_Complex, + Type_Info_Quaternion, Type_Info_String, Type_Info_Boolean, Type_Info_Any, @@ -163,6 +165,7 @@ Typeid_Kind :: enum u8 { Rune, Float, Complex, + Quaternion, String, Boolean, Any, diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index c33d5f62c..a5099944b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -357,6 +357,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } +quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } + +quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { @@ -546,9 +551,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { r, i := real(x), imag(x); return _sqrt_f64(r*r + i*i); } +abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f32(r*r + i*i + j*j + k*k); +} +abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f64(r*r + i*i + j*j + k*k); +} - -quo_complex64 :: proc(n, m: complex64) -> complex64 { +quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 { e, f: f32; if abs(real(m)) >= abs(imag(m)) { @@ -566,7 +578,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 { return complex(e, f); } -quo_complex128 :: proc(n, m: complex128) -> complex128 { +quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 { e, f: f64; if abs(real(m)) >= abs(imag(m)) { @@ -583,3 +595,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 { return complex(e, f); } + +mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 343c50ff7..a96056b61 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -326,7 +326,7 @@ union_type :: proc() { } parametric_polymorphism :: proc() { - fmt.println("# parametric_polymorphism"); + fmt.println("\n# parametric_polymorphism"); print_value :: proc(value: $T) { fmt.printf("print_value: %T %v\n", value, value); @@ -561,7 +561,7 @@ prefix_table := [?]string{ threading_example :: proc() { when os.OS == "windows" { - fmt.println("# threading_example"); + fmt.println("\n# threading_example"); worker_proc :: proc(t: ^thread.Thread) -> int { for iteration in 1..5 { @@ -601,7 +601,7 @@ threading_example :: proc() { } array_programming :: proc() { - fmt.println("# array_programming"); + fmt.println("\n# array_programming"); { a := [3]f32{1, 2, 3}; b := [3]f32{5, 6, 7}; @@ -646,7 +646,7 @@ array_programming :: proc() { } named_proc_return_parameters :: proc() { - fmt.println("# named proc return parameters"); + fmt.println("\n# named proc return parameters"); foo0 :: proc() -> int { return 123; @@ -668,7 +668,7 @@ named_proc_return_parameters :: proc() { using_enum :: proc() { - fmt.println("# using enum"); + fmt.println("\n# using enum"); using Foo :: enum {A, B, C}; @@ -680,7 +680,7 @@ using_enum :: proc() { } map_type :: proc() { - fmt.println("# map type"); + fmt.println("\n# map type"); // enums of type u16, u32, i16 & i32 also work Enum_u8 :: enum u8 { @@ -735,7 +735,7 @@ map_type :: proc() { } implicit_selector_expression :: proc() { - fmt.println("# implicit selector expression"); + fmt.println("\n# implicit selector expression"); Foo :: enum {A, B, C}; @@ -763,7 +763,7 @@ implicit_selector_expression :: proc() { } explicit_procedure_overloading :: proc() { - fmt.println("# explicit procedure overloading"); + fmt.println("\n# explicit procedure overloading"); add_ints :: proc(a, b: int) -> int { x := a + b; @@ -797,7 +797,7 @@ explicit_procedure_overloading :: proc() { } complete_switch :: proc() { - fmt.println("# complete_switch"); + fmt.println("\n# complete_switch"); { // enum using Foo :: enum { A, @@ -947,7 +947,7 @@ deferred_procedure_associations :: proc() { } reflection :: proc() { - fmt.println("# reflection"); + fmt.println("\n# reflection"); Foo :: struct { x: int `tag1`, @@ -981,6 +981,45 @@ reflection :: proc() { } } +quaternions :: proc() { + fmt.println("\n# quaternions"); + + { // Quaternion operations + q := 1 + 2i + 3j + 4k; + r := quaternion(5, 6, 7, 8); + t := q * r; + fmt.printf("(%v) * (%v) = %v\n", q, r, t); + v := q / r; + fmt.printf("(%v) / (%v) = %v\n", q, r, v); + u := q + r; + fmt.printf("(%v) + (%v) = %v\n", q, r, u); + s := q - r; + fmt.printf("(%v) - (%v) = %v\n", q, r, s); + } + { // The quaternion types + q128: quaternion128; // 4xf32 + q256: quaternion256; // 4xf64 + q128 = quaternion(1, 0, 0, 0); + q256 = 1; // quaternion(1, 0, 0, 0); + } + { // Built-in procedures + q := 1 + 2i + 3j + 4k; + fmt.println("q =", q); + fmt.println("real(q) =", real(q)); + fmt.println("imag(q) =", imag(q)); + fmt.println("jmag(q) =", jmag(q)); + fmt.println("kmag(q) =", kmag(q)); + fmt.println("conj(q) =", conj(q)); + fmt.println("abs(q) =", abs(q)); + } + { // Conversion of a complex type to a quaternion type + c := 1 + 2i; + q := quaternion256(c); + fmt.println(c); + fmt.println(q); + } +} + main :: proc() { when true { general_stuff(); @@ -1000,5 +1039,6 @@ main :: proc() { diverging_procedures(); deferred_procedure_associations(); reflection(); + quaternions(); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 24a130d62..6a9a53275 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -497,6 +497,14 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type if (is_type_complex(dst)) { return 1; } + if (is_type_quaternion(dst)) { + return 2; + } + break; + case Basic_UntypedQuaternion: + if (is_type_quaternion(dst)) { + return 1; + } break; } } @@ -1438,7 +1446,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ ExactValue imag = exact_value_imag(v); if (real.kind != ExactValue_Invalid && imag.kind != ExactValue_Invalid) { - if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag)); + if (out_value) *out_value = exact_value_complex(exact_value_to_f64(real), exact_value_to_f64(imag)); return true; } break; @@ -1449,6 +1457,36 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ default: GB_PANIC("Compiler error: Unknown complex type!"); break; } + return false; + } else if (is_type_quaternion(type)) { + ExactValue v = exact_value_to_quaternion(in_value); + if (v.kind != ExactValue_Quaternion) { + return false; + } + + switch (type->Basic.kind) { + case Basic_quaternion128: + case Basic_quaternion256: { + ExactValue real = exact_value_real(v); + ExactValue imag = exact_value_imag(v); + ExactValue jmag = exact_value_jmag(v); + ExactValue kmag = exact_value_kmag(v); + if (real.kind != ExactValue_Invalid && + imag.kind != ExactValue_Invalid) { + if (out_value) *out_value = exact_value_quaternion(exact_value_to_f64(real), exact_value_to_f64(imag), exact_value_to_f64(jmag), exact_value_to_f64(kmag)); + return true; + } + break; + } + case Basic_UntypedComplex: + if (out_value) *out_value = exact_value_to_quaternion(*out_value); + return true; + case Basic_UntypedQuaternion: + return true; + + default: GB_PANIC("Compiler error: Unknown complex type!"); break; + } + return false; } else if (is_type_pointer(type)) { if (in_value.kind == ExactValue_Pointer) { @@ -1481,10 +1519,14 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s'", a, b); } else { + #if 0 gbAllocator ha = heap_allocator(); String str = big_int_to_string(ha, &o->value.value_integer); defer (gb_free(ha, str.text)); error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b); + #else + error(o->expr, "Cannot convert '%s' to '%s'", a, b); + #endif } } else { error(o->expr, "Cannot convert '%s' to '%s'", a, b); @@ -1759,6 +1801,21 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } break; } + } else if (is_type_quaternion(x->type) || is_type_quaternion(y->type)) { + switch (op) { + case Token_CmpEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_eq"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_eq"); break; + } + break; + case Token_NotEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_ne"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_ne"); break; + } + break; + } } } @@ -1978,6 +2035,14 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { return true; } + if (is_type_complex(src) && is_type_quaternion(dst)) { + return true; + } + + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + return true; + } + if (is_type_bit_field_value(src) && is_type_integer(dst)) { return true; } @@ -2557,6 +2622,8 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { v = exact_value_to_integer(v); } else if (is_type_complex(t)) { v = exact_value_to_complex(v); + } else if (is_type_quaternion(t)) { + v = exact_value_to_quaternion(v); } return v; } @@ -2652,6 +2719,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { case Basic_UntypedInteger: case Basic_UntypedFloat: case Basic_UntypedComplex: + case Basic_UntypedQuaternion: case Basic_UntypedRune: if (!is_type_numeric(target_type)) { operand->mode = Addressing_Invalid; @@ -3769,10 +3837,98 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_quaternion: { + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type + Operand x = *operand; + Operand y = {}; + Operand z = {}; + Operand w = {}; + + // NOTE(bill): Invalid will be the default till fixed + operand->type = t_invalid; + operand->mode = Addressing_Invalid; + + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &z, ce->args[2]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &w, ce->args[3]); + if (y.mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; + convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && + y.mode == Addressing_Constant && + z.mode == Addressing_Constant && + w.mode == Addressing_Constant) { + if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) { + x.type = t_untyped_float; + } + if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) { + y.type = t_untyped_float; + } + if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) { + z.type = t_untyped_float; + } + if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) { + w.type = t_untyped_float; + } + } + + if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) { + gbString tx = type_to_string(x.type); + gbString ty = type_to_string(y.type); + gbString tz = type_to_string(z.type); + gbString tw = type_to_string(w.type); + error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw); + gb_string_free(tw); + gb_string_free(tz); + gb_string_free(ty); + gb_string_free(tx); + return false; + } + + if (!is_type_float(x.type)) { + gbString s = type_to_string(x.type); + error(call, "Arguments have type '%s', expected a floating point", s); + gb_string_free(s); + return false; + } + + if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) { + f64 r = exact_value_to_float(x.value).value_float; + f64 i = exact_value_to_float(y.value).value_float; + f64 j = exact_value_to_float(z.value).value_float; + f64 k = exact_value_to_float(w.value).value_float; + operand->value = exact_value_quaternion(r, i, j, k); + operand->mode = Addressing_Constant; + } else { + operand->mode = Addressing_Value; + } + + BasicKind kind = core_type(x.type)->Basic.kind; + switch (kind) { + case Basic_f32: operand->type = t_quaternion128; break; + case Basic_f64: operand->type = t_quaternion256; break; + case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + case BuiltinProc_real: case BuiltinProc_imag: { // real :: proc(x: type) -> float_type - // proc imag(x: type) -> float_type + // imag :: proc(x: type) -> float_type Operand *x = operand; if (is_type_untyped(x->type)) { @@ -3780,7 +3936,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_type_numeric(x->type)) { x->type = t_untyped_complex; } - } else { + } else if (is_type_quaternion(x->type)) { + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } else{ convert_to_typed(c, x, t_complex128); if (x->mode == Addressing_Invalid) { return false; @@ -3788,9 +3949,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } - if (!is_type_complex(x->type)) { + if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) { gbString s = type_to_string(x->type); - error(call, "Argument has type '%s', expected a complex type", s); + error(call, "Argument has type '%s', expected a complex or quaternion type", s); gb_string_free(s); return false; } @@ -3808,7 +3969,57 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 switch (kind) { case Basic_complex64: x->type = t_f32; break; case Basic_complex128: x->type = t_f64; break; + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + + case BuiltinProc_jmag: + case BuiltinProc_kmag: { + // jmag :: proc(x: type) -> float_type + // kmag :: proc(x: type) -> float_type + + Operand *x = operand; + if (is_type_untyped(x->type)) { + if (x->mode == Addressing_Constant) { + if (is_type_numeric(x->type)) { + x->type = t_untyped_complex; + } + } else{ + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } + } + + if (!is_type_quaternion(x->type)) { + gbString s = type_to_string(x->type); + error(call, "Argument has type '%s', expected a quaternion type", s); + gb_string_free(s); + return false; + } + + if (x->mode == Addressing_Constant) { + switch (id) { + case BuiltinProc_jmag: x->value = exact_value_jmag(x->value); break; + case BuiltinProc_kmag: x->value = exact_value_kmag(x->value); break; + } + } else { + x->mode = Addressing_Value; + } + + BasicKind kind = core_type(x->type)->Basic.kind; + switch (kind) { + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; + case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; default: GB_PANIC("Invalid type"); break; } @@ -3822,12 +4033,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (x->mode == Addressing_Constant) { ExactValue v = exact_value_to_complex(x->value); f64 r = v.value_complex.real; - f64 i = v.value_complex.imag; + f64 i = -v.value_complex.imag; x->value = exact_value_complex(r, i); x->mode = Addressing_Constant; } else { x->mode = Addressing_Value; } + } else if (is_type_quaternion(x->type)) { + if (x->mode == Addressing_Constant) { + ExactValue v = exact_value_to_quaternion(x->value); + f64 r = v.value_quaternion.real; + f64 i = -v.value_quaternion.imag; + f64 j = -v.value_quaternion.jmag; + f64 k = -v.value_quaternion.kmag; + x->value = exact_value_quaternion(r, i, j, k); + x->mode = Addressing_Constant; + } else { + x->mode = Addressing_Value; + } } else { gbString s = type_to_string(x->type); error(call, "Expected a complex or quaternion, got '%s'", s); @@ -4226,6 +4449,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "abs_f64"); if (are_types_identical(bt, t_complex64)) add_package_dependency(c, "runtime", "abs_complex64"); if (are_types_identical(bt, t_complex128)) add_package_dependency(c, "runtime", "abs_complex128"); + if (are_types_identical(bt, t_quaternion128)) add_package_dependency(c, "runtime", "abs_quaternion128"); + if (are_types_identical(bt, t_quaternion256)) add_package_dependency(c, "runtime", "abs_quaternion256"); } } @@ -6232,8 +6457,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Token_Imag: { String s = bl->token.string; Rune r = s[s.len-1]; + // NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers switch (r) { - case 'i': t = t_untyped_complex; break; + case 'i': t = t_untyped_complex; break; + case 'j': t = t_untyped_quaternion; break; + case 'k': t = t_untyped_quaternion; break; } break; diff --git a/src/checker.cpp b/src/checker.cpp index 45b661a58..d6f5ad402 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1610,6 +1610,10 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("quo_complex64"), str_lit("quo_complex128"), + str_lit("mul_quaternion128"), + str_lit("mul_quaternion256"), + str_lit("quo_quaternion128"), + str_lit("quo_quaternion256"), str_lit("umodti3"), str_lit("udivti3"), @@ -1891,6 +1895,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); + t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion")); t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); @@ -1915,6 +1920,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); + t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion); t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 536d47616..0135b3c50 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -16,8 +16,11 @@ enum BuiltinProcId { BuiltinProc_swizzle, BuiltinProc_complex, + BuiltinProc_quaternion, BuiltinProc_real, BuiltinProc_imag, + BuiltinProc_jmag, + BuiltinProc_kmag, BuiltinProc_conj, BuiltinProc_expand_to_tuple, @@ -172,8 +175,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 520812e44..54d4ef6f2 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y); struct Complex128 { f64 real, imag; }; +struct Quaternion256 { + f64 imag, jmag, kmag, real; +}; + +Quaternion256 quaternion256_inverse(Quaternion256 x) { + f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag); + x.real = +x.real * invmag2; + x.imag = -x.imag * invmag2; + x.jmag = -x.jmag * invmag2; + x.kmag = -x.kmag * invmag2; + return x; +} + enum ExactValueKind { ExactValue_Invalid, @@ -21,6 +34,7 @@ enum ExactValueKind { ExactValue_Integer, ExactValue_Float, ExactValue_Complex, + ExactValue_Quaternion, ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough? @@ -37,6 +51,7 @@ struct ExactValue { f64 value_float; i64 value_pointer; Complex128 value_complex; + Quaternion256 value_quaternion; Ast * value_compound; Ast * value_procedure; }; @@ -61,7 +76,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_integer(v.value_pointer); case ExactValue_Complex: return hashing_proc(&v.value_complex, gb_size_of(Complex128)); - + case ExactValue_Quaternion: + return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256)); case ExactValue_Compound: return hash_pointer(v.value_compound); case ExactValue_Procedure: @@ -116,6 +132,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) { return result; } +ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) { + ExactValue result = {ExactValue_Quaternion}; + result.value_quaternion.real = real; + result.value_quaternion.imag = imag; + result.value_quaternion.jmag = jmag; + result.value_quaternion.kmag = kmag; + return result; +} + ExactValue exact_value_pointer(i64 ptr) { ExactValue result = {ExactValue_Pointer}; result.value_pointer = ptr; @@ -253,8 +278,10 @@ ExactValue exact_value_from_basic_literal(Token token) { str.len--; // Ignore the 'i|j|k' f64 imag = float_from_string(str); - if (last_rune == 'i') { - return exact_value_complex(0, imag); + switch (last_rune) { + case 'i': return exact_value_complex(0, imag); + case 'j': return exact_value_quaternion(0, 0, imag, 0); + case 'k': return exact_value_quaternion(0, 0, 0, imag); } } case Token_Rune: { @@ -318,11 +345,26 @@ ExactValue exact_value_to_complex(ExactValue v) { return exact_value_complex(v.value_float, 0); case ExactValue_Complex: return v; + // case ExactValue_Quaternion: + // return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} +ExactValue exact_value_to_quaternion(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0); + case ExactValue_Float: + return exact_value_quaternion(v.value_float, 0, 0, 0); + case ExactValue_Complex: + return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0); + case ExactValue_Quaternion: + return v; } ExactValue r = {ExactValue_Invalid}; return r; } - ExactValue exact_value_real(ExactValue v) { switch (v.kind) { @@ -331,6 +373,8 @@ ExactValue exact_value_real(ExactValue v) { return v; case ExactValue_Complex: return exact_value_float(v.value_complex.real); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.real); } ExactValue r = {ExactValue_Invalid}; return r; @@ -343,6 +387,34 @@ ExactValue exact_value_imag(ExactValue v) { return exact_value_i64(0); case ExactValue_Complex: return exact_value_float(v.value_complex.imag); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.jmag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.kmag); } ExactValue r = {ExactValue_Invalid}; return r; @@ -361,6 +433,32 @@ ExactValue exact_value_make_imag(ExactValue v) { return r; } +ExactValue exact_value_make_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0); + case ExactValue_Float: + return exact_value_quaternion(0, 0, v.value_float, 0); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_make_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float); + case ExactValue_Float: + return exact_value_quaternion(0, 0, 0, v.value_float); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + i64 exact_value_to_i64(ExactValue v) { v = exact_value_to_integer(v); if (v.kind == ExactValue_Integer) { @@ -389,6 +487,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, case ExactValue_Integer: case ExactValue_Float: case ExactValue_Complex: + case ExactValue_Quaternion: return v; } break; @@ -413,6 +512,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, f64 imag = v.value_complex.imag; return exact_value_complex(-real, -imag); } + case ExactValue_Quaternion: { + f64 real = v.value_quaternion.real; + f64 imag = v.value_quaternion.imag; + f64 jmag = v.value_quaternion.jmag; + f64 kmag = v.value_quaternion.kmag; + return exact_value_quaternion(-real, -imag, -jmag, -kmag); + } } break; } @@ -463,8 +569,10 @@ i32 exact_value_order(ExactValue const &v) { return 3; case ExactValue_Complex: return 4; - case ExactValue_Pointer: + case ExactValue_Quaternion: return 5; + case ExactValue_Pointer: + return 6; default: GB_PANIC("How'd you get here? Invalid Value.kind"); @@ -485,7 +593,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Bool: case ExactValue_String: - case ExactValue_Complex: + case ExactValue_Quaternion: return; case ExactValue_Integer: @@ -499,6 +607,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_complex(big_int_to_f64(&x->value_integer), 0); return; + case ExactValue_Quaternion: + *x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0); + return; } break; @@ -509,6 +620,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_to_complex(*x); return; + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; + } + break; + + case ExactValue_Complex: + switch (y->kind) { + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; } break; } @@ -606,6 +728,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) break; } + case ExactValue_Quaternion: { + y = exact_value_to_quaternion(y); + f64 xr = x.value_quaternion.real; + f64 xi = x.value_quaternion.imag; + f64 xj = x.value_quaternion.jmag; + f64 xk = x.value_quaternion.kmag; + f64 yr = y.value_quaternion.real; + f64 yi = y.value_quaternion.imag; + f64 yj = y.value_quaternion.jmag; + f64 yk = y.value_quaternion.kmag; + + + f64 real = 0; + f64 imag = 0; + f64 jmag = 0; + f64 kmag = 0; + + switch (op) { + case Token_Add: + real = xr + yr; + imag = xi + yi; + jmag = xj + yj; + kmag = xk + yk; + break; + case Token_Sub: + real = xr - yr; + imag = xi - yi; + jmag = xj - yj; + kmag = xk - yk; + break; + case Token_Mul: + imag = xr * yi + xi * yr + xj * yk - xk * yj; + jmag = xr * yj - xi * yk + xj * yr + xk * yi; + kmag = xr * yk + xi * yj - xj * yi + xk * yr; + real = xr * yr - xi * yi - xj * yj - xk * yk; + break; + case Token_Quo: { + f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk); + imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2; + jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2; + kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2; + real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2; + break; + } + default: goto error; + } + return exact_value_quaternion(real, imag, jmag, kmag); + break; + } + case ExactValue_String: { if (op != Token_Add) goto error; diff --git a/src/ir.cpp b/src/ir.cpp index 2499b848f..2a4bb028b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3853,6 +3853,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_load(proc, res); } + if (is_type_quaternion(t_left)) { + ir_emit_comment(proc, str_lit("complex.arith.begin")); + defer (ir_emit_comment(proc, str_lit("complex.arith.end"))); + + right = ir_emit_conv(proc, right, t_left); + + Type *ft = base_complex_elem_type(t_left); + + if (op == Token_Add || op == Token_Sub) { + irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later + irValue *x0 = ir_emit_struct_ev(proc, left, 0); + irValue *x1 = ir_emit_struct_ev(proc, left, 1); + irValue *x2 = ir_emit_struct_ev(proc, left, 2); + irValue *x3 = ir_emit_struct_ev(proc, left, 3); + + irValue *y0 = ir_emit_struct_ev(proc, right, 0); + irValue *y1 = ir_emit_struct_ev(proc, right, 1); + irValue *y2 = ir_emit_struct_ev(proc, right, 2); + irValue *y3 = ir_emit_struct_ev(proc, right, 3); + + irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft); + irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft); + irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft); + irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft); + + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3); + + return ir_emit_load(proc, res); + } else if (op == Token_Mul) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } else if (op == Token_Quo) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } + } + #if 0 if (op == Token_Add) { @@ -4188,7 +4242,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } if (is_type_complex(a)) { - char *runtime_proc = ""; + char const *runtime_proc = ""; i64 sz = 8*type_size_of(a); switch (sz) { case 64: @@ -4212,6 +4266,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_runtime_call(proc, runtime_proc, args); } + if (is_type_quaternion(a)) { + char const *runtime_proc = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion128_eq"; break; + case Token_NotEq: runtime_proc = "quaternion128_ne"; break; + } + break; + case 256: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion256_eq"; break; + case Token_NotEq: runtime_proc = "quaternion256_ne"; break; + } + break; + } + GB_ASSERT(runtime_proc != nullptr); + + auto args = array_make(ir_allocator(), 2); + args[0] = left; + args[1] = right; + return ir_emit_runtime_call(proc, runtime_proc, args); + } + if (is_type_bit_set(a)) { switch (op_kind) { case Token_Lt: @@ -4295,11 +4374,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = alloc_type_pointer(ft); break; case 1: result_type = alloc_type_pointer(ft); break; } + } else if (is_type_quaternion(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = alloc_type_pointer(ft); break; + case 1: result_type = alloc_type_pointer(ft); break; + case 2: result_type = alloc_type_pointer(ft); break; + case 3: result_type = alloc_type_pointer(ft); break; + } } else if (is_type_slice(t)) { switch (index) { case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break; case 1: result_type = alloc_type_pointer(t_int); break; - case 2: result_type = alloc_type_pointer(t_int); break; } } else if (is_type_string(t)) { switch (index) { @@ -4370,6 +4456,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; } + case Basic_quaternion128: case Basic_quaternion256: + { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + break; + } } break; case Type_Struct: @@ -4752,6 +4849,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { ev = exact_value_to_float(ev); } else if (is_type_complex(dst)) { ev = exact_value_to_complex(ev); + } else if (is_type_quaternion(dst)) { + ev = exact_value_to_quaternion(ev); } else if (is_type_string(dst)) { // Handled elsewhere GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind); @@ -4875,6 +4974,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return ir_emit_load(proc, gen); } + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + // @QuaternionLayout + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, false); + irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft); + irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3); + return ir_emit_load(proc, gen); + } + + if (is_type_float(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real); + return ir_emit_load(proc, gen); + } + if (is_type_float(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + return ir_emit_load(proc, gen); + } + if (is_type_complex(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag); + return ir_emit_load(proc, gen); + } + + + // float <-> integer if (is_type_float(src) && is_type_integer(dst)) { irConvKind kind = irConv_fptosi; @@ -5315,6 +5457,7 @@ enum Typeid_Kind : u8 { Typeid_Rune, Typeid_Float, Typeid_Complex, + Typeid_Quaternion, Typeid_String, Typeid_Boolean, Typeid_Any, @@ -6067,17 +6210,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return ir_emit_load(proc, dst); } + case BuiltinProc_quaternion: { + ir_emit_comment(proc, str_lit("quaternion")); + irValue *real = ir_build_expr(proc, ce->args[0]); + irValue *imag = ir_build_expr(proc, ce->args[1]); + irValue *jmag = ir_build_expr(proc, ce->args[2]); + irValue *kmag = ir_build_expr(proc, ce->args[3]); + + // @QuaternionLayout + irValue *dst = ir_add_local_generated(proc, tv.type, false); + Type *ft = base_complex_elem_type(tv.type); + real = ir_emit_conv(proc, real, ft); + imag = ir_emit_conv(proc, imag, ft); + jmag = ir_emit_conv(proc, jmag, ft); + kmag = ir_emit_conv(proc, kmag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag); + + return ir_emit_load(proc, dst); + } + case BuiltinProc_real: { ir_emit_comment(proc, str_lit("real")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *real = ir_emit_struct_ev(proc, val, 0); - return ir_emit_conv(proc, real, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *real = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, real, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *real = ir_emit_struct_ev(proc, val, 3); + return ir_emit_conv(proc, real, tv.type); + } + GB_PANIC("invalid type for real"); + return nullptr; } case BuiltinProc_imag: { ir_emit_comment(proc, str_lit("imag")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *imag = ir_emit_struct_ev(proc, val, 1); - return ir_emit_conv(proc, imag, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for imag"); + return nullptr; + } + case BuiltinProc_jmag: { + ir_emit_comment(proc, str_lit("jmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for jmag"); + return nullptr; + } + case BuiltinProc_kmag: { + ir_emit_comment(proc, str_lit("kmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 2); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for kmag"); + return nullptr; } case BuiltinProc_conj: { @@ -6092,6 +6295,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + } else if (is_type_quaternion(t)) { + // @QuaternionLayout + res = ir_add_local_generated(proc, tv.type, false); + irValue *real = ir_emit_struct_ev(proc, val, 3); + irValue *imag = ir_emit_struct_ev(proc, val, 0); + irValue *jmag = ir_emit_struct_ev(proc, val, 1); + irValue *kmag = ir_emit_struct_ev(proc, val, 2); + imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); + jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag)); + kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag)); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag); } return ir_emit_load(proc, res); } @@ -6162,7 +6379,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return x; } ir_emit_comment(proc, str_lit("abs")); - if (is_type_complex(t)) { + if (is_type_quaternion(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(ir_allocator(), 1); + args[0] = x; + switch (sz) { + case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args); + case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_complex(t)) { i64 sz = 8*type_size_of(t); auto args = array_make(ir_allocator(), 1); args[0] = x; @@ -9876,6 +10102,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr); break; + case Basic_quaternion128: + case Basic_quaternion256: + tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr); + break; + case Basic_rawptr: tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr); break; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c1e41c4b0..30ad914a9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -418,20 +418,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { } return; - // case Basic_f16: ir_write_str_lit(f, "half"); return; - case Basic_f32: ir_write_str_lit(f, "float"); return; - case Basic_f64: ir_write_str_lit(f, "double"); return; + // case Basic_f16: ir_write_str_lit(f, "half"); return; + case Basic_f32: ir_write_str_lit(f, "float"); return; + case Basic_f64: ir_write_str_lit(f, "double"); return; - // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; - case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; - case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; + // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; + case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; + case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; - case Basic_any: ir_write_str_lit(f, "%..any"); return; - case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; - case Basic_string: ir_write_str_lit(f, "%..string"); return; - case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return; + case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return; - case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; + case Basic_any: ir_write_str_lit(f, "%..any"); return; + case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; + case Basic_string: ir_write_str_lit(f, "%..string"); return; + case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + + case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; } break; @@ -811,6 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * break; } case ExactValue_Complex: { + // xy/ri format type = core_type(type); GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); Type *ft = base_complex_elem_type(type); @@ -823,6 +827,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_byte(f, '}'); break; } + + case ExactValue_Quaternion: { + // xyzw/ijkr format + type = core_type(type); + GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type)); + Type *ft = base_complex_elem_type(type); + ir_write_byte(f, ' '); + ir_write_byte(f, '{'); + ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft); + ir_write_byte(f, '}'); + break; + } + case ExactValue_Pointer: if (value.value_pointer == 0) { if (is_type_typeid(type)) { @@ -2246,6 +2270,13 @@ void print_llvm_ir(irGen *ir) { ir_print_encoded_local(f, str_lit("..complex128")); ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n"); + ir_print_encoded_local(f, str_lit("..quaternion64")); + ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n"); + ir_print_encoded_local(f, str_lit("..quaternion128")); + ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n"); + ir_print_encoded_local(f, str_lit("..quaternion256")); + ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n"); + ir_print_encoded_local(f, str_lit("..typeid")); ir_write_str_lit(f, " = type "); ir_print_type(f, m, t_uintptr); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a551f0545..5ba402858 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -745,7 +745,10 @@ exponent: scan_mantissa(t, 10); } - if (t->curr_rune == 'i') { + switch (t->curr_rune) { + case 'i': + case 'j': + case 'k': token.kind = Token_Imag; advance_to_next_rune(t); } diff --git a/src/types.cpp b/src/types.cpp index b5c9152b6..94b89d8f5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -32,6 +32,9 @@ enum BasicKind { Basic_complex64, Basic_complex128, + Basic_quaternion128, + Basic_quaternion256, + Basic_int, Basic_uint, Basic_uintptr, @@ -66,6 +69,7 @@ enum BasicKind { Basic_UntypedInteger, Basic_UntypedFloat, Basic_UntypedComplex, + Basic_UntypedQuaternion, Basic_UntypedString, Basic_UntypedRune, Basic_UntypedNil, @@ -82,17 +86,18 @@ enum BasicFlag { BasicFlag_Unsigned = GB_BIT(2), BasicFlag_Float = GB_BIT(3), BasicFlag_Complex = GB_BIT(4), - BasicFlag_Pointer = GB_BIT(5), - BasicFlag_String = GB_BIT(6), - BasicFlag_Rune = GB_BIT(7), - BasicFlag_Untyped = GB_BIT(8), + BasicFlag_Quaternion = GB_BIT(5), + BasicFlag_Pointer = GB_BIT(6), + BasicFlag_String = GB_BIT(7), + BasicFlag_Rune = GB_BIT(8), + BasicFlag_Untyped = GB_BIT(9), - BasicFlag_LLVM = GB_BIT(10), + BasicFlag_LLVM = GB_BIT(11), BasicFlag_EndianLittle = GB_BIT(13), BasicFlag_EndianBig = GB_BIT(14), - BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, + BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion, BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, @@ -342,6 +347,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, + {Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}}, + {Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}}, + {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, @@ -377,6 +385,7 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, {Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}}, + {Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}}, {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, @@ -412,6 +421,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; +gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128]; +gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256]; + gb_global Type *t_int = &basic_types[Basic_int]; gb_global Type *t_uint = &basic_types[Basic_uint]; gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; @@ -446,6 +458,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex]; +gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; @@ -472,6 +485,7 @@ gb_global Type *t_type_info_integer = nullptr; gb_global Type *t_type_info_rune = nullptr; gb_global Type *t_type_info_float = nullptr; gb_global Type *t_type_info_complex = nullptr; +gb_global Type *t_type_info_quaternion = nullptr; gb_global Type *t_type_info_any = nullptr; gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_string = nullptr; @@ -496,6 +510,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr; gb_global Type *t_type_info_rune_ptr = nullptr; gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr; +gb_global Type *t_type_info_quaternion_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr; gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; @@ -924,6 +939,13 @@ bool is_type_complex(Type *t) { } return false; } +bool is_type_quaternion(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + return (t->Basic.flags & BasicFlag_Quaternion) != 0; + } + return false; +} bool is_type_f32(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1063,12 +1085,15 @@ bool is_type_simple_compare(Type *t) { Type *base_complex_elem_type(Type *t) { t = core_type(t); - if (is_type_complex(t)) { + if (t->kind == Type_Basic) { switch (t->Basic.kind) { - // case Basic_complex32: return t_f16; - case Basic_complex64: return t_f32; - case Basic_complex128: return t_f64; - case Basic_UntypedComplex: return t_untyped_float; + // case Basic_complex32: return t_f16; + case Basic_complex64: return t_f32; + case Basic_complex128: return t_f64; + case Basic_quaternion128: return t_f32; + case Basic_quaternion256: return t_f64; + case Basic_UntypedComplex: return t_untyped_float; + case Basic_UntypedQuaternion: return t_untyped_float; } } GB_PANIC("Invalid complex type"); @@ -1818,6 +1843,7 @@ Type *default_type(Type *type) { case Basic_UntypedInteger: return t_int; case Basic_UntypedFloat: return t_f64; case Basic_UntypedComplex: return t_complex128; + case Basic_UntypedQuaternion: return t_quaternion256; case Basic_UntypedString: return t_string; case Basic_UntypedRune: return t_rune; } @@ -2358,6 +2384,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_complex64: case Basic_complex128: return type_size_of_internal(t, path) / 2; + case Basic_quaternion128: case Basic_quaternion256: + return type_size_of_internal(t, path) / 4; } } break; -- cgit v1.2.3 From 7fa2d25eea28955c12d8fc6a597e8615562c0ee9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Oct 2019 10:22:41 +0100 Subject: Fix #complete switch with pointer case doesn't compile #416 --- src/check_stmt.cpp | 4 ++-- src/types.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 9163fadc2..26e3f8c26 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1205,7 +1205,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { GB_PANIC("Unknown type to type switch statement"); } - if (ptr_set_exists(&seen, y.type)) { + if (type_ptr_set_exists(&seen, y.type)) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); error(y.expr, @@ -1257,7 +1257,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { for_array(i, variants) { Type *t = variants[i]; - if (!ptr_set_exists(&seen, t)) { + if (!type_ptr_set_exists(&seen, t)) { array_add(&unhandled, t); } } diff --git a/src/types.cpp b/src/types.cpp index 94b89d8f5..d8a579510 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -551,8 +551,27 @@ i64 type_offset_of (Type *t, i32 index); gbString type_to_string (Type *type); void init_map_internal_types(Type *type); Type * bit_set_to_int(Type *t); +bool are_types_identical(Type *x, Type *y); +bool type_ptr_set_exists(PtrSet *s, Type *t) { + if (ptr_set_exists(s, t)) { + return true; + } + + // TODO(bill, 2019-10-05): This is very slow and it's probably a lot + // faster to cache types correctly + for_array(i, s->entries) { + Type *f = s->entries[i].ptr; + if (are_types_identical(t, f)) { + ptr_set_add(s, t); + return true; + } + } + + return false; +} + Type *base_type(Type *t) { for (;;) { if (t == nullptr) { -- cgit v1.2.3 From 2a6d9e8927ad1eb1e5f3a79fc9ed068a02cbfdfc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 12:38:23 +0100 Subject: `#panic`; Minor change to demo.odin; Fix `#assert` bug at file scope --- core/odin/parser/parser.odin | 2 +- core/runtime/core.odin | 54 +++++++++++++++++++----------------- examples/demo/demo.odin | 20 +++++++------- src/check_expr.cpp | 22 +++++++++++++-- src/check_type.cpp | 37 ++++++++++++++++++++----- src/checker.cpp | 13 +++++++-- src/checker.hpp | 1 + src/main.cpp | 14 ++++------ src/parser.cpp | 38 +++---------------------- src/types.cpp | 66 ++++++++++++++++++++++++-------------------- 10 files changed, 145 insertions(+), 122 deletions(-) (limited to 'src/types.cpp') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 213041924..fee9b7bdc 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1091,7 +1091,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case: error(p, stmt.pos, "#complete can only be applied to a switch statement"); } return stmt; - case "assert": + case "assert", "panic": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag)); bd.tok = tok; bd.name = name; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 729932781..9ad5d3d8a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -6,6 +6,7 @@ package runtime import "core:os" import "core:mem" import "core:log" +import "intrinsics" // Naming Conventions: // In general, Ada_Case for types and snake_case for values @@ -187,12 +188,13 @@ Typeid_Kind :: enum u8 { #assert(len(Typeid_Kind) < 32); Typeid_Bit_Field :: bit_field #align align_of(uintptr) { - index: 8*size_of(align_of(uintptr)) - 8, + index: 8*size_of(uintptr) - 8, kind: 5, // Typeid_Kind named: 1, special: 1, // signed, cstring, etc reserved: 1, } +#assert(size_of(Typeid_Bit_Field) == size_of(uintptr)); // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler @@ -678,7 +680,7 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool if p == nil { p = default_assertion_failure_proc; } - p("Runtime assertion", message, loc); + p("runtime assertion", message, loc); }(message, loc); } return condition; @@ -690,7 +692,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! { if p == nil { p = default_assertion_failure_proc; } - p("Panic", message, loc); + p("panic", message, loc); } @builtin @@ -816,8 +818,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { value: V, }; - _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); - header.is_key_string = is_string; + header.is_key_string = intrinsics.type_is_string(K); header.entry_size = int(size_of(Entry)); header.entry_align = int(align_of(Entry)); header.value_offset = uintptr(offset_of(Entry, value)); @@ -828,33 +829,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { __get_map_key :: proc "contextless" (k: $K) -> Map_Key { key := k; map_key: Map_Key; - ti := type_info_base_without_enum(type_info_of(K)); - switch _ in ti.variant { - case Type_Info_Integer: - switch 8*size_of(key) { - case 8: map_key.hash = u64(( ^u8)(&key)^); - case 16: map_key.hash = u64(( ^u16)(&key)^); - case 32: map_key.hash = u64(( ^u32)(&key)^); - case 64: map_key.hash = u64(( ^u64)(&key)^); - case: panic("Unhandled integer size"); - } - case Type_Info_Rune: + + T :: intrinsics.type_core_type(K); + + when intrinsics.type_is_integer(T) { + sz :: 8*size_of(T); + when sz == 8 do map_key.hash = u64(( ^u8)(&key)^); + else when sz == 16 do map_key.hash = u64((^u16)(&key)^); + else when sz == 32 do map_key.hash = u64((^u32)(&key)^); + else when sz == 64 do map_key.hash = u64((^u64)(&key)^); + else do #assert(false, "Unhandled integer size"); + } else when intrinsics.type_is_rune(T) { map_key.hash = u64((^rune)(&key)^); - case Type_Info_Pointer: + } else when intrinsics.type_is_pointer(T) { map_key.hash = u64(uintptr((^rawptr)(&key)^)); - case Type_Info_Float: - switch 8*size_of(key) { - case 32: map_key.hash = u64((^u32)(&key)^); - case 64: map_key.hash = u64((^u64)(&key)^); - case: panic("Unhandled float size"); - } - case Type_Info_String: + } else when intrinsics.type_is_float(T) { + sz :: 8*size_of(T); + when sz == 32 do map_key.hash = u64((^u32)(&key)^); + else when sz == 64 do map_key.hash = u64((^u64)(&key)^); + else do #assert(false, "Unhandled float size"); + } else when intrinsics.type_is_string(T) { + #assert(T == string); str := (^string)(&key)^; map_key.hash = default_hash_string(str); map_key.str = str; - case: - panic("Unhandled map key type"); + } else { + #assert(false, "Unhandled map key type"); } + return map_key; } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index ff861b1de..5ee9ded84 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -28,9 +28,9 @@ when os.OS == "windows" { Answers to common questions about Odin. */ -@(link_name="general_stuff") -general_stuff :: proc() { - fmt.println("# general_stuff"); +@(link_name="extra_general_stuff") +extra_general_stuff :: proc() { + fmt.println("# extra_general_stuff"); { // `do` for inline statements rather than block foo :: proc() do fmt.println("Foo!"); if false do foo(); @@ -209,8 +209,8 @@ union_type :: proc() { } } - Vector3 :: struct {x, y, z: f32}; - Quaternion :: struct {x, y, z, w: f32}; + Vector3 :: distinct [3]f32; + Quaternion :: distinct quaternion128; // More realistic examples { @@ -320,17 +320,17 @@ union_type :: proc() { /* Entity :: struct { - .. + ... derived: union{^Frog, ^Monster}, } Frog :: struct { using entity: Entity, - .. + ... } Monster :: struct { using entity: Entity, - .. + ... } new_entity :: proc(T: type) -> ^Entity { @@ -539,7 +539,7 @@ parametric_polymorphism :: proc() { fmt.println(r); r = 123; fmt.println(r); - r = Error.Foo0; + r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below fmt.println(r); } @@ -1190,7 +1190,7 @@ where_clauses :: proc() { main :: proc() { when true { - general_stuff(); + extra_general_stuff(); union_type(); parametric_polymorphism(); threading_example(); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a0d8221f..7c418c4f0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3071,7 +3071,6 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } if (selector->kind != Ast_Ident) { - // if (selector->kind != Ast_Ident) { error(selector, "Illegal selector kind: '%.*s'", LIT(ast_strings[selector->kind])); operand->mode = Addressing_Invalid; operand->expr = node; @@ -3544,6 +3543,25 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_untyped_bool; operand->mode = Addressing_Constant; + } else if (name == "panic") { + if (ce->args.count != 1) { + error(call, "'#panic' expects 1 argument, got %td", ce->args.count); + return false; + } + if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + operand->type = t_invalid; + operand->mode = Addressing_NoValue; } else if (name == "defined") { if (ce->args.count != 1) { error(call, "'#defined' expects 1 argument, got %td", ce->args.count); @@ -6349,7 +6367,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { ce->proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, ce->proc); String name = bd->name; - if (name == "location" || name == "assert" || name == "defined" || name == "load") { + if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "load") { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; operand->expr = ce->proc; diff --git a/src/check_type.cpp b/src/check_type.cpp index 329755ea5..4d107a9ac 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1847,7 +1847,7 @@ Array systemv_distribute_struct_fields(Type *t) { } auto distributed = array_make(heap_allocator(), 0, distributed_cap); - + i64 sz = type_size_of(bt); switch (bt->kind) { case Type_Basic: switch (bt->Basic.kind){ @@ -1925,9 +1925,9 @@ Array systemv_distribute_struct_fields(Type *t) { array_add(&distributed, t_int); break; + case Type_Union: case Type_DynamicArray: case Type_Map: - case Type_Union: case Type_BitField: // TODO(bill): Ignore? // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet goto DEFAULT; @@ -1937,7 +1937,7 @@ Array systemv_distribute_struct_fields(Type *t) { case Type_SimdVector: // TODO(bill): Is this correct logic? default: DEFAULT:; - if (type_size_of(bt) > 0) { + if (sz > 0) { array_add(&distributed, bt); } break; @@ -1959,13 +1959,22 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool if (types.count == 1) { if (offset) *offset = 1; + + i64 sz = type_size_of(types[0]); + if (is_type_float(types[0])) { return types[0]; - } else if (type_size_of(types[0]) == 8) { + } + switch (sz) { + case 0: + GB_PANIC("Zero sized type found!"); + case 1: + case 2: + case 4: + case 8: return types[0]; - } else { - return t_u64; } + return t_u64; } else if (types.count >= 2) { if (types[0] == t_f32 && types[1] == t_f32) { if (offset) *offset = 2; @@ -2050,7 +2059,7 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { Type *final_type = nullptr; if (field_types.count == 0) { - return t; + final_type = t; } else if (field_types.count == 1) { final_type = field_types[0]; } else { @@ -2072,8 +2081,22 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false); final_type = alloc_type_tuple(); final_type->Tuple.variables = variables; + if (t->kind == Type_Struct) { + // NOTE(bill): Make this packed + final_type->Tuple.is_packed = t->Struct.is_packed; + } } } + + + GB_ASSERT(final_type != nullptr); + i64 ftsz = type_size_of(final_type); + i64 otsz = type_size_of(original_type); + if (ftsz != otsz) { + // TODO(bill): Handle this case which will be caused by #packed most likely + GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %lld vs %lld", ftsz, otsz); + } + return final_type; } } diff --git a/src/checker.cpp b/src/checker.cpp index f30273439..8ce9d8ec2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3367,8 +3367,9 @@ bool collect_file_decls(CheckerContext *ctx, Array const &decls) { if (es->expr->kind == Ast_CallExpr) { ast_node(ce, CallExpr, es->expr); if (ce->proc->kind == Ast_BasicDirective) { - Operand o = {}; - check_expr(ctx, &o, es->expr); + if (ctx->collect_delayed_decls) { + array_add(&ctx->scope->delayed_directives, es->expr); + } } } case_end; @@ -3525,12 +3526,18 @@ void check_import_entities(Checker *c) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; CheckerContext ctx = c->init_ctx; - add_curr_ast_file(&ctx, f); + for_array(j, f->scope->delayed_imports) { Ast *decl = f->scope->delayed_imports[j]; check_add_import_decl(&ctx, decl); } + } + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + CheckerContext ctx = c->init_ctx; + add_curr_ast_file(&ctx, f); + for_array(j, f->scope->delayed_directives) { Ast *expr = f->scope->delayed_directives[j]; Operand o = {}; diff --git a/src/checker.hpp b/src/checker.hpp index 58cb01a82..f86acce5c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -222,6 +222,7 @@ struct ForeignContext { typedef Array CheckerTypePath; typedef Array CheckerPolyPath; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Map untyped; // Key: Ast * | Expression -> ExprInfo diff --git a/src/main.cpp b/src/main.cpp index b294e7f96..78859e04e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -445,7 +445,7 @@ bool parse_build_flags(Array args) { path = substring(path, 0, string_extension_position(path)); } #endif - build_context.out_filepath = path; + build_context.out_filepath = path_to_full_path(heap_allocator(), path); } else { gb_printf_err("Invalid -out path, got %.*s\n", LIT(path)); bad_flags = true; @@ -624,7 +624,7 @@ bool parse_build_flags(Array args) { break; } - if (str == "dll") { + if (str == "dll" || str == "shared") { build_context.is_dll = true; } else if (str == "exe") { build_context.is_dll = false; @@ -1112,7 +1112,7 @@ int main(int arg_count, char **arg_ptr) { if (0) { #ifdef GB_SYSTEM_UNIX } else if (selected_target_metrics->metrics == &target_essence_amd64) { - system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); #endif } else { @@ -1239,10 +1239,7 @@ int main(int arg_count, char **arg_ptr) { // This allows you to specify '-f' in a #foreign_system_library, // without having to implement any new syntax specifically for MacOS. #if defined(GB_SYSTEM_OSX) - if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { - // framework thingie - lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); - } else if (string_ends_with(lib, str_lit(".framework"))) { + if (string_ends_with(lib, str_lit(".framework"))) { // framework thingie String lib_name = lib; lib_name = remove_extension_from_path(lib_name); @@ -1251,8 +1248,7 @@ int main(int arg_count, char **arg_ptr) { // static libs, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); } else if (string_ends_with(lib, str_lit(".dylib"))) { - // dynamic lib, relative path to executable - // lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); + // dynamic lib lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths diff --git a/src/parser.cpp b/src/parser.cpp index 025a181ba..f69efc0ce 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3970,34 +3970,6 @@ Ast *parse_stmt(AstFile *f) { return s; } - // case Token_static: { - // CommentGroup *docs = f->lead_comment; - // Token token = expect_token(f, Token_static); - - // Ast *decl = nullptr; - // Array list = parse_lhs_expr_list(f); - // if (list.count == 0) { - // syntax_error(token, "Illegal use of 'static' statement"); - // expect_semicolon(f, nullptr); - // return ast_bad_stmt(f, token, f->curr_token); - // } - - // expect_token_after(f, Token_Colon, "identifier list"); - // decl = parse_value_decl(f, list, docs); - - // if (decl != nullptr && decl->kind == Ast_ValueDecl) { - // if (decl->ValueDecl.is_mutable) { - // decl->ValueDecl.is_static = true; - // } else { - // error(token, "'static' may only be currently used with variable declaration"); - // } - // return decl; - // } - - // syntax_error(token, "Illegal use of 'static' statement"); - // return ast_bad_stmt(f, token, f->curr_token); - // } break; - case Token_using: { CommentGroup *docs = f->lead_comment; Token token = expect_token(f, Token_using); @@ -4071,12 +4043,10 @@ Ast *parse_stmt(AstFile *f) { } else if (tag == "assert") { Ast *t = ast_basic_directive(f, hash_token, tag); return ast_expr_stmt(f, parse_call_expr(f, t)); - } /* else if (name.string == "no_deferred") { - s = parse_stmt(f); - s->stmt_state_flags |= StmtStateFlag_no_deferred; - } */ - - if (tag == "include") { + } else if (tag == "panic") { + Ast *t = ast_basic_directive(f, hash_token, tag); + return ast_expr_stmt(f, parse_call_expr(f, t)); + } else if (tag == "include") { syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); s = ast_bad_stmt(f, token, f->curr_token); } else { diff --git a/src/types.cpp b/src/types.cpp index d8a579510..8ad352f62 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -113,21 +113,22 @@ struct BasicType { struct TypeStruct { Array fields; Array tags; - Ast *node; - Scope * scope; - - Array offsets; - bool are_offsets_set; - bool are_offsets_being_processed; - bool is_packed; - bool is_raw_union; - bool is_polymorphic; - bool is_poly_specialized; + Array offsets; + Ast * node; + Scope * scope; + Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; - i64 custom_align; // NOTE(bill): Only used in structs at the moment + i64 custom_align; Entity * names; + + bool are_offsets_set; + bool are_offsets_being_processed; + bool is_packed; + bool is_raw_union; + bool is_polymorphic; + bool is_poly_specialized; }; struct TypeUnion { @@ -137,12 +138,11 @@ struct TypeUnion { i64 variant_block_size; i64 custom_align; i64 tag_size; + Type * polymorphic_params; // Type_Tuple + Type * polymorphic_parent; bool no_nil; - - bool is_polymorphic; - bool is_poly_specialized; - Type * polymorphic_params; // Type_Tuple - Type * polymorphic_parent; + bool is_polymorphic; + bool is_poly_specialized; }; #define TYPE_KINDS \ @@ -190,7 +190,9 @@ struct TypeUnion { TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \ Array offsets; \ + bool are_offsets_being_processed; \ bool are_offsets_set; \ + bool is_packed; \ }) \ TYPE_KIND(Proc, struct { \ Ast *node; \ @@ -201,9 +203,8 @@ struct TypeUnion { i32 result_count; \ Array abi_compat_params; \ Type * abi_compat_result_type; \ - bool return_by_pointer; \ - bool variadic; \ i32 variadic_index; \ + bool variadic; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ @@ -211,6 +212,7 @@ struct TypeUnion { bool has_proc_default_values; \ bool has_named_results; \ bool diverging; /* no return */ \ + bool return_by_pointer; \ u64 tags; \ isize specialization_count; \ ProcCallingConvention calling_convention; \ @@ -1782,7 +1784,8 @@ bool are_types_identical(Type *x, Type *y) { case Type_Tuple: if (y->kind == Type_Tuple) { - if (x->Tuple.variables.count == y->Tuple.variables.count) { + if (x->Tuple.variables.count == y->Tuple.variables.count && + x->Tuple.is_packed == y->Tuple.is_packed) { for_array(i, x->Tuple.variables) { Entity *xe = x->Tuple.variables[i]; Entity *ye = y->Tuple.variables[i]; @@ -2231,19 +2234,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty if (type->Array.count <= 4) { // HACK(bill): Memory leak switch (type->Array.count) { - #define _ARRAY_FIELD_CASE(_length, _name) \ - case (_length): \ - if (field_name == _name) { \ + #define _ARRAY_FIELD_CASE_IF(_length, _name) \ + if (field_name == (_name)) { \ selection_add_index(&sel, (_length)-1); \ sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \ return sel; \ - } \ + } + #define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ + case (_length): \ + _ARRAY_FIELD_CASE_IF(_length, _name0); \ + _ARRAY_FIELD_CASE_IF(_length, _name1); \ /*fallthrough*/ - _ARRAY_FIELD_CASE(4, "w"); - _ARRAY_FIELD_CASE(3, "z"); - _ARRAY_FIELD_CASE(2, "y"); - _ARRAY_FIELD_CASE(1, "x"); + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); default: break; #undef _ARRAY_FIELD_CASE @@ -2590,9 +2596,9 @@ bool type_set_offsets(Type *t) { } } else if (is_type_tuple(t)) { if (!t->Tuple.are_offsets_set) { - t->Struct.are_offsets_being_processed = true; - t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false); - t->Struct.are_offsets_being_processed = false; + t->Tuple.are_offsets_being_processed = true; + t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false); + t->Tuple.are_offsets_being_processed = false; t->Tuple.are_offsets_set = true; return true; } -- cgit v1.2.3 From ee8d3e03f89b1f8065fc9563d84830482bc3f387 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 18:25:39 +0000 Subject: Delay determination of procedure abi types until as late as possible to prevent type undetermination in self-referential data types #454 --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 20 ++++++++++++-------- src/ir.cpp | 3 +++ src/ir_print.cpp | 5 +++++ src/types.cpp | 9 +++++++-- 5 files changed, 29 insertions(+), 12 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b5d24e008..51497af7e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -89,7 +89,7 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand * Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); -void set_procedure_abi_types(CheckerContext *c, Type *type); +void set_procedure_abi_types(gbAllocator a, Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); Entity *entity_from_expr(Ast *expr) { @@ -963,7 +963,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, } if (modify_type) { - set_procedure_abi_types(c, source); + set_procedure_abi_types(c->allocator, source); } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index de33cc1a5..45c59f2bc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1273,7 +1273,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) { if (show_error) { - set_procedure_abi_types(ctx, poly_type); + set_procedure_abi_types(ctx->allocator, poly_type); } return poly_type; } @@ -2362,18 +2362,22 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type return false; } -void set_procedure_abi_types(CheckerContext *c, Type *type) { +void set_procedure_abi_types(gbAllocator allocator, Type *type) { type = base_type(type); if (type->kind != Type_Proc) { return; } - type->Proc.abi_compat_params = array_make(c->allocator, cast(isize)type->Proc.param_count); + if (type->Proc.abi_types_set) { + return; + } + + type->Proc.abi_compat_params = array_make(allocator, cast(isize)type->Proc.param_count); for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; - Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention); + Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { case ProcCC_Odin: @@ -2387,8 +2391,10 @@ void set_procedure_abi_types(CheckerContext *c, Type *type) { } // NOTE(bill): The types are the same - type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention); - type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention); + type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + + type->Proc.abi_types_set = true; } // NOTE(bill): 'operands' is for generating non generic procedure type @@ -2486,8 +2492,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, } type->Proc.is_polymorphic = is_polymorphic; - set_procedure_abi_types(c, type); - return success; } diff --git a/src/ir.cpp b/src/ir.cpp index ae60be7e3..d4aecebf0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3038,6 +3038,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar context_ptr = ir_find_or_generate_context_ptr(p); } + set_procedure_abi_types(heap_allocator(), pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -10019,6 +10020,8 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { void ir_build_proc(irValue *value, irProcedure *parent) { irProcedure *proc = &value->Proc; + set_procedure_abi_types(heap_allocator(), proc->type); + proc->parent = parent; if (proc->body != nullptr) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1d0c8af35..d47dfc898 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { + set_procedure_abi_types(heap_allocator(), t); + i64 word_bits = 8*build_context.word_size; t = base_type(t); GB_ASSERT(is_type_proc(t)); isize param_count = t->Proc.param_count; isize result_count = t->Proc.result_count; + ir_print_proc_results(f, m, t); ir_write_string(f, str_lit(" (")); if (t->Proc.return_by_pointer) { @@ -2125,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { + set_procedure_abi_types(heap_allocator(), proc->type); + if (proc->body == nullptr) { ir_write_str_lit(f, "declare "); // if (proc->tags & ProcTag_dll_import) { diff --git a/src/types.cpp b/src/types.cpp index 8ad352f62..bef69ee30 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -205,6 +205,7 @@ struct TypeUnion { Type * abi_compat_result_type; \ i32 variadic_index; \ bool variadic; \ + bool abi_types_set; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ @@ -2360,7 +2361,9 @@ i64 type_size_of(Type *t) { return 0; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_size >= 0) { + if (t->kind == Type_Named && t->cached_size >= 0) { + + } else if (t->kind != Type_Basic && t->cached_size >= 0) { return t->cached_size; } TypePath path = {0}; @@ -2375,7 +2378,9 @@ i64 type_align_of(Type *t) { return 1; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_align > 0) { + if (t->kind == Type_Named && t->cached_align >= 0) { + + } if (t->kind != Type_Basic && t->cached_align > 0) { return t->cached_align; } -- cgit v1.2.3