#include "compiler_internal.h" #include #include UNUSED static int precision_bits(TypeKind kind) { switch (kind) { case TYPE_F16: return 11; /*case TYPE_BF16: return 8;*/ case TYPE_F32: return 24; case TYPE_F64: return 53; case TYPE_F128: return 113; default: UNREACHABLE } } UNUSED static int max_exponent(TypeKind kind) { switch (kind) { case TYPE_F16: return 15; /*case TYPE_BF16: return 127;*/ case TYPE_F32: return 127; case TYPE_F64: return 1023; case TYPE_F128: return 16383; default: UNREACHABLE } } UNUSED static int min_exponent(TypeKind kind) { switch (kind) { case TYPE_F16: return -14; /*case TYPE_BF16: return -126;*/ case TYPE_F32: return -126; case TYPE_F64: return -1022; case TYPE_F128: return -16382; default: UNREACHABLE } } Float float_add(Float op1, Float op2) { assert(op1.type == op2.type); return (Float){ op1.f + op2.f, op1.type }; } Float float_sub(Float op1, Float op2) { assert(op1.type == op2.type); return (Float){ op1.f - op2.f, op1.type }; } Float float_mul(Float op1, Float op2) { assert(op1.type == op2.type); return (Float){ op1.f * op2.f, op1.type }; } Float float_div(Float op1, Float op2) { assert(op1.type == op2.type); return (Float){ op1.f / op2.f, op1.type }; } Float float_neg(Float op) { op.f = -op.f; return op; } static char *err_invalid_float_width = "The float width is not valid, it must be one of 16, 32, 64 and 128."; static char *err_float_out_of_range = "The float value is out of range."; static char *err_float_format_invalid = "The float format is invalid."; /** * This parses a float from a string. Unfortunately it is limited to parsing doubles as of now. * * @param string * @param error * @return the resulting Float, with type = TYPE_POISONED on error. */ Float float_from_string(const char *string, char **error) { const char *index = string; char c; scratch_buffer_clear(); while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9'))) { if (c == '_') continue; scratch_buffer_append_char(c); } if (c == '.') { scratch_buffer_append_char(c); while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9'))) { if (c == '_') continue; scratch_buffer_append_char(c); } } if (c == 'e' || c == 'E') { scratch_buffer_append_char(c); if (*index == '-') { scratch_buffer_append_char('-'); index++; } else if (*index == '+') index++; while ((c = *(index++)) && (c >= '0' && c <= '9')) { scratch_buffer_append_char(c); } } TypeKind kind = TYPE_F64; if (c == 'f') { int i = 0; while ((c = *(index++)) && (c >= '0' && c <= '9')) { if (i > 100) { if (error) *error = err_invalid_float_width; return (Float){ .type = TYPE_POISONED }; } i = i * 10 + c - '0'; } switch (i) { case 0: case 32: kind = TYPE_F32; break; case 16: kind = TYPE_F16; break; case 64: kind = TYPE_F64; break; case 128: kind = TYPE_F128; break; default: if (error) *error = err_invalid_float_width; return (Float){ .type = TYPE_POISONED }; } } const char *str = scratch_buffer_to_string(); char *end = NULL; errno = 0; double d = strtod(str, &end); if (d == HUGE_VAL && errno == ERANGE) { if (error) *error = err_float_out_of_range; return (Float){ .type = TYPE_POISONED }; } char *expected_end = scratch_buffer.str + scratch_buffer.len; if (d == 0 && end != expected_end) { if (error) *error = err_float_format_invalid; return (Float){ .type = TYPE_POISONED }; } return (Float){ d, kind }; } /** * This parses a float from hex. Unfortunately it is limited to parsing doubles as of now. * * @param string * @param error * @return the resulting Float, with type = TYPE_POISONED on error. */ Float float_from_hex(const char *string, char **error) { const char *index = string + 2; char c; scratch_buffer_clear(); scratch_buffer_append("0x"); while ((c = *(index++)) && (c == '_' || char_is_hex(c))) { if (c == '_') continue; scratch_buffer_append_char(c); } if (c == '.') { scratch_buffer_append_char(c); while ((c = *(index++)) && (c == '_' || char_is_hex(c))) { if (c == '_') continue; scratch_buffer_append_char(c); } } if (c == 'p' || c == 'P') { scratch_buffer_append_char(c); if (*index == '-') { scratch_buffer_append_char('-'); index++; } else if (*index == '+') index++; while ((c = *(index++)) && (c >= '0' && c <= '9')) { scratch_buffer_append_char(c); } } TypeKind kind = TYPE_F64; if (c == 'f') { int i = 0; while ((c = *(index++)) && (c >= '0' && c <= '9')) { if (i > 100) { if (error) *error = err_invalid_float_width; return (Float){ .type = TYPE_POISONED }; } i = i * 10 + c - '0'; } switch (i) { case 0: case 32: kind = TYPE_F32; break; case 16: kind = TYPE_F16; break; case 64: kind = TYPE_F64; break; case 128: kind = TYPE_F128; break; default: if (error) *error = err_invalid_float_width; return (Float){ .type = TYPE_POISONED }; } } const char *str = scratch_buffer_to_string(); char *end = NULL; errno = 0; double d = strtod(str, &end); if (d == HUGE_VAL && errno == ERANGE) { if (error) *error = err_float_out_of_range; return (Float){ .type = TYPE_POISONED }; } if (d == 0 && end != scratch_buffer.str + scratch_buffer.len) { if (error) *error = err_float_format_invalid; return (Float){ .type = TYPE_POISONED }; } return (Float){ d, kind }; }