Index: src/arm/macro-assembler-arm.cc |
=================================================================== |
--- src/arm/macro-assembler-arm.cc (revision 5394) |
+++ src/arm/macro-assembler-arm.cc (working copy) |
@@ -25,6 +25,8 @@ |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+#include <limits.h> // For LONG_MIN, LONG_MAX. |
+ |
#include "v8.h" |
#if defined(V8_TARGET_ARCH_ARM) |
@@ -1333,6 +1335,104 @@ |
} |
+// Tries to get a signed int32 out of a double precision floating point heap |
+// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the |
+// 32bits signed integer range. |
+void MacroAssembler::ConvertToInt32(Register source, |
+ Register dest, |
+ Register scratch, |
+ Register scratch2, |
+ Label *not_int32) { |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ CpuFeatures::Scope scope(VFP3); |
+ sub(scratch, source, Operand(kHeapObjectTag)); |
+ vldr(d0, scratch, HeapNumber::kValueOffset); |
+ vcvt_s32_f64(s0, d0); |
+ vmov(dest, s0); |
+ // Signed vcvt instruction will saturate to the minimum (0x80000000) or |
+ // maximun (0x7fffffff) signed 32bits integer when the double is out of |
+ // range. When substracting one, the minimum signed integer becomes the |
+ // maximun signed integer. |
+ sub(scratch, dest, Operand(1)); |
+ cmp(scratch, Operand(LONG_MAX - 1)); |
+ // If equal then dest was LONG_MAX, if greater dest was LONG_MIN. |
+ b(ge, not_int32); |
+ } else { |
+ // This code is faster for doubles that are in the ranges -0x7fffffff to |
+ // -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to |
+ // the range of signed int32 values that are not Smis. Jumps to the label |
+ // 'not_int32' if the double isn't in the range -0x80000000.0 to |
+ // 0x80000000.0 (excluding the endpoints). |
+ Label right_exponent, done; |
+ // Get exponent word. |
+ ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset)); |
+ // Get exponent alone in scratch2. |
+ Ubfx(scratch2, |
+ scratch, |
+ HeapNumber::kExponentShift, |
+ HeapNumber::kExponentBits); |
+ // Load dest with zero. We use this either for the final shift or |
+ // for the answer. |
+ mov(dest, Operand(0)); |
+ // Check whether the exponent matches a 32 bit signed int that is not a Smi. |
+ // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is |
+ // the exponent that we are fastest at and also the highest exponent we can |
+ // handle here. |
+ const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30; |
+ // The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we |
+ // split it up to avoid a constant pool entry. You can't do that in general |
+ // for cmp because of the overflow flag, but we know the exponent is in the |
+ // range 0-2047 so there is no overflow. |
+ int fudge_factor = 0x400; |
+ sub(scratch2, scratch2, Operand(fudge_factor)); |
+ cmp(scratch2, Operand(non_smi_exponent - fudge_factor)); |
+ // If we have a match of the int32-but-not-Smi exponent then skip some |
+ // logic. |
+ b(eq, &right_exponent); |
+ // If the exponent is higher than that then go to slow case. This catches |
+ // numbers that don't fit in a signed int32, infinities and NaNs. |
+ b(gt, not_int32); |
+ |
+ // We know the exponent is smaller than 30 (biased). If it is less than |
+ // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie |
+ // it rounds to zero. |
+ const uint32_t zero_exponent = HeapNumber::kExponentBias + 0; |
+ sub(scratch2, scratch2, Operand(zero_exponent - fudge_factor), SetCC); |
+ // Dest already has a Smi zero. |
+ b(lt, &done); |
+ |
+ // We have an exponent between 0 and 30 in scratch2. Subtract from 30 to |
+ // get how much to shift down. |
+ rsb(dest, scratch2, Operand(30)); |
+ |
+ bind(&right_exponent); |
+ // Get the top bits of the mantissa. |
+ and_(scratch2, scratch, Operand(HeapNumber::kMantissaMask)); |
+ // Put back the implicit 1. |
+ orr(scratch2, scratch2, Operand(1 << HeapNumber::kExponentShift)); |
+ // Shift up the mantissa bits to take up the space the exponent used to |
+ // take. We just orred in the implicit bit so that took care of one and |
+ // we want to leave the sign bit 0 so we subtract 2 bits from the shift |
+ // distance. |
+ const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; |
+ mov(scratch2, Operand(scratch2, LSL, shift_distance)); |
+ // Put sign in zero flag. |
+ tst(scratch, Operand(HeapNumber::kSignMask)); |
+ // Get the second half of the double. For some exponents we don't |
+ // actually need this because the bits get shifted out again, but |
+ // it's probably slower to test than just to do it. |
+ ldr(scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset)); |
+ // Shift down 22 bits to get the last 10 bits. |
+ orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance)); |
+ // Move down according to the exponent. |
+ mov(dest, Operand(scratch, LSR, dest)); |
+ // Fix sign if sign bit was set. |
+ rsb(dest, dest, Operand(0), LeaveCC, ne); |
+ bind(&done); |
+ } |
+} |
+ |
+ |
void MacroAssembler::GetLeastBitsFromSmi(Register dst, |
Register src, |
int num_least_bits) { |