Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: src/conversions-inl.h

Issue 2636453003: [conversions] Make "DoubleToUint32IfEqualToSelf" use bit magic (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_CONVERSIONS_INL_H_ 5 #ifndef V8_CONVERSIONS_INL_H_
6 #define V8_CONVERSIONS_INL_H_ 6 #define V8_CONVERSIONS_INL_H_
7 7
8 #include <float.h> // Required for DBL_MAX and on Win32 for finite() 8 #include <float.h> // Required for DBL_MAX and on Win32 for finite()
9 #include <limits.h> // Required for INT_MAX etc. 9 #include <limits.h> // Required for INT_MAX etc.
10 #include <stdarg.h> 10 #include <stdarg.h>
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 bool negative = x < 0; 50 bool negative = x < 0;
51 if (negative) { 51 if (negative) {
52 x = -x; 52 x = -x;
53 } 53 }
54 if (x < k2Pow52) { 54 if (x < k2Pow52) {
55 x += k2Pow52; 55 x += k2Pow52;
56 uint32_t result; 56 uint32_t result;
57 #ifndef V8_TARGET_BIG_ENDIAN 57 #ifndef V8_TARGET_BIG_ENDIAN
58 Address mantissa_ptr = reinterpret_cast<Address>(&x); 58 Address mantissa_ptr = reinterpret_cast<Address>(&x);
59 #else 59 #else
60 Address mantissa_ptr = reinterpret_cast<Address>(&x) + kIntSize; 60 Address mantissa_ptr = reinterpret_cast<Address>(&x) + kInt32Size;
61 #endif 61 #endif
62 // Copy least significant 32 bits of mantissa. 62 // Copy least significant 32 bits of mantissa.
63 memcpy(&result, mantissa_ptr, sizeof(result)); 63 memcpy(&result, mantissa_ptr, sizeof(result));
64 return negative ? ~result + 1 : result; 64 return negative ? ~result + 1 : result;
65 } 65 }
66 // Large number (outside uint32 range), Infinity or NaN. 66 // Large number (outside uint32 range), Infinity or NaN.
67 return 0x80000000u; // Return integer indefinite. 67 return 0x80000000u; // Return integer indefinite.
68 } 68 }
69 69
70 70
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 value == FastI2D(FastD2I(value)); 116 value == FastI2D(FastD2I(value));
117 } 117 }
118 118
119 119
120 bool IsUint32Double(double value) { 120 bool IsUint32Double(double value) {
121 return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 && 121 return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
122 value == FastUI2D(FastD2UI(value)); 122 value == FastUI2D(FastD2UI(value));
123 } 123 }
124 124
125 bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) { 125 bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) {
126 if (value < 0) return false; 126 const double k2Pow52 = 4503599627370496.0;
127 // TODO(leszeks): We maybe could be faster than FastD2UI here, since we only 127 const uint32_t kValidTopBits = 0x43300000;
128 // care about the value being valid if the conversion is valid. 128
129 uint32_t converted_value = FastD2UI(value); 129 // Add 2^52 to the double, to place valid uint32 values in the low-significant
130 if (FastUI2D(converted_value) == value) { 130 // bits of the exponent, by effectively setting the (implicit) top bit of the
131 *uint32_value = converted_value; 131 // significand. Note that this addition also normalises 0.0 and -0.0.
132 return true; 132 double shifted_value = value + k2Pow52;
133
134 // At this point, a valid uint32 valued double will be represented as:
135 //
136 // sign = 0
137 // exponent = 52
138 // significand = 1. 00...00 <value>
139 // implicit^ ^^^^^^^ 32 bits
140 // ^^^^^^^^^^^^^^^ 52 bits
141 //
142 // Therefore, it is sufficient to check the top 32 bits to make sure that the
143 // sign, exponent and remaining significand bits are valid, and extract the
144 // bottom 32 bits to get the value.
145
146 uint32_t check;
147 #ifndef V8_TARGET_BIG_ENDIAN
148 Address top_ptr = reinterpret_cast<Address>(&shifted_value) + kInt32Size;
149 Address bottom_ptr = reinterpret_cast<Address>(&shifted_value);
150 #else
151 Address top_ptr = reinterpret_cast<Address>(&shifted_value);
152 Address bottom_ptr = reinterpret_cast<Address>(&shifted_value) + kInt32Size;
153 #endif
154 memcpy(&check, top_ptr, sizeof(uint32_t));
rmcilroy 2017/01/16 14:12:11 Could you just do a reinterpreter_cast on the addr
Leszek Swirski 2017/01/16 14:26:54 Good question -- short version, no, because of str
rmcilroy 2017/01/16 15:59:51 Ahh I see, thanks for the explination.
Leszek Swirski 2017/01/17 12:36:19 Whoops, it turns out my microbenchmarks were super
155 if (check == kValidTopBits) {
156 memcpy(uint32_value, bottom_ptr, sizeof(uint32_t));
rmcilroy 2017/01/16 14:12:11 ditto
Leszek Swirski 2017/01/16 14:26:54 As above.
157 // Make sure we convert back to the right value.
158 return FastUI2D(*uint32_value) == value;
133 } 159 }
160 DCHECK(DoubleToUint32(value) != value);
134 return false; 161 return false;
135 } 162 }
136 163
137 int32_t NumberToInt32(Object* number) { 164 int32_t NumberToInt32(Object* number) {
138 if (number->IsSmi()) return Smi::cast(number)->value(); 165 if (number->IsSmi()) return Smi::cast(number)->value();
139 return DoubleToInt32(number->Number()); 166 return DoubleToInt32(number->Number());
140 } 167 }
141 168
142 uint32_t NumberToUint32(Object* number) { 169 uint32_t NumberToUint32(Object* number) {
143 if (number->IsSmi()) return Smi::cast(number)->value(); 170 if (number->IsSmi()) return Smi::cast(number)->value();
(...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 buffer[buffer_pos] = '\0'; 822 buffer[buffer_pos] = '\0';
796 823
797 double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); 824 double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
798 return (sign == NEGATIVE) ? -converted : converted; 825 return (sign == NEGATIVE) ? -converted : converted;
799 } 826 }
800 827
801 } // namespace internal 828 } // namespace internal
802 } // namespace v8 829 } // namespace v8
803 830
804 #endif // V8_CONVERSIONS_INL_H_ 831 #endif // V8_CONVERSIONS_INL_H_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698