aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-04-01 10:06:00 +0100
committergingerBill <bill@gingerbill.org>2021-04-01 10:06:00 +0100
commit54e6c507698bf68b040400783f05686cacaddff1 (patch)
treeebe699d8a059f4e76e0a99494823d4cc3e3bcc1d /src
parenta00d7cc705668da8a8b1a6ebd52668b5e9087bb9 (diff)
Implement `f16` functionality
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp26
-rw-r--r--src/checker.cpp5
-rw-r--r--src/common.cpp30
-rw-r--r--src/exact_value.cpp6
-rw-r--r--src/ir.cpp39
-rw-r--r--src/ir_print.cpp28
-rw-r--r--src/llvm_abi.cpp8
-rw-r--r--src/llvm_backend.cpp111
-rw-r--r--src/tokenizer.cpp3
-rw-r--r--src/types.cpp125
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");