Home | History | Annotate | Download | only in wasm
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <math.h>
      6 #include <stdint.h>
      7 #include <stdlib.h>
      8 #include <limits>
      9 
     10 #include "include/v8config.h"
     11 
     12 #include "src/base/bits.h"
     13 #include "src/utils.h"
     14 #include "src/wasm/wasm-external-refs.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace wasm {
     19 
     20 void f32_trunc_wrapper(float* param) { *param = truncf(*param); }
     21 
     22 void f32_floor_wrapper(float* param) { *param = floorf(*param); }
     23 
     24 void f32_ceil_wrapper(float* param) { *param = ceilf(*param); }
     25 
     26 void f32_nearest_int_wrapper(float* param) { *param = nearbyintf(*param); }
     27 
     28 void f64_trunc_wrapper(double* param) {
     29   WriteDoubleValue(param, trunc(ReadDoubleValue(param)));
     30 }
     31 
     32 void f64_floor_wrapper(double* param) {
     33   WriteDoubleValue(param, floor(ReadDoubleValue(param)));
     34 }
     35 
     36 void f64_ceil_wrapper(double* param) {
     37   WriteDoubleValue(param, ceil(ReadDoubleValue(param)));
     38 }
     39 
     40 void f64_nearest_int_wrapper(double* param) {
     41   WriteDoubleValue(param, nearbyint(ReadDoubleValue(param)));
     42 }
     43 
     44 void int64_to_float32_wrapper(int64_t* input, float* output) {
     45   *output = static_cast<float>(*input);
     46 }
     47 
     48 void uint64_to_float32_wrapper(uint64_t* input, float* output) {
     49 #if V8_CC_MSVC
     50   // With MSVC we use static_cast<float>(uint32_t) instead of
     51   // static_cast<float>(uint64_t) to achieve round-to-nearest-ties-even
     52   // semantics. The idea is to calculate
     53   // static_cast<float>(high_word) * 2^32 + static_cast<float>(low_word). To
     54   // achieve proper rounding in all cases we have to adjust the high_word
     55   // with a "rounding bit" sometimes. The rounding bit is stored in the LSB of
     56   // the high_word if the low_word may affect the rounding of the high_word.
     57   uint32_t low_word = static_cast<uint32_t>(*input & 0xffffffff);
     58   uint32_t high_word = static_cast<uint32_t>(*input >> 32);
     59 
     60   float shift = static_cast<float>(1ull << 32);
     61   // If the MSB of the high_word is set, then we make space for a rounding bit.
     62   if (high_word < 0x80000000) {
     63     high_word <<= 1;
     64     shift = static_cast<float>(1ull << 31);
     65   }
     66 
     67   if ((high_word & 0xfe000000) && low_word) {
     68     // Set the rounding bit.
     69     high_word |= 1;
     70   }
     71 
     72   float result = static_cast<float>(high_word);
     73   result *= shift;
     74   result += static_cast<float>(low_word);
     75   *output = result;
     76 
     77 #else
     78   *output = static_cast<float>(*input);
     79 #endif
     80 }
     81 
     82 void int64_to_float64_wrapper(int64_t* input, double* output) {
     83   *output = static_cast<double>(*input);
     84 }
     85 
     86 void uint64_to_float64_wrapper(uint64_t* input, double* output) {
     87 #if V8_CC_MSVC
     88   // With MSVC we use static_cast<double>(uint32_t) instead of
     89   // static_cast<double>(uint64_t) to achieve round-to-nearest-ties-even
     90   // semantics. The idea is to calculate
     91   // static_cast<double>(high_word) * 2^32 + static_cast<double>(low_word).
     92   uint32_t low_word = static_cast<uint32_t>(*input & 0xffffffff);
     93   uint32_t high_word = static_cast<uint32_t>(*input >> 32);
     94 
     95   double shift = static_cast<double>(1ull << 32);
     96 
     97   double result = static_cast<double>(high_word);
     98   result *= shift;
     99   result += static_cast<double>(low_word);
    100   *output = result;
    101 
    102 #else
    103   *output = static_cast<double>(*input);
    104 #endif
    105 }
    106 
    107 int32_t float32_to_int64_wrapper(float* input, int64_t* output) {
    108   // We use "<" here to check the upper bound because of rounding problems: With
    109   // "<=" some inputs would be considered within int64 range which are actually
    110   // not within int64 range.
    111   if (*input >= static_cast<float>(std::numeric_limits<int64_t>::min()) &&
    112       *input < static_cast<float>(std::numeric_limits<int64_t>::max())) {
    113     *output = static_cast<int64_t>(*input);
    114     return 1;
    115   }
    116   return 0;
    117 }
    118 
    119 int32_t float32_to_uint64_wrapper(float* input, uint64_t* output) {
    120   // We use "<" here to check the upper bound because of rounding problems: With
    121   // "<=" some inputs would be considered within uint64 range which are actually
    122   // not within uint64 range.
    123   if (*input > -1.0 &&
    124       *input < static_cast<float>(std::numeric_limits<uint64_t>::max())) {
    125     *output = static_cast<uint64_t>(*input);
    126     return 1;
    127   }
    128   return 0;
    129 }
    130 
    131 int32_t float64_to_int64_wrapper(double* input, int64_t* output) {
    132   // We use "<" here to check the upper bound because of rounding problems: With
    133   // "<=" some inputs would be considered within int64 range which are actually
    134   // not within int64 range.
    135   if (*input >= static_cast<double>(std::numeric_limits<int64_t>::min()) &&
    136       *input < static_cast<double>(std::numeric_limits<int64_t>::max())) {
    137     *output = static_cast<int64_t>(*input);
    138     return 1;
    139   }
    140   return 0;
    141 }
    142 
    143 int32_t float64_to_uint64_wrapper(double* input, uint64_t* output) {
    144   // We use "<" here to check the upper bound because of rounding problems: With
    145   // "<=" some inputs would be considered within uint64 range which are actually
    146   // not within uint64 range.
    147   if (*input > -1.0 &&
    148       *input < static_cast<double>(std::numeric_limits<uint64_t>::max())) {
    149     *output = static_cast<uint64_t>(*input);
    150     return 1;
    151   }
    152   return 0;
    153 }
    154 
    155 int32_t int64_div_wrapper(int64_t* dst, int64_t* src) {
    156   if (*src == 0) {
    157     return 0;
    158   }
    159   if (*src == -1 && *dst == std::numeric_limits<int64_t>::min()) {
    160     return -1;
    161   }
    162   *dst /= *src;
    163   return 1;
    164 }
    165 
    166 int32_t int64_mod_wrapper(int64_t* dst, int64_t* src) {
    167   if (*src == 0) {
    168     return 0;
    169   }
    170   *dst %= *src;
    171   return 1;
    172 }
    173 
    174 int32_t uint64_div_wrapper(uint64_t* dst, uint64_t* src) {
    175   if (*src == 0) {
    176     return 0;
    177   }
    178   *dst /= *src;
    179   return 1;
    180 }
    181 
    182 int32_t uint64_mod_wrapper(uint64_t* dst, uint64_t* src) {
    183   if (*src == 0) {
    184     return 0;
    185   }
    186   *dst %= *src;
    187   return 1;
    188 }
    189 
    190 uint32_t word32_ctz_wrapper(uint32_t* input) {
    191   return static_cast<uint32_t>(base::bits::CountTrailingZeros32(*input));
    192 }
    193 
    194 uint32_t word64_ctz_wrapper(uint64_t* input) {
    195   return static_cast<uint32_t>(base::bits::CountTrailingZeros64(*input));
    196 }
    197 
    198 uint32_t word32_popcnt_wrapper(uint32_t* input) {
    199   return static_cast<uint32_t>(base::bits::CountPopulation(*input));
    200 }
    201 
    202 uint32_t word64_popcnt_wrapper(uint64_t* input) {
    203   return static_cast<uint32_t>(base::bits::CountPopulation(*input));
    204 }
    205 
    206 void float64_pow_wrapper(double* param0, double* param1) {
    207   double x = ReadDoubleValue(param0);
    208   double y = ReadDoubleValue(param1);
    209   WriteDoubleValue(param0, Pow(x, y));
    210 }
    211 
    212 static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
    213 
    214 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
    215   wasm_trap_callback_for_testing = callback;
    216 }
    217 
    218 void call_trap_callback_for_testing() {
    219   if (wasm_trap_callback_for_testing) {
    220     wasm_trap_callback_for_testing();
    221   }
    222 }
    223 
    224 }  // namespace wasm
    225 }  // namespace internal
    226 }  // namespace v8
    227