authorgravatar for info@bnoordhuis.nlBen Noordhuis <info@bnoordhuis.nl> 2018-06-27 16:20:04+02:00
committergravatar for info@bnoordhuis.nlBen Noordhuis <info@bnoordhuis.nl> 2018-06-27 16:20:04+02:00
logfd75e73ee9818f12fd81d8fdb3cb949c492d664a
tree84ee56a2ef7a65a0bbb3a7dd12f015970b4ed725
parent1f45075a0e1d86fa110011f6cedbef61a9f6f056

add f16 type

Add support for half-precision floating point operations. Introduce `__extendhfsf2` and `__truncsfhf2` in std/special/compiler_rt. Add `__gnu_h2f_ieee` and `__gnu_f2h_ieee` as aliases that are used in Windows builds. The logic in std/special/compiler_rt/extendXfYf2.zig has been reworked and can now operate on 16 bits floating point types. `extendXfYf2()` and `truncXfYf2()` are marked `inline` to work around a not entirely understood stack alignment issue on Windows when calling the f16 versions of the builtins. closes #1122

16 files changed, 505 insertions(+), 35 deletions(-)

CMakeLists.txt+16
......@@ -261,12 +261,15 @@ endif()
261261set(EMBEDDED_SOFTFLOAT_SOURCES
262262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"
263263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"
264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c"
264265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"
265266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"
266267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"
268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c"
267269 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"
268270 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"
269271 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"
272 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c"
270273 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"
271274 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"
272275 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c"
......@@ -293,8 +296,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
293296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"
294297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"
295298 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c"
299 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c"
300 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c"
301 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c"
302 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c"
303 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c"
304 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c"
305 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c"
306 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c"
307 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c"
308 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c"
309 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c"
296310 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"
297311 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"
312 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c"
298313 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c"
299314 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"
300315 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"
......@@ -572,6 +587,7 @@ set(ZIG_STD_FILES
572587 "special/compiler_rt/floatuntidf.zig"
573588 "special/compiler_rt/muloti4.zig"
574589 "special/compiler_rt/index.zig"
590 "special/compiler_rt/truncXfYf2.zig"
575591 "special/compiler_rt/udivmod.zig"
576592 "special/compiler_rt/udivmoddi4.zig"
577593 "special/compiler_rt/udivmodti4.zig"
src/all_types.hpp+2
......@@ -258,6 +258,7 @@ struct ConstExprValue {
258258 // populated if special == ConstValSpecialStatic
259259 BigInt x_bigint;
260260 BigFloat x_bigfloat;
261 float16_t x_f16;
261262 float x_f32;
262263 double x_f64;
263264 float128_t x_f128;
......@@ -1598,6 +1599,7 @@ struct CodeGen {
15981599 TypeTableEntry *entry_i128;
15991600 TypeTableEntry *entry_isize;
16001601 TypeTableEntry *entry_usize;
1602 TypeTableEntry *entry_f16;
16011603 TypeTableEntry *entry_f32;
16021604 TypeTableEntry *entry_f64;
16031605 TypeTableEntry *entry_f128;
src/analyze.cpp+15
......@@ -4668,6 +4668,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
46684668 }
46694669 case TypeTableEntryIdFloat:
46704670 switch (const_val->type->data.floating.bit_count) {
4671 case 16:
4672 {
4673 uint16_t result;
4674 static_assert(sizeof(result) == sizeof(const_val->data.x_f16), "");
4675 memcpy(&result, &const_val->data.x_f16, sizeof(result));
4676 return result * 65537u;
4677 }
46714678 case 32:
46724679 {
46734680 uint32_t result;
......@@ -5128,6 +5135,9 @@ void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double va
51285135 bigfloat_init_64(&const_val->data.x_bigfloat, value);
51295136 } else if (type->id == TypeTableEntryIdFloat) {
51305137 switch (type->data.floating.bit_count) {
5138 case 16:
5139 const_val->data.x_f16 = zig_double_to_f16(value);
5140 break;
51315141 case 32:
51325142 const_val->data.x_f32 = value;
51335143 break;
......@@ -5441,6 +5451,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
54415451 case TypeTableEntryIdFloat:
54425452 assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count);
54435453 switch (a->type->data.floating.bit_count) {
5454 case 16:
5455 return f16_eq(a->data.x_f16, b->data.x_f16);
54445456 case 32:
54455457 return a->data.x_f32 == b->data.x_f32;
54465458 case 64:
......@@ -5614,6 +5626,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
56145626 return;
56155627 case TypeTableEntryIdFloat:
56165628 switch (type_entry->data.floating.bit_count) {
5629 case 16:
5630 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
5631 return;
56175632 case 32:
56185633 buf_appendf(buf, "%f", const_val->data.x_f32);
56195634 return;
src/bigfloat.cpp+8
......@@ -18,6 +18,10 @@ void bigfloat_init_128(BigFloat *dest, float128_t x) {
1818 dest->value = x;
1919}
2020
21void bigfloat_init_16(BigFloat *dest, float16_t x) {
22 f16_to_f128M(x, &dest->value);
23}
24
2125void bigfloat_init_32(BigFloat *dest, float x) {
2226 float32_t f32_val;
2327 memcpy(&f32_val, &x, sizeof(float));
......@@ -146,6 +150,10 @@ Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
146150 }
147151}
148152
153float16_t bigfloat_to_f16(const BigFloat *bigfloat) {
154 return f128M_to_f16(&bigfloat->value);
155}
156
149157float bigfloat_to_f32(const BigFloat *bigfloat) {
150158 float32_t f32_value = f128M_to_f32(&bigfloat->value);
151159 float result;
src/bigfloat.hpp+2
......@@ -22,6 +22,7 @@ struct BigFloat {
2222
2323struct Buf;
2424
25void bigfloat_init_16(BigFloat *dest, float16_t x);
2526void bigfloat_init_32(BigFloat *dest, float x);
2627void bigfloat_init_64(BigFloat *dest, double x);
2728void bigfloat_init_128(BigFloat *dest, float128_t x);
......@@ -29,6 +30,7 @@ void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
2930void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
3031int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
3132
33float16_t bigfloat_to_f16(const BigFloat *bigfloat);
3234float bigfloat_to_f32(const BigFloat *bigfloat);
3335double bigfloat_to_f64(const BigFloat *bigfloat);
3436float128_t bigfloat_to_f128(const BigFloat *bigfloat);
src/codegen.cpp+4
......@@ -17,6 +17,7 @@
1717#include "os.hpp"
1818#include "translate_c.hpp"
1919#include "target.hpp"
20#include "util.hpp"
2021#include "zig_llvm.h"
2122
2223#include <stdio.h>
......@@ -5211,6 +5212,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
52115212 const_val->data.x_err_set->value, false);
52125213 case TypeTableEntryIdFloat:
52135214 switch (type_entry->data.floating.bit_count) {
5215 case 16:
5216 return LLVMConstReal(type_entry->type_ref, zig_f16_to_double(const_val->data.x_f16));
52145217 case 32:
52155218 return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
52165219 case 64:
......@@ -6195,6 +6198,7 @@ static void define_builtin_types(CodeGen *g) {
61956198 *field = entry;
61966199 g->primitive_type_table.put(&entry->name, entry);
61976200 };
6201 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
61986202 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
61996203 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
62006204 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
src/ir.cpp+149-2
......@@ -11,9 +11,10 @@
1111#include "ir.hpp"
1212#include "ir_print.hpp"
1313#include "os.hpp"
14#include "translate_c.hpp"
1514#include "range_set.hpp"
1615#include "softfloat.hpp"
16#include "translate_c.hpp"
17#include "util.hpp"
1718
1819struct IrExecContext {
1920 ConstExprValue *mem_slot_list;
......@@ -7238,6 +7239,11 @@ static bool float_has_fraction(ConstExprValue *const_val) {
72387239 return bigfloat_has_fraction(&const_val->data.x_bigfloat);
72397240 } else if (const_val->type->id == TypeTableEntryIdFloat) {
72407241 switch (const_val->type->data.floating.bit_count) {
7242 case 16:
7243 {
7244 float16_t floored = f16_roundToInt(const_val->data.x_f16, softfloat_round_minMag, false);
7245 return !f16_eq(floored, const_val->data.x_f16);
7246 }
72417247 case 32:
72427248 return floorf(const_val->data.x_f32) != const_val->data.x_f32;
72437249 case 64:
......@@ -7261,6 +7267,9 @@ static void float_append_buf(Buf *buf, ConstExprValue *const_val) {
72617267 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);
72627268 } else if (const_val->type->id == TypeTableEntryIdFloat) {
72637269 switch (const_val->type->data.floating.bit_count) {
7270 case 16:
7271 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
7272 break;
72647273 case 32:
72657274 buf_appendf(buf, "%f", const_val->data.x_f32);
72667275 break;
......@@ -7296,6 +7305,17 @@ static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {
72967305 bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat);
72977306 } else if (const_val->type->id == TypeTableEntryIdFloat) {
72987307 switch (const_val->type->data.floating.bit_count) {
7308 case 16:
7309 {
7310 double x = zig_f16_to_double(const_val->data.x_f16);
7311 if (x >= 0) {
7312 bigint_init_unsigned(bigint, (uint64_t)x);
7313 } else {
7314 bigint_init_unsigned(bigint, (uint64_t)-x);
7315 bigint->is_negative = true;
7316 }
7317 break;
7318 }
72997319 case 32:
73007320 if (const_val->data.x_f32 >= 0) {
73017321 bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32));
......@@ -7332,6 +7352,9 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
73327352 bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat);
73337353 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
73347354 switch (dest_val->type->data.floating.bit_count) {
7355 case 16:
7356 dest_val->data.x_f16 = bigfloat_to_f16(bigfloat);
7357 break;
73357358 case 32:
73367359 dest_val->data.x_f32 = bigfloat_to_f32(bigfloat);
73377360 break;
......@@ -7349,11 +7372,39 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
73497372 }
73507373}
73517374
7375static void float_init_f16(ConstExprValue *dest_val, float16_t x) {
7376 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
7377 bigfloat_init_16(&dest_val->data.x_bigfloat, x);
7378 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7379 switch (dest_val->type->data.floating.bit_count) {
7380 case 16:
7381 dest_val->data.x_f16 = x;
7382 break;
7383 case 32:
7384 dest_val->data.x_f32 = zig_f16_to_double(x);
7385 break;
7386 case 64:
7387 dest_val->data.x_f64 = zig_f16_to_double(x);
7388 break;
7389 case 128:
7390 f16_to_f128M(x, &dest_val->data.x_f128);
7391 break;
7392 default:
7393 zig_unreachable();
7394 }
7395 } else {
7396 zig_unreachable();
7397 }
7398}
7399
73527400static void float_init_f32(ConstExprValue *dest_val, float x) {
73537401 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
73547402 bigfloat_init_32(&dest_val->data.x_bigfloat, x);
73557403 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
73567404 switch (dest_val->type->data.floating.bit_count) {
7405 case 16:
7406 dest_val->data.x_f16 = zig_double_to_f16(x);
7407 break;
73577408 case 32:
73587409 dest_val->data.x_f32 = x;
73597410 break;
......@@ -7380,6 +7431,9 @@ static void float_init_f64(ConstExprValue *dest_val, double x) {
73807431 bigfloat_init_64(&dest_val->data.x_bigfloat, x);
73817432 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
73827433 switch (dest_val->type->data.floating.bit_count) {
7434 case 16:
7435 dest_val->data.x_f16 = zig_double_to_f16(x);
7436 break;
73837437 case 32:
73847438 dest_val->data.x_f32 = x;
73857439 break;
......@@ -7406,6 +7460,9 @@ static void float_init_f128(ConstExprValue *dest_val, float128_t x) {
74067460 bigfloat_init_128(&dest_val->data.x_bigfloat, x);
74077461 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
74087462 switch (dest_val->type->data.floating.bit_count) {
7463 case 16:
7464 dest_val->data.x_f16 = f128M_to_f16(&x);
7465 break;
74097466 case 32:
74107467 {
74117468 float32_t f32_val = f128M_to_f32(&x);
......@@ -7436,6 +7493,9 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)
74367493 float_init_bigfloat(dest_val, &src_val->data.x_bigfloat);
74377494 } else if (src_val->type->id == TypeTableEntryIdFloat) {
74387495 switch (src_val->type->data.floating.bit_count) {
7496 case 16:
7497 float_init_f16(dest_val, src_val->data.x_f16);
7498 break;
74397499 case 32:
74407500 float_init_f32(dest_val, src_val->data.x_f32);
74417501 break;
......@@ -7459,6 +7519,14 @@ static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
74597519 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);
74607520 } else if (op1->type->id == TypeTableEntryIdFloat) {
74617521 switch (op1->type->data.floating.bit_count) {
7522 case 16:
7523 if (f16_lt(op1->data.x_f16, op2->data.x_f16)) {
7524 return CmpLT;
7525 } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) {
7526 return CmpGT;
7527 } else {
7528 return CmpEQ;
7529 }
74627530 case 32:
74637531 if (op1->data.x_f32 > op2->data.x_f32) {
74647532 return CmpGT;
......@@ -7496,6 +7564,17 @@ static Cmp float_cmp_zero(ConstExprValue *op) {
74967564 return bigfloat_cmp_zero(&op->data.x_bigfloat);
74977565 } else if (op->type->id == TypeTableEntryIdFloat) {
74987566 switch (op->type->data.floating.bit_count) {
7567 case 16:
7568 {
7569 const float16_t zero = zig_double_to_f16(0);
7570 if (f16_lt(op->data.x_f16, zero)) {
7571 return CmpLT;
7572 } else if (f16_lt(zero, op->data.x_f16)) {
7573 return CmpGT;
7574 } else {
7575 return CmpEQ;
7576 }
7577 }
74997578 case 32:
75007579 if (op->data.x_f32 < 0.0) {
75017580 return CmpLT;
......@@ -7537,6 +7616,9 @@ static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75377616 bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
75387617 } else if (op1->type->id == TypeTableEntryIdFloat) {
75397618 switch (op1->type->data.floating.bit_count) {
7619 case 16:
7620 out_val->data.x_f16 = f16_add(op1->data.x_f16, op2->data.x_f16);
7621 return;
75407622 case 32:
75417623 out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32;
75427624 return;
......@@ -7561,6 +7643,9 @@ static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75617643 bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
75627644 } else if (op1->type->id == TypeTableEntryIdFloat) {
75637645 switch (op1->type->data.floating.bit_count) {
7646 case 16:
7647 out_val->data.x_f16 = f16_sub(op1->data.x_f16, op2->data.x_f16);
7648 return;
75647649 case 32:
75657650 out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32;
75667651 return;
......@@ -7585,6 +7670,9 @@ static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75857670 bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
75867671 } else if (op1->type->id == TypeTableEntryIdFloat) {
75877672 switch (op1->type->data.floating.bit_count) {
7673 case 16:
7674 out_val->data.x_f16 = f16_mul(op1->data.x_f16, op2->data.x_f16);
7675 return;
75887676 case 32:
75897677 out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32;
75907678 return;
......@@ -7609,6 +7697,9 @@ static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
76097697 bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
76107698 } else if (op1->type->id == TypeTableEntryIdFloat) {
76117699 switch (op1->type->data.floating.bit_count) {
7700 case 16:
7701 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
7702 return;
76127703 case 32:
76137704 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
76147705 return;
......@@ -7633,6 +7724,19 @@ static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstE
76337724 bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
76347725 } else if (op1->type->id == TypeTableEntryIdFloat) {
76357726 switch (op1->type->data.floating.bit_count) {
7727 case 16:
7728 {
7729 double a = zig_f16_to_double(op1->data.x_f16);
7730 double b = zig_f16_to_double(op2->data.x_f16);
7731 double c = a / b;
7732 if (c >= 0.0) {
7733 c = floor(c);
7734 } else {
7735 c = ceil(c);
7736 }
7737 out_val->data.x_f16 = zig_double_to_f16(c);
7738 return;
7739 }
76367740 case 32:
76377741 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
76387742 if (out_val->data.x_f32 >= 0.0) {
......@@ -7668,6 +7772,10 @@ static void float_div_floor(ConstExprValue *out_val, ConstExprValue *op1, ConstE
76687772 bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
76697773 } else if (op1->type->id == TypeTableEntryIdFloat) {
76707774 switch (op1->type->data.floating.bit_count) {
7775 case 16:
7776 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
7777 out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_min, false);
7778 return;
76717779 case 32:
76727780 out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32);
76737781 return;
......@@ -7693,6 +7801,9 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
76937801 bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
76947802 } else if (op1->type->id == TypeTableEntryIdFloat) {
76957803 switch (op1->type->data.floating.bit_count) {
7804 case 16:
7805 out_val->data.x_f16 = f16_rem(op1->data.x_f16, op2->data.x_f16);
7806 return;
76967807 case 32:
76977808 out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32);
76987809 return;
......@@ -7710,6 +7821,16 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
77107821 }
77117822}
77127823
7824// c = a - b * trunc(a / b)
7825static float16_t zig_f16_mod(float16_t a, float16_t b) {
7826 float16_t c;
7827 c = f16_div(a, b);
7828 c = f16_roundToInt(c, softfloat_round_min, true);
7829 c = f16_mul(b, c);
7830 c = f16_sub(a, c);
7831 return c;
7832}
7833
77137834// c = a - b * trunc(a / b)
77147835static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* c) {
77157836 f128M_div(a, b, c);
......@@ -7725,6 +7846,9 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
77257846 bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
77267847 } else if (op1->type->id == TypeTableEntryIdFloat) {
77277848 switch (op1->type->data.floating.bit_count) {
7849 case 16:
7850 out_val->data.x_f16 = zig_f16_mod(op1->data.x_f16, op2->data.x_f16);
7851 return;
77287852 case 32:
77297853 out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32);
77307854 return;
......@@ -7748,6 +7872,12 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
77487872 bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat);
77497873 } else if (op->type->id == TypeTableEntryIdFloat) {
77507874 switch (op->type->data.floating.bit_count) {
7875 case 16:
7876 {
7877 const float16_t zero = zig_double_to_f16(0);
7878 out_val->data.x_f16 = f16_sub(zero, op->data.x_f16);
7879 return;
7880 }
77517881 case 32:
77527882 out_val->data.x_f32 = -op->data.x_f32;
77537883 return;
......@@ -7770,6 +7900,9 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
77707900void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
77717901 if (op->type->id == TypeTableEntryIdFloat) {
77727902 switch (op->type->data.floating.bit_count) {
7903 case 16:
7904 memcpy(buf, &op->data.x_f16, 2); // TODO wrong when compiler is big endian
7905 return;
77737906 case 32:
77747907 memcpy(buf, &op->data.x_f32, 4); // TODO wrong when compiler is big endian
77757908 return;
......@@ -7790,6 +7923,9 @@ void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
77907923void float_read_ieee597(ConstExprValue *val, uint8_t *buf, bool is_big_endian) {
77917924 if (val->type->id == TypeTableEntryIdFloat) {
77927925 switch (val->type->data.floating.bit_count) {
7926 case 16:
7927 memcpy(&val->data.x_f16, buf, 2); // TODO wrong when compiler is big endian
7928 return;
77937929 case 32:
77947930 memcpy(&val->data.x_f32, buf, 4); // TODO wrong when compiler is big endian
77957931 return;
......@@ -8817,6 +8953,9 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
88178953 if (other_val->type->id == TypeTableEntryIdComptimeFloat) {
88188954 assert(new_type->id == TypeTableEntryIdFloat);
88198955 switch (new_type->data.floating.bit_count) {
8956 case 16:
8957 const_val->data.x_f16 = bigfloat_to_f16(&other_val->data.x_bigfloat);
8958 break;
88208959 case 32:
88218960 const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat);
88228961 break;
......@@ -8847,6 +8986,9 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
88478986 BigFloat bigfloat;
88488987 bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);
88498988 switch (new_type->data.floating.bit_count) {
8989 case 16:
8990 const_val->data.x_f16 = bigfloat_to_f16(&bigfloat);
8991 break;
88508992 case 32:
88518993 const_val->data.x_f32 = bigfloat_to_f32(&bigfloat);
88528994 break;
......@@ -20104,6 +20246,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
2010420246 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
2010520247 } else if (float_type->id == TypeTableEntryIdFloat) {
2010620248 switch (float_type->data.floating.bit_count) {
20249 case 16:
20250 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);
20251 break;
2010720252 case 32:
2010820253 out_val->data.x_f32 = sqrtf(val->data.x_f32);
2010920254 break;
......@@ -20124,7 +20269,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
2012420269 }
2012520270
2012620271 assert(float_type->id == TypeTableEntryIdFloat);
20127 if (float_type->data.floating.bit_count != 32 && float_type->data.floating.bit_count != 64) {
20272 if (float_type->data.floating.bit_count != 16 &&
20273 float_type->data.floating.bit_count != 32 &&
20274 float_type->data.floating.bit_count != 64) {
2012820275 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
2012920276 return ira->codegen->builtin_types.entry_invalid;
2013020277 }
src/util.hpp+19
......@@ -31,6 +31,8 @@
3131
3232#endif
3333
34#include "softfloat.hpp"
35
3436#define BREAKPOINT __asm("int $0x03")
3537
3638ATTRIBUTE_COLD
......@@ -165,4 +167,21 @@ static inline uint8_t log2_u64(uint64_t x) {
165167 return (63 - clzll(x));
166168}
167169
170static inline float16_t zig_double_to_f16(double x) {
171 float64_t y;
172 static_assert(sizeof(x) == sizeof(y), "");
173 memcpy(&y, &x, sizeof(x));
174 return f64_to_f16(y);
175}
176
177
178// Return value is safe to coerce to float even when |x| is NaN or Infinity.
179static inline double zig_f16_to_double(float16_t x) {
180 float64_t y = f16_to_f64(x);
181 double z;
182 static_assert(sizeof(y) == sizeof(z), "");
183 memcpy(&z, &y, sizeof(y));
184 return z;
185}
186
168187#endif
std/special/compiler_rt/extendXfYf2.zig+29-27
......@@ -10,9 +10,13 @@ pub extern fn __extendsftf2(a: f32) f128 {
1010 return extendXfYf2(f128, f32, a);
1111}
1212
13pub extern fn __extendhfsf2(a: u16) f32 {
14 return extendXfYf2(f32, f16, @bitCast(f16, a));
15}
16
1317const CHAR_BIT = 8;
1418
15pub fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
19inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
1620 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
1721 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
1822 const srcSigBits = std.math.floatMantissaBits(src_t);
......@@ -22,22 +26,22 @@ pub fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
2226
2327 // Various constants whose values follow from the type parameters.
2428 // Any reasonable optimizer will fold and propagate all of these.
25 const srcBits: i32 = @sizeOf(src_t) * CHAR_BIT;
26 const srcExpBits: i32 = srcBits - srcSigBits - 1;
27 const srcInfExp: i32 = (1 << srcExpBits) - 1;
28 const srcExpBias: i32 = srcInfExp >> 1;
29 const srcBits = @sizeOf(src_t) * CHAR_BIT;
30 const srcExpBits = srcBits - srcSigBits - 1;
31 const srcInfExp = (1 << srcExpBits) - 1;
32 const srcExpBias = srcInfExp >> 1;
2933
30 const srcMinNormal: src_rep_t = src_rep_t(1) << srcSigBits;
31 const srcInfinity: src_rep_t = src_rep_t(@bitCast(u32, srcInfExp)) << srcSigBits;
32 const srcSignMask: src_rep_t = src_rep_t(1) << @intCast(SrcShift, srcSigBits +% srcExpBits);
33 const srcAbsMask: src_rep_t = srcSignMask -% 1;
34 const srcQNaN: src_rep_t = src_rep_t(1) << @intCast(SrcShift, srcSigBits -% 1);
35 const srcNaNCode: src_rep_t = srcQNaN -% 1;
34 const srcMinNormal = 1 << srcSigBits;
35 const srcInfinity = srcInfExp << srcSigBits;
36 const srcSignMask = 1 << (srcSigBits + srcExpBits);
37 const srcAbsMask = srcSignMask - 1;
38 const srcQNaN = 1 << (srcSigBits - 1);
39 const srcNaNCode = srcQNaN - 1;
3640
37 const dstBits: i32 = @sizeOf(dst_t) * CHAR_BIT;
38 const dstExpBits: i32 = dstBits - dstSigBits - 1;
39 const dstInfExp: i32 = (1 << dstExpBits) - 1;
40 const dstExpBias: i32 = dstInfExp >> 1;
41 const dstBits = @sizeOf(dst_t) * CHAR_BIT;
42 const dstExpBits = dstBits - dstSigBits - 1;
43 const dstInfExp = (1 << dstExpBits) - 1;
44 const dstExpBias = dstInfExp >> 1;
4145
4246 const dstMinNormal: dst_rep_t = dst_rep_t(1) << dstSigBits;
4347
......@@ -47,38 +51,36 @@ pub fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
4751 const sign: src_rep_t = aRep & srcSignMask;
4852 var absResult: dst_rep_t = undefined;
4953
50 // If @sizeOf(src_rep_t) < @sizeOf(int), the subtraction result is promoted
51 // to (signed) int. To avoid that, explicitly cast to src_rep_t.
52 if ((src_rep_t)(aAbs -% srcMinNormal) < srcInfinity -% srcMinNormal) {
54 if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) {
5355 // a is a normal number.
5456 // Extend to the destination type by shifting the significand and
5557 // exponent into the proper position and rebiasing the exponent.
56 absResult = dst_rep_t(aAbs) << (dstSigBits -% srcSigBits);
57 absResult += dst_rep_t(@bitCast(u32, dstExpBias -% srcExpBias)) << dstSigBits;
58 absResult = dst_rep_t(aAbs) << (dstSigBits - srcSigBits);
59 absResult += (dstExpBias - srcExpBias) << dstSigBits;
5860 } else if (aAbs >= srcInfinity) {
5961 // a is NaN or infinity.
6062 // Conjure the result by beginning with infinity, then setting the qNaN
6163 // bit (if needed) and right-aligning the rest of the trailing NaN
6264 // payload field.
63 absResult = dst_rep_t(@bitCast(u32, dstInfExp)) << dstSigBits;
64 absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
65 absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
65 absResult = dstInfExp << dstSigBits;
66 absResult |= dst_rep_t(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
67 absResult |= dst_rep_t(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
6668 } else if (aAbs != 0) {
6769 // a is denormal.
6870 // renormalize the significand and clear the leading bit, then insert
6971 // the correct adjusted exponent in the destination type.
70 const scale: i32 = @clz(aAbs) - @clz(srcMinNormal);
72 const scale: u32 = @clz(aAbs) - @clz(src_rep_t(srcMinNormal));
7173 absResult = dst_rep_t(aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
7274 absResult ^= dstMinNormal;
73 const resultExponent: i32 = dstExpBias - srcExpBias - scale + 1;
74 absResult |= dst_rep_t(@bitCast(u32, resultExponent)) << @intCast(DstShift, dstSigBits);
75 const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;
76 absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits;
7577 } else {
7678 // a is zero.
7779 absResult = 0;
7880 }
7981
8082 // Apply the signbit to (dst_t)abs(a).
81 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | dst_rep_t(sign) << @intCast(DstShift, dstBits - srcBits);
83 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | dst_rep_t(sign) << (dstBits - srcBits);
8284 return @bitCast(dst_t, result);
8385}
8486
std/special/compiler_rt/extendXfYf2_test.zig+46
......@@ -1,4 +1,5 @@
11const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
2const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
23const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
34const assert = @import("std").debug.assert;
45
......@@ -24,6 +25,22 @@ fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void {
2425 @panic("__extenddftf2 test failure");
2526}
2627
28fn test__extendhfsf2(a: u16, expected: u32) void {
29 const x = __extendhfsf2(a);
30 const rep = @bitCast(u32, x);
31
32 if (rep == expected) {
33 if (rep & 0x7fffffff > 0x7f800000) {
34 return; // NaN is always unequal.
35 }
36 if (x == @bitCast(f32, expected)) {
37 return;
38 }
39 }
40
41 @panic("__extendhfsf2 test failure");
42}
43
2744fn test__extendsftf2(a: f32, expectedHi: u64, expectedLo: u64) void {
2845 const x = __extendsftf2(a);
2946
......@@ -68,6 +85,35 @@ test "extenddftf2" {
6885 test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000);
6986}
7087
88test "extendhfsf2" {
89 test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN
90 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
91
92 test__extendhfsf2(0, 0); // 0
93 test__extendhfsf2(0x8000, 0x80000000); // -0
94
95 test__extendhfsf2(0x7c00, 0x7f800000); // inf
96 test__extendhfsf2(0xfc00, 0xff800000); // -inf
97
98 test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24
99 test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24
100
101 test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24
102 test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24
103
104 test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14
105 test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14
106
107 test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504
108 test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504
109
110 test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10
111 test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10
112
113 test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3
114 test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3
115}
116
71117test "extendsftf2" {
72118 // qNaN
73119 test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0);
std/special/compiler_rt/index.zig+5
......@@ -15,6 +15,8 @@ comptime {
1515 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
1616 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
1717 @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);
18 @export("__gnu_h2f_ieee", @import("extendXfYf2.zig").__extendhfsf2, linkage);
19 @export("__gnu_f2h_ieee", @import("truncXfYf2.zig").__truncsfhf2, linkage);
1820 }
1921
2022 @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
......@@ -22,6 +24,9 @@ comptime {
2224 @export("__floatuntidf", @import("floatuntidf.zig").__floatuntidf, linkage);
2325 @export("__extenddftf2", @import("extendXfYf2.zig").__extenddftf2, linkage);
2426 @export("__extendsftf2", @import("extendXfYf2.zig").__extendsftf2, linkage);
27 @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
28
29 @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
2530
2631 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
2732 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
std/special/compiler_rt/truncXfYf2.zig created+111
......@@ -0,0 +1,111 @@
1const std = @import("std");
2
3pub extern fn __truncsfhf2(a: f32) u16 {
4 return @bitCast(u16, truncXfYf2(f16, f32, a));
5}
6
7const CHAR_BIT = 8;
8
9inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
10 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
11 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
12 const srcSigBits = std.math.floatMantissaBits(src_t);
13 const dstSigBits = std.math.floatMantissaBits(dst_t);
14 const SrcShift = std.math.Log2Int(src_rep_t);
15 const DstShift = std.math.Log2Int(dst_rep_t);
16
17 // Various constants whose values follow from the type parameters.
18 // Any reasonable optimizer will fold and propagate all of these.
19 const srcBits = @sizeOf(src_t) * CHAR_BIT;
20 const srcExpBits = srcBits - srcSigBits - 1;
21 const srcInfExp = (1 << srcExpBits) - 1;
22 const srcExpBias = srcInfExp >> 1;
23
24 const srcMinNormal = 1 << srcSigBits;
25 const srcSignificandMask = srcMinNormal - 1;
26 const srcInfinity = srcInfExp << srcSigBits;
27 const srcSignMask = 1 << (srcSigBits + srcExpBits);
28 const srcAbsMask = srcSignMask - 1;
29 const roundMask = (1 << (srcSigBits - dstSigBits)) - 1;
30 const halfway = 1 << (srcSigBits - dstSigBits - 1);
31 const srcQNaN = 1 << (srcSigBits - 1);
32 const srcNaNCode = srcQNaN - 1;
33
34 const dstBits = @sizeOf(dst_t) * CHAR_BIT;
35 const dstExpBits = dstBits - dstSigBits - 1;
36 const dstInfExp = (1 << dstExpBits) - 1;
37 const dstExpBias = dstInfExp >> 1;
38
39 const underflowExponent = srcExpBias + 1 - dstExpBias;
40 const overflowExponent = srcExpBias + dstInfExp - dstExpBias;
41 const underflow = underflowExponent << srcSigBits;
42 const overflow = overflowExponent << srcSigBits;
43
44 const dstQNaN = 1 << (dstSigBits - 1);
45 const dstNaNCode = dstQNaN - 1;
46
47 // Break a into a sign and representation of the absolute value
48 const aRep: src_rep_t = @bitCast(src_rep_t, a);
49 const aAbs: src_rep_t = aRep & srcAbsMask;
50 const sign: src_rep_t = aRep & srcSignMask;
51 var absResult: dst_rep_t = undefined;
52
53 if (aAbs -% underflow < aAbs -% overflow) {
54 // The exponent of a is within the range of normal numbers in the
55 // destination format. We can convert by simply right-shifting with
56 // rounding and adjusting the exponent.
57 absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits));
58 absResult -%= dst_rep_t(srcExpBias - dstExpBias) << dstSigBits;
59
60 const roundBits: src_rep_t = aAbs & roundMask;
61 if (roundBits > halfway) {
62 // Round to nearest
63 absResult += 1;
64 } else if (roundBits == halfway) {
65 // Ties to even
66 absResult += absResult & 1;
67 }
68 } else if (aAbs > srcInfinity) {
69 // a is NaN.
70 // Conjure the result by beginning with infinity, setting the qNaN
71 // bit and inserting the (truncated) trailing NaN field.
72 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
73 absResult |= dstQNaN;
74 absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode);
75 } else if (aAbs >= overflow) {
76 // a overflows to infinity.
77 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
78 } else {
79 // a underflows on conversion to the destination type or is an exact
80 // zero. The result may be a denormal or zero. Extract the exponent
81 // to get the shift amount for the denormalization.
82 const aExp: u32 = aAbs >> srcSigBits;
83 const shift: u32 = srcExpBias - dstExpBias - aExp + 1;
84
85 const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal;
86
87 // Right shift by the denormalization amount with sticky.
88 if (shift > srcSigBits) {
89 absResult = 0;
90 } else {
91 const sticky: src_rep_t = significand << @intCast(SrcShift, srcBits - shift);
92 const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky;
93 absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits));
94 const roundBits: src_rep_t = denormalizedSignificand & roundMask;
95 if (roundBits > halfway) {
96 // Round to nearest
97 absResult += 1;
98 } else if (roundBits == halfway) {
99 // Ties to even
100 absResult += absResult & 1;
101 }
102 }
103 }
104
105 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits));
106 return @bitCast(dst_t, result);
107}
108
109test "import truncXfYf2" {
110 _ = @import("truncXfYf2_test.zig");
111}
std/special/compiler_rt/truncXfYf2_test.zig created+64
......@@ -0,0 +1,64 @@
1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
2
3fn test__truncsfhf2(a: u32, expected: u16) void {
4 const actual = __truncsfhf2(@bitCast(f32, a));
5
6 if (actual == expected) {
7 return;
8 }
9
10 @panic("__truncsfhf2 test failure");
11}
12
13test "truncsfhf2" {
14 test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN
15 test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN
16
17 test__truncsfhf2(0, 0); // 0
18 test__truncsfhf2(0x80000000, 0x8000); // -0
19
20 test__truncsfhf2(0x7f800000, 0x7c00); // inf
21 test__truncsfhf2(0xff800000, 0xfc00); // -inf
22
23 test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf
24 test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf
25
26 test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf
27 test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf
28
29 test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14
30 test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14
31
32 test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504
33 test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504
34
35 test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504
36 test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504
37
38 test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504
39 test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504
40
41 test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10
42 test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10
43
44 test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3
45 test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3
46
47 test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535
48 test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535
49
50 test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12
51
52 test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1
53 test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14
54
55 test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24
56 test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24
57
58 test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24
59 test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24
60
61 test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20
62 test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24
63 test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero
64}
test/cases/cast.zig+23-5
......@@ -350,13 +350,16 @@ fn testFloatToInts() void {
350350 assert(x == 10000);
351351 const y = @floatToInt(i32, f32(1e4));
352352 assert(y == 10000);
353 expectFloatToInt(u8, 255.1, 255);
354 expectFloatToInt(i8, 127.2, 127);
355 expectFloatToInt(i8, -128.2, -128);
353 expectFloatToInt(f16, 255.1, u8, 255);
354 expectFloatToInt(f16, 127.2, i8, 127);
355 expectFloatToInt(f16, -128.2, i8, -128);
356 expectFloatToInt(f32, 255.1, u8, 255);
357 expectFloatToInt(f32, 127.2, i8, 127);
358 expectFloatToInt(f32, -128.2, i8, -128);
356359}
357360
358fn expectFloatToInt(comptime T: type, f: f32, i: T) void {
359 assert(@floatToInt(T, f) == i);
361fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
362 assert(@floatToInt(I, f) == i);
360363}
361364
362365test "cast u128 to f128 and back" {
......@@ -418,6 +421,16 @@ test "@intCast comptime_int" {
418421}
419422
420423test "@floatCast comptime_int and comptime_float" {
424 {
425 const result = @floatCast(f16, 1234);
426 assert(@typeOf(result) == f16);
427 assert(result == 1234.0);
428 }
429 {
430 const result = @floatCast(f16, 1234.0);
431 assert(@typeOf(result) == f16);
432 assert(result == 1234.0);
433 }
421434 {
422435 const result = @floatCast(f32, 1234);
423436 assert(@typeOf(result) == f32);
......@@ -431,6 +444,11 @@ test "@floatCast comptime_int and comptime_float" {
431444}
432445
433446test "comptime_int @intToFloat" {
447 {
448 const result = @intToFloat(f16, 1234);
449 assert(@typeOf(result) == f16);
450 assert(result == 1234.0);
451 }
434452 {
435453 const result = @intToFloat(f32, 1234);
436454 assert(@typeOf(result) == f32);
test/cases/math.zig+11-1
......@@ -6,15 +6,20 @@ test "division" {
66}
77fn testDivision() void {
88 assert(div(u32, 13, 3) == 4);
9 assert(div(f16, 1.0, 2.0) == 0.5);
910 assert(div(f32, 1.0, 2.0) == 0.5);
1011
1112 assert(divExact(u32, 55, 11) == 5);
1213 assert(divExact(i32, -55, 11) == -5);
14 assert(divExact(f16, 55.0, 11.0) == 5.0);
15 assert(divExact(f16, -55.0, 11.0) == -5.0);
1316 assert(divExact(f32, 55.0, 11.0) == 5.0);
1417 assert(divExact(f32, -55.0, 11.0) == -5.0);
1518
1619 assert(divFloor(i32, 5, 3) == 1);
1720 assert(divFloor(i32, -5, 3) == -2);
21 assert(divFloor(f16, 5.0, 3.0) == 1.0);
22 assert(divFloor(f16, -5.0, 3.0) == -2.0);
1823 assert(divFloor(f32, 5.0, 3.0) == 1.0);
1924 assert(divFloor(f32, -5.0, 3.0) == -2.0);
2025 assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
......@@ -24,6 +29,8 @@ fn testDivision() void {
2429
2530 assert(divTrunc(i32, 5, 3) == 1);
2631 assert(divTrunc(i32, -5, 3) == -1);
32 assert(divTrunc(f16, 5.0, 3.0) == 1.0);
33 assert(divTrunc(f16, -5.0, 3.0) == -1.0);
2734 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
2835 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
2936
......@@ -435,10 +442,11 @@ test "comptime float rem int" {
435442}
436443
437444test "remainder division" {
445 comptime remdiv(f16);
438446 comptime remdiv(f32);
439447 comptime remdiv(f64);
440448 comptime remdiv(f128);
441 remdiv(f32);
449 remdiv(f16);
442450 remdiv(f64);
443451 remdiv(f128);
444452}
......@@ -453,6 +461,8 @@ test "@sqrt" {
453461 comptime testSqrt(f64, 12.0);
454462 testSqrt(f32, 13.0);
455463 comptime testSqrt(f32, 13.0);
464 testSqrt(f16, 13.0);
465 comptime testSqrt(f16, 13.0);
456466
457467 const x = 14.0;
458468 const y = x * x;
test/cases/misc.zig+1
......@@ -53,6 +53,7 @@ test "@IntType builtin" {
5353}
5454
5555test "floating point primitive bit counts" {
56 assert(f16.bit_count == 16);
5657 assert(f32.bit_count == 32);
5758 assert(f64.bit_count == 64);
5859}