diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin index 74ade0260..74283720f 100644 --- a/core/builtin/builtin.odin +++ b/core/builtin/builtin.odin @@ -43,6 +43,7 @@ complex32 :: complex32; complex64 :: complex64; complex128 :: complex128; +quaternion64 :: quaternion64; quaternion128 :: quaternion128; quaternion256 :: quaternion256; @@ -76,6 +77,17 @@ u64be :: u64be; i128be :: i128be; u128be :: u128be; + +f16le :: f16le; +f32le :: f32le; +f64le :: f64le; + +f16be :: f16be; +f32be :: f32be; +f64be :: f64be; + + + // Procedures len :: proc(array: Array_Type) -> int --- cap :: proc(array: Array_Type) -> int --- @@ -103,3 +115,6 @@ min :: proc(values: ..T) -> T --- max :: proc(values: ..T) -> T --- abs :: proc(value: T) -> T --- clamp :: proc(value, minimum, maximum: T) -> T --- + +soa_zip :: proc(slices: ...) -> #soa[]Struct --- +soa_unzip :: proc(value: $S/#soa[]$E) -> (slices: ...) --- diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 2c5127139..b3725a916 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -89,6 +89,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { case Type_Info_Float: val: f64; switch f in a { + case f16: val = f64(f); case f32: val = f64(f); case f64: val = f64(f); } diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index a59a7dad0..4716f7954 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -948,6 +948,7 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { u: u64; switch bit_size { + case 16: u = u64(transmute(u16)f16(v)); case 32: u = u64(transmute(u32)f32(v)); case 64: u = transmute(u64)v; case: panic("Unhandled float size"); @@ -2023,12 +2024,15 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case any: fmt_arg(fi, a, verb); case rune: fmt_rune(fi, a, verb); + case f16: fmt_float(fi, f64(a), 16, verb); case f32: fmt_float(fi, f64(a), 32, verb); case f64: fmt_float(fi, a, 64, verb); + case f16le: fmt_float(fi, f64(a), 16, verb); case f32le: fmt_float(fi, f64(a), 32, verb); case f64le: fmt_float(fi, f64(a), 64, verb); + case f16be: fmt_float(fi, f64(a), 16, verb); case f32be: fmt_float(fi, f64(a), 32, verb); case f64be: fmt_float(fi, f64(a), 64, verb); diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index e00dccde9..58f546191 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -431,9 +431,9 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, str } switch digit_count { - case 8, 16: break; + case 4, 8, 16: break; case: - error(t, t.offset, "invalid hexadecimal floating-point number, expected 8 or 16 digits, got %d", digit_count); + error(t, t.offset, "invalid hexadecimal floating-point number, expected 4, 8, or 16 digits, got %d", digit_count); } } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index f9328bdb0..a38a04cb8 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -1,5 +1,7 @@ package runtime +import "intrinsics" + bswap_16 :: proc "none" (x: u16) -> u16 { return x>>8 | x<<8; } @@ -25,6 +27,12 @@ bswap_128 :: proc "none" (x: u128) -> u128 { return transmute(u128)z; } +bswap_f16 :: proc "none" (f: f16) -> f16 { + x := transmute(u16)f; + z := bswap_16(x); + return transmute(f16)z; + +} bswap_f32 :: proc "none" (f: f32) -> f32 { x := transmute(u32)f; @@ -410,6 +418,12 @@ foreign { @(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 --- @(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 --- } +abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 { + foreign { + @(link_name="llvm.fabs.f16") _abs :: proc "none" (x: f16) -> f16 --- + } + return _abs(x); +} abs_f32 :: #force_inline proc "contextless" (x: f32) -> f32 { foreign { @(link_name="llvm.fabs.f32") _abs :: proc "none" (x: f32) -> f32 --- @@ -423,6 +437,12 @@ abs_f64 :: #force_inline proc "contextless" (x: f64) -> f64 { return _abs(x); } +min_f16 :: proc(a, b: f16) -> f16 { + foreign { + @(link_name="llvm.minnum.f16") _min :: proc "none" (a, b: f16) -> f16 --- + } + return _min(a, b); +} min_f32 :: proc(a, b: f32) -> f32 { foreign { @(link_name="llvm.minnum.f32") _min :: proc "none" (a, b: f32) -> f32 --- @@ -435,6 +455,12 @@ min_f64 :: proc(a, b: f64) -> f64 { } return _min(a, b); } +max_f16 :: proc(a, b: f16) -> f16 { + foreign { + @(link_name="llvm.maxnum.f16") _max :: proc "none" (a, b: f16) -> f16 --- + } + return _max(a, b); +} max_f32 :: proc(a, b: f32) -> f32 { foreign { @(link_name="llvm.maxnum.f32") _max :: proc "none" (a, b: f32) -> f32 --- @@ -448,6 +474,10 @@ max_f64 :: proc(a, b: f64) -> f64 { return _max(a, b); } +abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 { + r, i := real(x), imag(x); + return f16(_sqrt_f32(f32(r*r + i*i))); +} abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 { r, i := real(x), imag(x); return _sqrt_f32(r*r + i*i); @@ -456,6 +486,10 @@ abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 { r, i := real(x), imag(x); return _sqrt_f64(r*r + i*i); } +abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return f16(_sqrt_f32(f32(r*r + i*i + j*j + k*k))); +} abs_quaternion128 :: #force_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); @@ -465,6 +499,26 @@ abs_quaternion256 :: #force_inline proc "contextless" (x: quaternion256) -> f64 return _sqrt_f64(r*r + i*i + j*j + k*k); } + +quo_complex32 :: proc "contextless" (n, m: complex32) -> complex32 { + e, f: f16; + + if abs(real(m)) >= abs(imag(m)) { + ratio := imag(m) / real(m); + denom := real(m) + ratio*imag(m); + e = (real(n) + imag(n)*ratio) / denom; + f = (imag(n) - real(n)*ratio) / denom; + } else { + ratio := real(m) / imag(m); + denom := imag(m) + ratio*real(m); + e = (real(n)*ratio + imag(n)) / denom; + f = (imag(n)*ratio - real(n)) / denom; + } + + return complex(e, f); +} + + quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 { e, f: f32; @@ -501,6 +555,18 @@ quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 { return complex(e, f); } +mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { + 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_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); @@ -525,6 +591,20 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { return quaternion(t0, t1, t2, t3); } +quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { + 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_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); @@ -552,3 +632,90 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { return quaternion(t0, t1, t2, t3); } + +@(link_name="__truncsfhf2") +truncsfhf2 :: proc "c" (value: f32) -> u16 { + v: struct #raw_union { i: u32, f: f32 }; + i, s, e, m: i32; + + v.f = value; + i = i32(v.i); + + s = (i >> 16) & 0x00008000; + e = ((i >> 23) & 0x000000ff) - (127 - 15); + m = i & 0x007fffff; + + + if (e <= 0) { + if (e < -10) { + return u16(s); + } + m = (m | 0x00800000) >> u32(1 - e); + + if (m & 0x00001000) != 0 { + m += 0x00002000; + } + + return u16(s | (m >> 13)); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + return u16(s | 0x7c00); /* NOTE(bill): infinity */ + } else { + /* NOTE(bill): NAN */ + m >>= 13; + return u16(s | 0x7c00 | m | i32(m == 0)); + } + } else { + if (m & 0x00001000) != 0 { + m += 0x00002000; + if (m & 0x00800000) != 0 { + m = 0; + e += 1; + } + } + + if (e > 30) { + f := 1e12; + for j := 0; j < 10; j += 1 { + /* NOTE(bill): Cause overflow */ + g := intrinsics.volatile_load(&f); + g *= g; + intrinsics.volatile_store(&f, g); + } + + return u16(s | 0x7c00); + } + + return u16(s | (e << 10) | (m >> 13)); + } +} + + +@(link_name="__truncdfhf2") +truncdfhf2 :: proc "c" (value: f64) -> u16 { + return truncsfhf2(f32(value)); +} + +@(link_name="__gnu_h2f_ieee") +gnu_h2f_ieee :: proc "c" (value: u16) -> f32 { + fp32 :: struct #raw_union { u: u32, f: f32 }; + + v: fp32; + magic, inf_or_nan: fp32; + magic.u = u32((254 - 15) << 23); + inf_or_nan.u = u32((127 + 16) << 23); + + v.u = u32(value & 0x7fff) << 13; + v.f *= magic.f; + if v.f >= inf_or_nan.f { + v.u |= 255 << 23; + } + v.u |= u32(value & 0x8000) << 16; + return v.f; +} + + +@(link_name="__gnu_f2h_ieee") +gnu_f2h_ieee :: proc "c" (value: f32) -> u16 { + return truncsfhf2(value); +} diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin index bc4155c82..e98d1400a 100644 --- a/core/strconv/generic_float.odin +++ b/core/strconv/generic_float.odin @@ -25,6 +25,9 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) bits: u64; flt: ^Float_Info; switch bit_size { + case 16: + bits = u64(transmute(u16)f16(val)); + flt = &_f16_info; case 32: bits = u64(transmute(u32)f32(val)); flt = &_f32_info; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 20540c839..c8f5e6468 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1549,14 +1549,16 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ if (out_value) *out_value = v; switch (type->Basic.kind) { - // case Basic_f16: + case Basic_f16: case Basic_f32: case Basic_f64: return true; + case Basic_f16le: + case Basic_f16be: case Basic_f32le: - case Basic_f64le: case Basic_f32be: + case Basic_f64le: case Basic_f64be: return true; @@ -2775,12 +2777,14 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint if (bt->kind == Type_Basic) switch (bt->Basic.kind) { case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break; + case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; } } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { Type *bt = base_type(x->type); if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; } @@ -4495,6 +4499,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 gb_string_free(s); return false; } + if (is_type_endian_specific(x.type)) { + gbString s = type_to_string(x.type); + error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s); + gb_string_free(s); + return false; + } if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) { f64 r = exact_value_to_float(x.value).value_float; @@ -4507,7 +4517,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 BasicKind kind = core_type(x.type)->Basic.kind; switch (kind) { - // case Basic_f16: operand->type = t_complex32; break; + case Basic_f16: operand->type = t_complex32; break; case Basic_f32: operand->type = t_complex64; break; case Basic_f64: operand->type = t_complex128; break; case Basic_UntypedFloat: operand->type = t_untyped_complex; break; @@ -4586,6 +4596,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 gb_string_free(s); return false; } + if (is_type_endian_specific(x.type)) { + gbString s = type_to_string(x.type); + error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", 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; @@ -4600,6 +4616,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 BasicKind kind = core_type(x.type)->Basic.kind; switch (kind) { + case Basic_f16: operand->type = t_quaternion64; break; 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; @@ -4655,8 +4672,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 BasicKind kind = core_type(x->type)->Basic.kind; switch (kind) { + case Basic_complex32: x->type = t_f16; break; case Basic_complex64: x->type = t_f32; break; case Basic_complex128: x->type = t_f64; break; + case Basic_quaternion64: x->type = t_f16; 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; @@ -4708,6 +4727,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 BasicKind kind = core_type(x->type)->Basic.kind; switch (kind) { + case Basic_quaternion64: x->type = t_f16; 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; diff --git a/src/checker.cpp b/src/checker.cpp index e7271746f..a34e02c07 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1769,6 +1769,10 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("fixdfti"), str_lit("floattidf"), + str_lit("truncsfhf2"), + str_lit("truncdfhf2"), + str_lit("gnu_h2f_ieee"), + str_lit("gnu_f2h_ieee"), str_lit("memset"), str_lit("memcpy"), @@ -1783,6 +1787,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("bswap_64"), str_lit("bswap_128"), + str_lit("bswap_f16"), str_lit("bswap_f32"), str_lit("bswap_f64"), }; diff --git a/src/common.cpp b/src/common.cpp index 2e24c0c43..9786bd41d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -763,7 +763,7 @@ i64 prev_pow2(i64 n) { return n - (n >> 1); } -i16 f32_to_f16(f32 value) { +u16 f32_to_f16(f32 value) { union { u32 i; f32 f; } v; i32 i, s, e, m; @@ -776,20 +776,20 @@ i16 f32_to_f16(f32 value) { if (e <= 0) { - if (e < -10) return cast(i16)s; + if (e < -10) return cast(u16)s; m = (m | 0x00800000) >> (1 - e); if (m & 0x00001000) m += 0x00002000; - return cast(i16)(s | (m >> 13)); + return cast(u16)(s | (m >> 13)); } else if (e == 0xff - (127 - 15)) { if (m == 0) { - return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */ + return cast(u16)(s | 0x7c00); /* NOTE(bill): infinity */ } else { /* NOTE(bill): NAN */ m >>= 13; - return cast(i16)(s | 0x7c00 | m | (m == 0)); + return cast(u16)(s | 0x7c00 | m | (m == 0)); } } else { if (m & 0x00001000) { @@ -807,13 +807,29 @@ i16 f32_to_f16(f32 value) { f *= f; /* NOTE(bill): Cause overflow */ } - return cast(i16)(s | 0x7c00); + return cast(u16)(s | 0x7c00); } - return cast(i16)(s | (e << 10) | (m >> 13)); + return cast(u16)(s | (e << 10) | (m >> 13)); } } +f32 f16_to_f32(u16 value) { + typedef union { u32 u; f32 f; } fp32; + fp32 v; + + fp32 magic = {(254u - 15u) << 23}; + fp32 inf_or_nan = {(127u + 16u) << 23}; + + v.u = (value & 0x7fffu) << 13; + v.f *= magic.f; + if (v.f >= inf_or_nan.f) { + v.u |= 255u << 23; + } + v.u |= (value & 0x8000u) << 16; + return v.f; +} + f64 gb_sqrt(f64 x) { return sqrt(x); } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 326f4d587..12c14b4fa 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -271,7 +271,11 @@ ExactValue exact_value_float_from_string(String string) { } } u64 u = u64_from_string(string); - if (digit_count == 8) { + if (digit_count == 4) { + u16 x = cast(u16)u; + f32 f = f16_to_f32(x); + return exact_value_float(cast(f64)f); + } else if (digit_count == 8) { u32 x = cast(u32)u; f32 f = bit_cast(x); return exact_value_float(cast(f64)f); diff --git a/src/ir.cpp b/src/ir.cpp index 34d4f79c1..9fb06582d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2052,24 +2052,27 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_uintptr: return irDebugBasicEncoding_unsigned; - // case Basic_f16: + case Basic_f16: case Basic_f32: case Basic_f64: + case Basic_f16le: case Basic_f32le: case Basic_f64le: + case Basic_f16be: case Basic_f32be: case Basic_f64be: return irDebugBasicEncoding_float; - // case Basic_complex32: + case Basic_complex32: case Basic_complex64: case Basic_complex128: + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: case Basic_cstring: case Basic_string: case Basic_any: case Basic_rawptr: - case Basic_quaternion128: - case Basic_quaternion256: break; // not a "DIBasicType" } @@ -2549,9 +2552,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (type->kind == Type_Basic) { switch (type->Basic.kind) { // Composite basic types - case Basic_complex64: case Basic_complex128: + case Basic_complex32: case Basic_complex64: case Basic_complex128: return ir_add_debug_info_type_complex(module, type); - case Basic_quaternion128: case Basic_quaternion256: + case Basic_quaternion64: case Basic_quaternion128: case Basic_quaternion256: return ir_add_debug_info_type_quaternion(module, type); case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); @@ -5430,7 +5433,9 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { case 1: result_type = t_typeid; break; } break; - case Basic_complex64: case Basic_complex128: + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: { Type *ft = base_complex_elem_type(t); switch (index) { @@ -5439,7 +5444,9 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; } - case Basic_quaternion128: case Basic_quaternion256: + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: { Type *ft = base_complex_elem_type(t); switch (index) { @@ -5828,6 +5835,7 @@ irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t) { char const *proc_name = nullptr; switch (sz*8) { + case 16: proc_name = "bswap_f16"; break; case 32: proc_name = "bswap_f32"; break; case 64: proc_name = "bswap_f64"; break; } @@ -6272,9 +6280,10 @@ bool ir_is_type_aggregate(Type *t) { case Basic_any: return true; - // case Basic_complex32: + case Basic_complex32: case Basic_complex64: case Basic_complex128: + case Basic_quaternion64: case Basic_quaternion128: case Basic_quaternion256: return true; @@ -7025,6 +7034,7 @@ irValue *ir_emit_min(irProcedure *proc, Type *t, irValue *x, irValue *y) { args[0] = x; args[1] = y; switch (sz) { + case 16: return ir_emit_runtime_call(proc, "min_f16", args); case 32: return ir_emit_runtime_call(proc, "min_f32", args); case 64: return ir_emit_runtime_call(proc, "min_f64", args); } @@ -7043,6 +7053,7 @@ irValue *ir_emit_max(irProcedure *proc, Type *t, irValue *x, irValue *y) { args[0] = x; args[1] = y; switch (sz) { + case 16: return ir_emit_runtime_call(proc, "max_f16", args); case 32: return ir_emit_runtime_call(proc, "max_f32", args); case 64: return ir_emit_runtime_call(proc, "max_f64", args); } @@ -7487,6 +7498,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu auto args = array_make(ir_allocator(), 1); args[0] = x; switch (sz) { + case 64: return ir_emit_runtime_call(proc, "abs_quaternion64", args); case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args); case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args); } @@ -7496,6 +7508,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu auto args = array_make(ir_allocator(), 1); args[0] = x; switch (sz) { + case 32: return ir_emit_runtime_call(proc, "abs_complex32", args); case 64: return ir_emit_runtime_call(proc, "abs_complex64", args); case 128: return ir_emit_runtime_call(proc, "abs_complex128", args); } @@ -7505,6 +7518,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu auto args = array_make(ir_allocator(), 1); args[0] = x; switch (sz) { + case 16: return ir_emit_runtime_call(proc, "abs_f16", args); case 32: return ir_emit_runtime_call(proc, "abs_f32", args); case 64: return ir_emit_runtime_call(proc, "abs_f64", args); } @@ -12162,11 +12176,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info tag = ir_emit_conv(proc, variant_ptr, t_type_info_rune_ptr); break; - // case Basic_f16: + case Basic_f16: case Basic_f32: case Basic_f64: + case Basic_f16le: case Basic_f32le: case Basic_f64le: + case Basic_f16be: case Basic_f32be: case Basic_f64be: { @@ -12185,12 +12201,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info break; - // case Basic_complex32: + case Basic_complex32: case Basic_complex64: case Basic_complex128: tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr); break; + case Basic_quaternion64: case Basic_quaternion128: case Basic_quaternion256: tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1b35247c4..d0c014a27 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -418,21 +418,24 @@ 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_f16le: ir_write_str_lit(f, "half"); return; case Basic_f32le: ir_write_str_lit(f, "float"); return; case Basic_f64le: ir_write_str_lit(f, "double"); return; + case Basic_f16be: ir_write_str_lit(f, "half"); return; case Basic_f32be: ir_write_str_lit(f, "float"); return; case Basic_f64be: ir_write_str_lit(f, "double"); return; - // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); 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_quaternion64: ir_write_str_lit(f, "%..quaternion64"); return; case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return; case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return; @@ -873,6 +876,23 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * } #else switch (type->Basic.kind) { + case Basic_f16: + ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32); + break; + case Basic_f16le: + if (build_context.endian_kind != TargetEndian_Little) { + u_32 = gb_endian_swap32(u_32); + } + ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32); + break; + case Basic_f16be: + if (build_context.endian_kind != TargetEndian_Big) { + u_32 = gb_endian_swap32(u_32); + } + ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32); + break; + + case Basic_f32: ir_fprintf(f, "bitcast (i32 %u to float)", u_32); break; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 5c72c0345..65e3b2c58 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -158,6 +158,8 @@ i64 lb_sizeof(LLVMTypeRef type) { unsigned w = LLVMGetIntTypeWidth(type); return (w + 7)/8; } + case LLVMHalfTypeKind: + return 2; case LLVMFloatTypeKind: return 4; case LLVMDoubleTypeKind: @@ -222,6 +224,8 @@ i64 lb_alignof(LLVMTypeRef type) { unsigned w = LLVMGetIntTypeWidth(type); return gb_clamp((w + 7)/8, 1, build_context.max_align); } + case LLVMHalfTypeKind: + return 2; case LLVMFloatTypeKind: return 4; case LLVMDoubleTypeKind: @@ -584,6 +588,7 @@ namespace lbAbiAmd64SysV { LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { case LLVMIntegerTypeKind: + case LLVMHalfTypeKind: case LLVMFloatTypeKind: case LLVMDoubleTypeKind: case LLVMPointerTypeKind: @@ -799,6 +804,7 @@ namespace lbAbiAmd64SysV { switch (LLVMGetTypeKind(t)) { case LLVMIntegerTypeKind: case LLVMPointerTypeKind: + case LLVMHalfTypeKind: unify(cls, ix + off/8, RegClass_Int); break; case LLVMFloatTypeKind: @@ -842,6 +848,7 @@ namespace lbAbiAmd64SysV { RegClass reg = RegClass_NoClass; switch (elem_kind) { case LLVMIntegerTypeKind: + case LLVMHalfTypeKind: switch (LLVMGetIntTypeWidth(elem)) { case 8: reg = RegClass_SSEInt8; case 16: reg = RegClass_SSEInt16; @@ -934,6 +941,7 @@ namespace lbAbiArm64 { LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { case LLVMIntegerTypeKind: + case LLVMHalfTypeKind: case LLVMFloatTypeKind: case LLVMDoubleTypeKind: case LLVMPointerTypeKind: diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index e8028eece..efa19a3bf 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -961,17 +961,34 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Basic_rune: return LLVMInt32TypeInContext(ctx); - // Basic_f16, + + case Basic_f16: return LLVMHalfTypeInContext(ctx); case Basic_f32: return LLVMFloatTypeInContext(ctx); case Basic_f64: return LLVMDoubleTypeInContext(ctx); + case Basic_f16le: return LLVMHalfTypeInContext(ctx); case Basic_f32le: return LLVMFloatTypeInContext(ctx); case Basic_f64le: return LLVMDoubleTypeInContext(ctx); + case Basic_f16be: return LLVMHalfTypeInContext(ctx); case Basic_f32be: return LLVMFloatTypeInContext(ctx); case Basic_f64be: return LLVMDoubleTypeInContext(ctx); - // Basic_complex32, + case Basic_complex32: + { + char const *name = "..complex32"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[2] = { + lb_type(m, t_f16), + lb_type(m, t_f16), + }; + LLVMStructSetBody(type, fields, 2, false); + return type; + } case Basic_complex64: { char const *name = "..complex64"; @@ -1003,6 +1020,23 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return type; } + case Basic_quaternion64: + { + char const *name = "..quaternion64"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[4] = { + lb_type(m, t_f16), + lb_type(m, t_f16), + lb_type(m, t_f16), + lb_type(m, t_f16), + }; + LLVMStructSetBody(type, fields, 4, false); + return type; + } case Basic_quaternion128: { char const *name = "..quaternion128"; @@ -1622,7 +1656,8 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_rune: return lb_debug_type_basic_type(m, str_lit("rune"), 32, LLVMDWARFTypeEncoding_Utf); - // Basic_f16, + + case Basic_f16: return lb_debug_type_basic_type(m, str_lit("f16"), 16, LLVMDWARFTypeEncoding_Float); case Basic_f32: return lb_debug_type_basic_type(m, str_lit("f32"), 32, LLVMDWARFTypeEncoding_Float); case Basic_f64: return lb_debug_type_basic_type(m, str_lit("f64"), 64, LLVMDWARFTypeEncoding_Float); @@ -1642,6 +1677,8 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_u64le: return lb_debug_type_basic_type(m, str_lit("u64le"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); case Basic_i128le: return lb_debug_type_basic_type(m, str_lit("i128le"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); case Basic_u128le: return lb_debug_type_basic_type(m, str_lit("u128le"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); + + case Basic_f16le: return lb_debug_type_basic_type(m, str_lit("f16le"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); case Basic_f32le: return lb_debug_type_basic_type(m, str_lit("f32le"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); case Basic_f64le: return lb_debug_type_basic_type(m, str_lit("f64le"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); @@ -1653,10 +1690,18 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_u64be: return lb_debug_type_basic_type(m, str_lit("u64be"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); case Basic_i128be: return lb_debug_type_basic_type(m, str_lit("i128be"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); case Basic_u128be: return lb_debug_type_basic_type(m, str_lit("u128be"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); + + case Basic_f16be: return lb_debug_type_basic_type(m, str_lit("f16be"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); case Basic_f32be: return lb_debug_type_basic_type(m, str_lit("f32be"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); case Basic_f64be: return lb_debug_type_basic_type(m, str_lit("f64be"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - // Basic_complex32, + case Basic_complex32: + { + LLVMMetadataRef elements[2] = {}; + elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0); + elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 4); + return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements)); + } case Basic_complex64: { LLVMMetadataRef elements[2] = {}; @@ -1672,6 +1717,15 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { return lb_debug_basic_struct(m, str_lit("complex128"), 128, 64, elements, gb_count_of(elements)); } + case Basic_quaternion64: + { + LLVMMetadataRef elements[4] = {}; + elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0); + elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 4); + elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 8); + elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 12); + return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements)); + } case Basic_quaternion128: { LLVMMetadataRef elements[4] = {}; @@ -5262,6 +5316,17 @@ lbValue lb_const_bool(lbModule *m, Type *type, bool value) { return res; } +LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) { + GB_ASSERT(type_size_of(type) == 2); + + u16 u = f32_to_f16(f); + if (is_type_different_to_arch_endianness(type)) { + u = gb_endian_swap16(u); + } + LLVMValueRef i = LLVMConstInt(LLVMInt16TypeInContext(m->ctx), u, false); + return LLVMConstBitCast(i, lb_type(m, type)); +} + LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) { GB_ASSERT(type_size_of(type) == 4); u32 u = bit_cast(f); @@ -5761,11 +5826,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } return res; case ExactValue_Float: - if (type_size_of(type) == 4) { - f32 f = cast(f32)value.value_float; - res.value = lb_const_f32(m, f, type); - return res; - } if (is_type_different_to_arch_endianness(type)) { u64 u = bit_cast(value.value_float); u = gb_endian_swap64(u); @@ -5778,6 +5838,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc { LLVMValueRef values[2] = {}; switch (8*type_size_of(type)) { + case 32: + values[0] = lb_const_f16(m, cast(f32)value.value_complex->real); + values[1] = lb_const_f16(m, cast(f32)value.value_complex->imag); + break; case 64: values[0] = lb_const_f32(m, cast(f32)value.value_complex->real); values[1] = lb_const_f32(m, cast(f32)value.value_complex->imag); @@ -5796,6 +5860,13 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc { LLVMValueRef values[4] = {}; switch (8*type_size_of(type)) { + case 64: + // @QuaternionLayout + values[3] = lb_const_f16(m, cast(f32)value.value_quaternion->real); + values[0] = lb_const_f16(m, cast(f32)value.value_quaternion->imag); + values[1] = lb_const_f16(m, cast(f32)value.value_quaternion->jmag); + values[2] = lb_const_f16(m, cast(f32)value.value_quaternion->kmag); + break; case 128: // @QuaternionLayout values[3] = lb_const_f32(m, cast(f32)value.value_quaternion->real); @@ -7340,9 +7411,10 @@ bool lb_is_type_aggregate(Type *t) { case Basic_any: return true; - // case Basic_complex32: + case Basic_complex32: case Basic_complex64: case Basic_complex128: + case Basic_quaternion64: case Basic_quaternion128: case Basic_quaternion256: return true; @@ -7663,7 +7735,9 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { case 1: result_type = t_typeid; break; } break; - case Basic_complex64: case Basic_complex128: + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: { Type *ft = base_complex_elem_type(t); switch (index) { @@ -7672,7 +7746,9 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { } break; } - case Basic_quaternion128: case Basic_quaternion256: + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: { Type *ft = base_complex_elem_type(t); switch (index) { @@ -8816,6 +8892,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { + case 64: return lb_emit_runtime_call(p, "abs_quaternion64", args); case 128: return lb_emit_runtime_call(p, "abs_quaternion128", args); case 256: return lb_emit_runtime_call(p, "abs_quaternion256", args); } @@ -8825,6 +8902,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { + case 32: return lb_emit_runtime_call(p, "abs_complex32", args); case 64: return lb_emit_runtime_call(p, "abs_complex64", args); case 128: return lb_emit_runtime_call(p, "abs_complex128", args); } @@ -8834,6 +8912,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { + case 16: return lb_emit_runtime_call(p, "abs_f16", args); case 32: return lb_emit_runtime_call(p, "abs_f32", args); case 64: return lb_emit_runtime_call(p, "abs_f64", args); } @@ -9566,6 +9645,7 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { if (is_type_float(platform_type)) { String name = {}; switch (sz) { + case 2: name = str_lit("bswap_f16"); break; case 4: name = str_lit("bswap_f32"); break; case 8: name = str_lit("bswap_f64"); break; default: GB_PANIC("unhandled byteswap size"); break; @@ -12678,11 +12758,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_rune_ptr); break; - // case Basic_f16: + case Basic_f16: case Basic_f32: case Basic_f64: + case Basic_f16le: case Basic_f32le: case Basic_f64le: + case Basic_f16be: case Basic_f32be: case Basic_f64be: { @@ -12708,12 +12790,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } break; - // case Basic_complex32: + case Basic_complex32: case Basic_complex64: case Basic_complex128: tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_complex_ptr); break; + case Basic_quaternion64: case Basic_quaternion128: case Basic_quaternion256: tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_quaternion_ptr); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f09cfa9a7..509bcb9cd 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -865,11 +865,12 @@ void scan_number_to_token(Tokenizer *t, Token *token, bool seen_decimal_point) { } } switch (digit_count) { + case 4: case 8: case 16: break; default: - tokenizer_err(t, "Invalid hexadecimal float, expected 8 or 16 digits, got %td", digit_count); + tokenizer_err(t, "Invalid hexadecimal float, expected 4, 8, or 16 digits, got %td", digit_count); break; } } diff --git a/src/types.cpp b/src/types.cpp index 00cb0b6d9..87846222c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -25,14 +25,15 @@ enum BasicKind { Basic_rune, - // Basic_f16, + Basic_f16, Basic_f32, Basic_f64, - // Basic_complex32, + Basic_complex32, Basic_complex64, Basic_complex128, + Basic_quaternion64, Basic_quaternion128, Basic_quaternion256, @@ -65,9 +66,11 @@ enum BasicKind { Basic_i128be, Basic_u128be, + Basic_f16le, Basic_f32le, Basic_f64le, + Basic_f16be, Basic_f32be, Basic_f64be, @@ -463,14 +466,15 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_rune, BasicFlag_Integer | BasicFlag_Rune, 4, STR_LIT("rune")}}, - // {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}}, + {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}}, {Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}}, {Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}}, - // {Type_Basic, {Basic_complex32, BasicFlag_Complex, 4, STR_LIT("complex32")}}, + {Type_Basic, {Basic_complex32, BasicFlag_Complex, 4, STR_LIT("complex32")}}, {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, + {Type_Basic, {Basic_quaternion64, BasicFlag_Quaternion, 8, STR_LIT("quaternion64")}}, {Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}}, {Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}}, @@ -504,9 +508,11 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_i128be, BasicFlag_Integer | BasicFlag_EndianBig, 16, STR_LIT("i128be")}}, {Type_Basic, {Basic_u128be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 16, STR_LIT("u128be")}}, + {Type_Basic, {Basic_f16le, BasicFlag_Float | BasicFlag_EndianLittle, 2, STR_LIT("f16le")}}, {Type_Basic, {Basic_f32le, BasicFlag_Float | BasicFlag_EndianLittle, 4, STR_LIT("f32le")}}, {Type_Basic, {Basic_f64le, BasicFlag_Float | BasicFlag_EndianLittle, 8, STR_LIT("f64le")}}, + {Type_Basic, {Basic_f16be, BasicFlag_Float | BasicFlag_EndianBig, 2, STR_LIT("f16be")}}, {Type_Basic, {Basic_f32be, BasicFlag_Float | BasicFlag_EndianBig, 4, STR_LIT("f32be")}}, {Type_Basic, {Basic_f64be, BasicFlag_Float | BasicFlag_EndianBig, 8, STR_LIT("f64be")}}, @@ -543,14 +549,15 @@ gb_global Type *t_u128 = &basic_types[Basic_u128]; gb_global Type *t_rune = &basic_types[Basic_rune]; -// gb_global Type *t_f16 = &basic_types[Basic_f16]; +gb_global Type *t_f16 = &basic_types[Basic_f16]; gb_global Type *t_f32 = &basic_types[Basic_f32]; gb_global Type *t_f64 = &basic_types[Basic_f64]; -// gb_global Type *t_complex32 = &basic_types[Basic_complex32]; +gb_global Type *t_complex32 = &basic_types[Basic_complex32]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; +gb_global Type *t_quaternion64 = &basic_types[Basic_quaternion64]; gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128]; gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256]; @@ -1127,6 +1134,13 @@ bool is_type_quaternion(Type *t) { } return false; } +bool is_type_f16(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + return t->Basic.kind == Basic_f16; + } + return false; +} bool is_type_f32(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1265,7 +1279,7 @@ Type *core_array_type(Type *t) { for (;;) { Type *prev = t; t = base_array_type(t); - if (t->kind != Type_Array && t->kind != Type_SimdVector) { + if (t->kind != Type_Array && t->kind != Type_EnumeratedArray && t->kind != Type_SimdVector) { break; } } @@ -1278,9 +1292,10 @@ Type *base_complex_elem_type(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { switch (t->Basic.kind) { - // case Basic_complex32: return t_f16; + case Basic_complex32: return t_f16; case Basic_complex64: return t_f32; case Basic_complex128: return t_f64; + case Basic_quaternion64: return t_f16; case Basic_quaternion128: return t_f32; case Basic_quaternion256: return t_f64; case Basic_UntypedComplex: return t_untyped_float; @@ -1392,7 +1407,43 @@ bool is_type_endian_little(Type *t) { bool types_have_same_internal_endian(Type *a, Type *b) { return is_type_endian_little(a) == is_type_endian_little(b); } +bool is_type_endian_specific(Type *t) { + t = core_type(t); + if (t->kind == Type_BitSet) { + t = bit_set_to_int(t); + } + if (t->kind == Type_Basic) { + switch (t->Basic.kind) { + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_u128le: + return true; + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_u128be: + return true; + + case Basic_f16le: + case Basic_f16be: + case Basic_f32le: + case Basic_f32be: + case Basic_f64le: + case Basic_f64be: + return true; + } + } + + return false; +} bool is_type_dereferenceable(Type *t) { if (is_type_rawptr(t)) { @@ -1428,6 +1479,7 @@ Type *integer_endian_type_to_platform_type(Type *t) { case Basic_u32le: return t_u32; case Basic_i64le: return t_i64; case Basic_u64le: return t_u64; + case Basic_u128le: return t_u128; case Basic_i16be: return t_i16; case Basic_u16be: return t_u16; @@ -1435,7 +1487,10 @@ Type *integer_endian_type_to_platform_type(Type *t) { case Basic_u32be: return t_u32; case Basic_i64be: return t_i64; case Basic_u64be: return t_u64; + case Basic_u128be: return t_u128; + case Basic_f16le: return t_f16; + case Basic_f16be: return t_f16; case Basic_f32le: return t_f32; case Basic_f32be: return t_f32; case Basic_f64le: return t_f64; @@ -1484,31 +1539,6 @@ bool is_type_valid_for_keys(Type *t) { return false; } return is_type_comparable(t); -#if 0 - if (is_type_integer(t)) { - return true; - } - if (is_type_float(t)) { - return true; - } - if (is_type_string(t)) { - return true; - } - if (is_type_pointer(t)) { - return true; - } - if (is_type_typeid(t)) { - return true; - } - if (is_type_simple_compare(t)) { - return true; - } - if (is_type_comparable(t)) { - return true; - } - - return false; -#endif } bool is_type_valid_bit_set_elem(Type *t) { @@ -2493,6 +2523,35 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty #endif } break; + case Basic_quaternion64: { + // @QuaternionLayout + gb_local_persist String w = str_lit("w"); + gb_local_persist String x = str_lit("x"); + gb_local_persist String y = str_lit("y"); + gb_local_persist String z = str_lit("z"); + gb_local_persist Entity *entity__w = alloc_entity_field(nullptr, make_token_ident(w), t_f32, false, 3); + gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f32, false, 0); + gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f32, false, 1); + gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f32, false, 2); + if (field_name == w) { + selection_add_index(&sel, 3); + sel.entity = entity__w; + return sel; + } else if (field_name == x) { + selection_add_index(&sel, 0); + sel.entity = entity__x; + return sel; + } else if (field_name == y) { + selection_add_index(&sel, 1); + sel.entity = entity__y; + return sel; + } else if (field_name == z) { + selection_add_index(&sel, 2); + sel.entity = entity__z; + return sel; + } + } break; + case Basic_quaternion128: { // @QuaternionLayout gb_local_persist String w = str_lit("w");