From c0a6ae3eff2a206b0ea379a042832bbd889c9571 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 31 Oct 2014 20:19:16 +0300 Subject: [PATCH] - Smaller but not precise conversion between strings and numbers under CONFIG_ECMA_NUMBER_TYPE==CONFIG_ECMA_NUMBER_FLOAT32 (float32 mode); - float64 mode by default if not CompactProfile-mode; - CompactProfile-mode for MCU builds. --- Makefile | 11 +- Makefile.mk | 33 ++--- src/libecmaobjects/ecma-helpers-conversion.c | 140 +++++++++++++++++++ 3 files changed, 156 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index db5ce6fd9..9ec62b879 100644 --- a/Makefile +++ b/Makefile @@ -46,11 +46,12 @@ export TARGET_RELEASE_MODES = release export TARGET_PC_SYSTEMS = linux export TARGET_MCU_SYSTEMS = $(addprefix stm32f,3 4) -export TARGET_PC_MODS = musl sanitize valgrind float64 cp cp_minimal \ +export TARGET_PC_MODS = musl sanitize valgrind cp cp_minimal \ musl-valgrind \ + valgrind-cp \ musl-cp_minimal -export TARGET_MCU_MODS = +export TARGET_MCU_MODS = cp_minimal export TARGET_PC_SYSTEMS_MODS = $(TARGET_PC_SYSTEMS) \ $(foreach __MOD,$(TARGET_PC_MODS),$(foreach __SYSTEM,$(TARGET_PC_SYSTEMS),$(__SYSTEM)-$(__MOD))) @@ -86,10 +87,10 @@ all: precommit PRECOMMIT_CHECK_TARGETS_NO_VALGRIND_LIST= debug.linux.check \ release.linux.check \ - debug_release.linux.check \ - debug.linux-float64.check + debug_release.linux.check PRECOMMIT_CHECK_TARGETS_VALGRIND_LIST= debug.linux-valgrind.check \ - release.linux-musl-valgrind.check + release.linux-musl-valgrind.check \ + debug.linux-valgrind-cp.check # debug.linux-musl-valgrind.check \ debug_release.linux-valgrind.check \ diff --git a/Makefile.mk b/Makefile.mk index 1004b307e..197fd1693 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -160,22 +160,15 @@ else OPTION_LIBC := raw endif -# float64 mode -ifeq ($(filter float64,$(TARGET_MODS)), float64) - ifeq ($(OPTION_MCU),enable) - $(error MCU target doesn\'t support float64) - endif - - OPTION_FLOAT64 := enable -else - OPTION_FLOAT64 := disable -endif - # CompactProfile mode -ifeq ($(filter cp,$(TARGET_MODS)), cp) +ifeq ($(OPTION_MCU),enable) OPTION_COMPACT_PROFILE := enable else - OPTION_COMPACT_PROFILE := disable + ifeq ($(filter cp,$(TARGET_MODS)), cp) + OPTION_COMPACT_PROFILE := enable + else + OPTION_COMPACT_PROFILE := disable + endif endif # minimal CompactProfile mode @@ -186,11 +179,6 @@ else OPTION_CP_MINIMAL := disable endif -# Enabling float64 mode for unittests -ifeq ($(filter-out $(TESTS_TARGET),$(TARGET_MODE)),) - OPTION_FLOAT64 := enable -endif - ifeq ($(filter sanitize,$(TARGET_MODS)), sanitize) ifeq ($(OPTION_LIBC),musl) $(error ASAN and LIBC_MUSL are mutually exclusive) @@ -366,12 +354,10 @@ ifeq ($(OPTION_NDEBUG),enable) DEFINES_JERRY += -DJERRY_NDEBUG endif -ifeq ($(OPTION_FLOAT64),enable) - DEFINES_JERRY += -DCONFIG_ECMA_NUMBER_TYPE=CONFIG_ECMA_NUMBER_FLOAT64 -endif - ifeq ($(OPTION_COMPACT_PROFILE),enable) DEFINES_JERRY += -DCONFIG_ECMA_COMPACT_PROFILE +else + DEFINES_JERRY += -DCONFIG_ECMA_NUMBER_TYPE=CONFIG_ECMA_NUMBER_FLOAT64 endif ifeq ($(OPTION_CP_MINIMAL),enable) @@ -383,7 +369,8 @@ ifeq ($(OPTION_CP_MINIMAL),enable) -DCONFIG_ECMA_COMPACT_PROFILE_DISABLE_MATH_BUILTIN \ -DCONFIG_ECMA_COMPACT_PROFILE_DISABLE_DATE_BUILTIN \ -DCONFIG_ECMA_COMPACT_PROFILE_DISABLE_JSON_BUILTIN \ - -DCONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN + -DCONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN \ + -DCONFIG_ECMA_NUMBER_TYPE=CONFIG_ECMA_NUMBER_FLOAT32 endif ifeq ($(OPTION_MCU),disable) diff --git a/src/libecmaobjects/ecma-helpers-conversion.c b/src/libecmaobjects/ecma-helpers-conversion.c index ac7dcc089..32c148a3e 100644 --- a/src/libecmaobjects/ecma-helpers-conversion.c +++ b/src/libecmaobjects/ecma-helpers-conversion.c @@ -609,6 +609,7 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string return sign ? -ECMA_NUMBER_ZERO : ECMA_NUMBER_ZERO; } +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 int32_t binary_exponent = 1; /* @@ -733,6 +734,25 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string return ecma_number_make_from_sign_mantissa_and_exponent (sign, fraction_uint64, binary_exponent); +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + /* Less precise conversion */ + ecma_number_t num = (ecma_number_t) (uint32_t) fraction_uint64; + + ecma_number_t m = e_sign ? (ecma_number_t) 0.1 : (ecma_number_t) 10.0; + + while (e) + { + if (e % 2) + { + num *= m; + } + + m *= m; + e /= 2; + } + + return num; +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ } /* ecma_zt_string_to_number */ /** @@ -847,6 +867,7 @@ ecma_number_to_int32 (ecma_number_t value) /**< unsigned 32-bit integer value */ return (int32_t) (uint32_t) value; } /* ecma_number_to_int32 */ +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 /** * Perform conversion of binary representation of number to decimal representation with decimal exponent */ @@ -1085,6 +1106,8 @@ ecma_number_to_zt_string_calc_number_params (ecma_number_t num, /**< ecma-number *out_decimal_exp_p = decimal_exp_p1 + digits_num; } /* ecma_number_to_zt_string_calc_number_params */ +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ + /** * Convert ecma-number to zero-terminated string * @@ -1155,6 +1178,7 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ } else { +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 uint64_t fraction_uint64; int32_t binary_exponent; @@ -1180,6 +1204,122 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ JERRY_ASSERT (s == s_uint64); #endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + /* Less precise conversion */ + + uint64_t fraction_uint64; + uint32_t fraction; + int32_t exponent; + int32_t dot_shift; + int32_t decimal_exp = 0; + + dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction_uint64, &exponent); + + fraction = (uint32_t) fraction_uint64; + JERRY_ASSERT (fraction == fraction_uint64); + + if (exponent != 0) + { + ecma_number_t t = 1.0f; + bool do_divide; + + if (exponent < 0) + { + do_divide = true; + + while (exponent <= 0) + { + t *= 2.0f; + exponent++; + + if (t >= 10.0f) + { + t /= 10.0f; + decimal_exp--; + } + + JERRY_ASSERT (t < 10.0f); + } + + while (t > 1.0f) + { + exponent--; + t /= 2.0f; + } + } + else + { + do_divide = false; + + while (exponent >= 0) + { + t *= 2.0f; + exponent--; + + if (t >= 10.0f) + { + t /= 10.0f; + decimal_exp++; + } + + JERRY_ASSERT (t < 10.0f); + } + + while (t > 2.0f) + { + exponent++; + t /= 2.0f; + } + } + + if (do_divide) + { + fraction = (uint32_t) ((ecma_number_t) fraction / t); + } + else + { + fraction = (uint32_t) ((ecma_number_t) fraction * t); + } + } + + uint32_t s; + int32_t n; + int32_t k; + + if (exponent > 0) + { + fraction <<= exponent; + } + else + { + fraction >>= -exponent; + } + + const int32_t int_part_shift = dot_shift; + const uint32_t frac_part_mask = ((((uint32_t)1) << int_part_shift) - 1); + + uint32_t int_part = fraction >> int_part_shift; + uint32_t frac_part = fraction & frac_part_mask; + + s = int_part; + k = 1; + n = decimal_exp + 1; + + JERRY_ASSERT (int_part < 10); + + while (k < ECMA_NUMBER_MAX_DIGITS + && frac_part != 0) + { + frac_part *= 10; + + uint32_t new_frac_part = frac_part & frac_part_mask; + uint32_t digit = (frac_part - new_frac_part) >> int_part_shift; + s = s * 10 + digit; + k++; + frac_part = new_frac_part; + } +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ + // 6. if (k <= n && n <= 21) {