mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-05 10:14:05 +00:00
Implement f16 functionality
This commit is contained in:
@@ -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: ...) ---
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"),
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
39
src/ir.cpp
39
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
125
src/types.cpp
125
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");
|
||||
|
||||
Reference in New Issue
Block a user