diff options
| author | gingerBill <bill@gingerbill.org> | 2021-04-01 10:06:00 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-04-01 10:06:00 +0100 |
| commit | 54e6c507698bf68b040400783f05686cacaddff1 (patch) | |
| tree | ebe699d8a059f4e76e0a99494823d4cc3e3bcc1d /src | |
| parent | a00d7cc705668da8a8b1a6ebd52668b5e9087bb9 (diff) | |
Implement `f16` functionality
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.cpp | 26 | ||||
| -rw-r--r-- | src/checker.cpp | 5 | ||||
| -rw-r--r-- | src/common.cpp | 30 | ||||
| -rw-r--r-- | src/exact_value.cpp | 6 | ||||
| -rw-r--r-- | src/ir.cpp | 39 | ||||
| -rw-r--r-- | src/ir_print.cpp | 28 | ||||
| -rw-r--r-- | src/llvm_abi.cpp | 8 | ||||
| -rw-r--r-- | src/llvm_backend.cpp | 111 | ||||
| -rw-r--r-- | src/tokenizer.cpp | 3 | ||||
| -rw-r--r-- | src/types.cpp | 125 |
10 files changed, 307 insertions, 74 deletions
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<f32>(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<irValue *>(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<irValue *>(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<irValue *>(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<u32>(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<u64>(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<lbValue>(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<lbValue>(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<lbValue>(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"); |