| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
| 10 #include "src/hydrogen-osr.h" | 10 #include "src/hydrogen-osr.h" |
| (...skipping 1949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1960 __ j(condition, &return_left, Label::kNear); | 1960 __ j(condition, &return_left, Label::kNear); |
| 1961 __ movp(left_reg, right_op); | 1961 __ movp(left_reg, right_op); |
| 1962 } | 1962 } |
| 1963 __ bind(&return_left); | 1963 __ bind(&return_left); |
| 1964 } else { | 1964 } else { |
| 1965 DCHECK(instr->hydrogen()->representation().IsDouble()); | 1965 DCHECK(instr->hydrogen()->representation().IsDouble()); |
| 1966 Label check_nan_left, check_zero, return_left, return_right; | 1966 Label check_nan_left, check_zero, return_left, return_right; |
| 1967 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above; | 1967 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above; |
| 1968 XMMRegister left_reg = ToDoubleRegister(left); | 1968 XMMRegister left_reg = ToDoubleRegister(left); |
| 1969 XMMRegister right_reg = ToDoubleRegister(right); | 1969 XMMRegister right_reg = ToDoubleRegister(right); |
| 1970 __ ucomisd(left_reg, right_reg); | 1970 __ Ucomisd(left_reg, right_reg); |
| 1971 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. | 1971 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| 1972 __ j(equal, &check_zero, Label::kNear); // left == right. | 1972 __ j(equal, &check_zero, Label::kNear); // left == right. |
| 1973 __ j(condition, &return_left, Label::kNear); | 1973 __ j(condition, &return_left, Label::kNear); |
| 1974 __ jmp(&return_right, Label::kNear); | 1974 __ jmp(&return_right, Label::kNear); |
| 1975 | 1975 |
| 1976 __ bind(&check_zero); | 1976 __ bind(&check_zero); |
| 1977 XMMRegister xmm_scratch = double_scratch0(); | 1977 XMMRegister xmm_scratch = double_scratch0(); |
| 1978 __ Xorpd(xmm_scratch, xmm_scratch); | 1978 __ Xorpd(xmm_scratch, xmm_scratch); |
| 1979 __ ucomisd(left_reg, xmm_scratch); | 1979 __ Ucomisd(left_reg, xmm_scratch); |
| 1980 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. | 1980 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. |
| 1981 // At this point, both left and right are either 0 or -0. | 1981 // At this point, both left and right are either 0 or -0. |
| 1982 if (operation == HMathMinMax::kMathMin) { | 1982 if (operation == HMathMinMax::kMathMin) { |
| 1983 __ orps(left_reg, right_reg); | 1983 __ orps(left_reg, right_reg); |
| 1984 } else { | 1984 } else { |
| 1985 // Since we operate on +0 and/or -0, addsd and andsd have the same effect. | 1985 // Since we operate on +0 and/or -0, addsd and andsd have the same effect. |
| 1986 __ addsd(left_reg, right_reg); | 1986 __ addsd(left_reg, right_reg); |
| 1987 } | 1987 } |
| 1988 __ jmp(&return_left, Label::kNear); | 1988 __ jmp(&return_left, Label::kNear); |
| 1989 | 1989 |
| 1990 __ bind(&check_nan_left); | 1990 __ bind(&check_nan_left); |
| 1991 __ ucomisd(left_reg, left_reg); // NaN check. | 1991 __ Ucomisd(left_reg, left_reg); // NaN check. |
| 1992 __ j(parity_even, &return_left, Label::kNear); | 1992 __ j(parity_even, &return_left, Label::kNear); |
| 1993 __ bind(&return_right); | 1993 __ bind(&return_right); |
| 1994 __ Movapd(left_reg, right_reg); | 1994 __ Movapd(left_reg, right_reg); |
| 1995 | 1995 |
| 1996 __ bind(&return_left); | 1996 __ bind(&return_left); |
| 1997 } | 1997 } |
| 1998 } | 1998 } |
| 1999 | 1999 |
| 2000 | 2000 |
| 2001 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { | 2001 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2122 } else if (r.IsSmi()) { | 2122 } else if (r.IsSmi()) { |
| 2123 DCHECK(!info()->IsStub()); | 2123 DCHECK(!info()->IsStub()); |
| 2124 Register reg = ToRegister(instr->value()); | 2124 Register reg = ToRegister(instr->value()); |
| 2125 __ testp(reg, reg); | 2125 __ testp(reg, reg); |
| 2126 EmitBranch(instr, not_zero); | 2126 EmitBranch(instr, not_zero); |
| 2127 } else if (r.IsDouble()) { | 2127 } else if (r.IsDouble()) { |
| 2128 DCHECK(!info()->IsStub()); | 2128 DCHECK(!info()->IsStub()); |
| 2129 XMMRegister reg = ToDoubleRegister(instr->value()); | 2129 XMMRegister reg = ToDoubleRegister(instr->value()); |
| 2130 XMMRegister xmm_scratch = double_scratch0(); | 2130 XMMRegister xmm_scratch = double_scratch0(); |
| 2131 __ Xorpd(xmm_scratch, xmm_scratch); | 2131 __ Xorpd(xmm_scratch, xmm_scratch); |
| 2132 __ ucomisd(reg, xmm_scratch); | 2132 __ Ucomisd(reg, xmm_scratch); |
| 2133 EmitBranch(instr, not_equal); | 2133 EmitBranch(instr, not_equal); |
| 2134 } else { | 2134 } else { |
| 2135 DCHECK(r.IsTagged()); | 2135 DCHECK(r.IsTagged()); |
| 2136 Register reg = ToRegister(instr->value()); | 2136 Register reg = ToRegister(instr->value()); |
| 2137 HType type = instr->hydrogen()->value()->type(); | 2137 HType type = instr->hydrogen()->value()->type(); |
| 2138 if (type.IsBoolean()) { | 2138 if (type.IsBoolean()) { |
| 2139 DCHECK(!info()->IsStub()); | 2139 DCHECK(!info()->IsStub()); |
| 2140 __ CompareRoot(reg, Heap::kTrueValueRootIndex); | 2140 __ CompareRoot(reg, Heap::kTrueValueRootIndex); |
| 2141 EmitBranch(instr, equal); | 2141 EmitBranch(instr, equal); |
| 2142 } else if (type.IsSmi()) { | 2142 } else if (type.IsSmi()) { |
| 2143 DCHECK(!info()->IsStub()); | 2143 DCHECK(!info()->IsStub()); |
| 2144 __ SmiCompare(reg, Smi::FromInt(0)); | 2144 __ SmiCompare(reg, Smi::FromInt(0)); |
| 2145 EmitBranch(instr, not_equal); | 2145 EmitBranch(instr, not_equal); |
| 2146 } else if (type.IsJSArray()) { | 2146 } else if (type.IsJSArray()) { |
| 2147 DCHECK(!info()->IsStub()); | 2147 DCHECK(!info()->IsStub()); |
| 2148 EmitBranch(instr, no_condition); | 2148 EmitBranch(instr, no_condition); |
| 2149 } else if (type.IsHeapNumber()) { | 2149 } else if (type.IsHeapNumber()) { |
| 2150 DCHECK(!info()->IsStub()); | 2150 DCHECK(!info()->IsStub()); |
| 2151 XMMRegister xmm_scratch = double_scratch0(); | 2151 XMMRegister xmm_scratch = double_scratch0(); |
| 2152 __ Xorpd(xmm_scratch, xmm_scratch); | 2152 __ Xorpd(xmm_scratch, xmm_scratch); |
| 2153 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); | 2153 __ Ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2154 EmitBranch(instr, not_equal); | 2154 EmitBranch(instr, not_equal); |
| 2155 } else if (type.IsString()) { | 2155 } else if (type.IsString()) { |
| 2156 DCHECK(!info()->IsStub()); | 2156 DCHECK(!info()->IsStub()); |
| 2157 __ cmpp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); | 2157 __ cmpp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); |
| 2158 EmitBranch(instr, not_equal); | 2158 EmitBranch(instr, not_equal); |
| 2159 } else { | 2159 } else { |
| 2160 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); | 2160 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); |
| 2161 // Avoid deopts in the case where we've never executed this path before. | 2161 // Avoid deopts in the case where we've never executed this path before. |
| 2162 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); | 2162 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); |
| 2163 | 2163 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2232 __ j(equal, instr->TrueLabel(chunk_)); | 2232 __ j(equal, instr->TrueLabel(chunk_)); |
| 2233 } | 2233 } |
| 2234 | 2234 |
| 2235 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { | 2235 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { |
| 2236 // heap number -> false iff +0, -0, or NaN. | 2236 // heap number -> false iff +0, -0, or NaN. |
| 2237 Label not_heap_number; | 2237 Label not_heap_number; |
| 2238 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); | 2238 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 2239 __ j(not_equal, ¬_heap_number, Label::kNear); | 2239 __ j(not_equal, ¬_heap_number, Label::kNear); |
| 2240 XMMRegister xmm_scratch = double_scratch0(); | 2240 XMMRegister xmm_scratch = double_scratch0(); |
| 2241 __ Xorpd(xmm_scratch, xmm_scratch); | 2241 __ Xorpd(xmm_scratch, xmm_scratch); |
| 2242 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); | 2242 __ Ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2243 __ j(zero, instr->FalseLabel(chunk_)); | 2243 __ j(zero, instr->FalseLabel(chunk_)); |
| 2244 __ jmp(instr->TrueLabel(chunk_)); | 2244 __ jmp(instr->TrueLabel(chunk_)); |
| 2245 __ bind(¬_heap_number); | 2245 __ bind(¬_heap_number); |
| 2246 } | 2246 } |
| 2247 | 2247 |
| 2248 if (!expected.IsGeneric()) { | 2248 if (!expected.IsGeneric()) { |
| 2249 // We've seen something for the first time -> deopt. | 2249 // We've seen something for the first time -> deopt. |
| 2250 // This can only happen if we are not generic already. | 2250 // This can only happen if we are not generic already. |
| 2251 DeoptimizeIf(no_condition, instr, Deoptimizer::kUnexpectedObject); | 2251 DeoptimizeIf(no_condition, instr, Deoptimizer::kUnexpectedObject); |
| 2252 } | 2252 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2312 // We can statically evaluate the comparison. | 2312 // We can statically evaluate the comparison. |
| 2313 double left_val = ToDouble(LConstantOperand::cast(left)); | 2313 double left_val = ToDouble(LConstantOperand::cast(left)); |
| 2314 double right_val = ToDouble(LConstantOperand::cast(right)); | 2314 double right_val = ToDouble(LConstantOperand::cast(right)); |
| 2315 int next_block = EvalComparison(instr->op(), left_val, right_val) ? | 2315 int next_block = EvalComparison(instr->op(), left_val, right_val) ? |
| 2316 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); | 2316 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); |
| 2317 EmitGoto(next_block); | 2317 EmitGoto(next_block); |
| 2318 } else { | 2318 } else { |
| 2319 if (instr->is_double()) { | 2319 if (instr->is_double()) { |
| 2320 // Don't base result on EFLAGS when a NaN is involved. Instead | 2320 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 2321 // jump to the false block. | 2321 // jump to the false block. |
| 2322 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 2322 __ Ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 2323 __ j(parity_even, instr->FalseLabel(chunk_)); | 2323 __ j(parity_even, instr->FalseLabel(chunk_)); |
| 2324 } else { | 2324 } else { |
| 2325 int32_t value; | 2325 int32_t value; |
| 2326 if (right->IsConstantOperand()) { | 2326 if (right->IsConstantOperand()) { |
| 2327 value = ToInteger32(LConstantOperand::cast(right)); | 2327 value = ToInteger32(LConstantOperand::cast(right)); |
| 2328 if (instr->hydrogen_value()->representation().IsSmi()) { | 2328 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 2329 __ Cmp(ToRegister(left), Smi::FromInt(value)); | 2329 __ Cmp(ToRegister(left), Smi::FromInt(value)); |
| 2330 } else { | 2330 } else { |
| 2331 __ cmpl(ToRegister(left), Immediate(value)); | 2331 __ cmpl(ToRegister(left), Immediate(value)); |
| 2332 } | 2332 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2380 | 2380 |
| 2381 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { | 2381 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { |
| 2382 if (instr->hydrogen()->representation().IsTagged()) { | 2382 if (instr->hydrogen()->representation().IsTagged()) { |
| 2383 Register input_reg = ToRegister(instr->object()); | 2383 Register input_reg = ToRegister(instr->object()); |
| 2384 __ Cmp(input_reg, factory()->the_hole_value()); | 2384 __ Cmp(input_reg, factory()->the_hole_value()); |
| 2385 EmitBranch(instr, equal); | 2385 EmitBranch(instr, equal); |
| 2386 return; | 2386 return; |
| 2387 } | 2387 } |
| 2388 | 2388 |
| 2389 XMMRegister input_reg = ToDoubleRegister(instr->object()); | 2389 XMMRegister input_reg = ToDoubleRegister(instr->object()); |
| 2390 __ ucomisd(input_reg, input_reg); | 2390 __ Ucomisd(input_reg, input_reg); |
| 2391 EmitFalseBranch(instr, parity_odd); | 2391 EmitFalseBranch(instr, parity_odd); |
| 2392 | 2392 |
| 2393 __ subp(rsp, Immediate(kDoubleSize)); | 2393 __ subp(rsp, Immediate(kDoubleSize)); |
| 2394 __ Movsd(MemOperand(rsp, 0), input_reg); | 2394 __ Movsd(MemOperand(rsp, 0), input_reg); |
| 2395 __ addp(rsp, Immediate(kDoubleSize)); | 2395 __ addp(rsp, Immediate(kDoubleSize)); |
| 2396 | 2396 |
| 2397 int offset = sizeof(kHoleNanUpper32); | 2397 int offset = sizeof(kHoleNanUpper32); |
| 2398 __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32)); | 2398 __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32)); |
| 2399 EmitBranch(instr, equal); | 2399 EmitBranch(instr, equal); |
| 2400 } | 2400 } |
| 2401 | 2401 |
| 2402 | 2402 |
| 2403 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) { | 2403 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) { |
| 2404 Representation rep = instr->hydrogen()->value()->representation(); | 2404 Representation rep = instr->hydrogen()->value()->representation(); |
| 2405 DCHECK(!rep.IsInteger32()); | 2405 DCHECK(!rep.IsInteger32()); |
| 2406 | 2406 |
| 2407 if (rep.IsDouble()) { | 2407 if (rep.IsDouble()) { |
| 2408 XMMRegister value = ToDoubleRegister(instr->value()); | 2408 XMMRegister value = ToDoubleRegister(instr->value()); |
| 2409 XMMRegister xmm_scratch = double_scratch0(); | 2409 XMMRegister xmm_scratch = double_scratch0(); |
| 2410 __ Xorpd(xmm_scratch, xmm_scratch); | 2410 __ Xorpd(xmm_scratch, xmm_scratch); |
| 2411 __ ucomisd(xmm_scratch, value); | 2411 __ Ucomisd(xmm_scratch, value); |
| 2412 EmitFalseBranch(instr, not_equal); | 2412 EmitFalseBranch(instr, not_equal); |
| 2413 __ Movmskpd(kScratchRegister, value); | 2413 __ Movmskpd(kScratchRegister, value); |
| 2414 __ testl(kScratchRegister, Immediate(1)); | 2414 __ testl(kScratchRegister, Immediate(1)); |
| 2415 EmitBranch(instr, not_zero); | 2415 EmitBranch(instr, not_zero); |
| 2416 } else { | 2416 } else { |
| 2417 Register value = ToRegister(instr->value()); | 2417 Register value = ToRegister(instr->value()); |
| 2418 Handle<Map> map = masm()->isolate()->factory()->heap_number_map(); | 2418 Handle<Map> map = masm()->isolate()->factory()->heap_number_map(); |
| 2419 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK); | 2419 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK); |
| 2420 __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset), | 2420 __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset), |
| 2421 Immediate(0x1)); | 2421 Immediate(0x1)); |
| (...skipping 1186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3608 DeoptimizeIf(overflow, instr, Deoptimizer::kMinusZero); | 3608 DeoptimizeIf(overflow, instr, Deoptimizer::kMinusZero); |
| 3609 } | 3609 } |
| 3610 __ roundsd(xmm_scratch, input_reg, kRoundDown); | 3610 __ roundsd(xmm_scratch, input_reg, kRoundDown); |
| 3611 __ Cvttsd2si(output_reg, xmm_scratch); | 3611 __ Cvttsd2si(output_reg, xmm_scratch); |
| 3612 __ cmpl(output_reg, Immediate(0x1)); | 3612 __ cmpl(output_reg, Immediate(0x1)); |
| 3613 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); | 3613 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); |
| 3614 } else { | 3614 } else { |
| 3615 Label negative_sign, done; | 3615 Label negative_sign, done; |
| 3616 // Deoptimize on unordered. | 3616 // Deoptimize on unordered. |
| 3617 __ Xorpd(xmm_scratch, xmm_scratch); // Zero the register. | 3617 __ Xorpd(xmm_scratch, xmm_scratch); // Zero the register. |
| 3618 __ ucomisd(input_reg, xmm_scratch); | 3618 __ Ucomisd(input_reg, xmm_scratch); |
| 3619 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); | 3619 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); |
| 3620 __ j(below, &negative_sign, Label::kNear); | 3620 __ j(below, &negative_sign, Label::kNear); |
| 3621 | 3621 |
| 3622 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3622 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3623 // Check for negative zero. | 3623 // Check for negative zero. |
| 3624 Label positive_sign; | 3624 Label positive_sign; |
| 3625 __ j(above, &positive_sign, Label::kNear); | 3625 __ j(above, &positive_sign, Label::kNear); |
| 3626 __ Movmskpd(output_reg, input_reg); | 3626 __ Movmskpd(output_reg, input_reg); |
| 3627 __ testl(output_reg, Immediate(1)); | 3627 __ testl(output_reg, Immediate(1)); |
| 3628 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); | 3628 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); |
| 3629 __ Set(output_reg, 0); | 3629 __ Set(output_reg, 0); |
| 3630 __ jmp(&done); | 3630 __ jmp(&done); |
| 3631 __ bind(&positive_sign); | 3631 __ bind(&positive_sign); |
| 3632 } | 3632 } |
| 3633 | 3633 |
| 3634 // Use truncating instruction (OK because input is positive). | 3634 // Use truncating instruction (OK because input is positive). |
| 3635 __ Cvttsd2si(output_reg, input_reg); | 3635 __ Cvttsd2si(output_reg, input_reg); |
| 3636 // Overflow is signalled with minint. | 3636 // Overflow is signalled with minint. |
| 3637 __ cmpl(output_reg, Immediate(0x1)); | 3637 __ cmpl(output_reg, Immediate(0x1)); |
| 3638 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); | 3638 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); |
| 3639 __ jmp(&done, Label::kNear); | 3639 __ jmp(&done, Label::kNear); |
| 3640 | 3640 |
| 3641 // Non-zero negative reaches here. | 3641 // Non-zero negative reaches here. |
| 3642 __ bind(&negative_sign); | 3642 __ bind(&negative_sign); |
| 3643 // Truncate, then compare and compensate. | 3643 // Truncate, then compare and compensate. |
| 3644 __ Cvttsd2si(output_reg, input_reg); | 3644 __ Cvttsd2si(output_reg, input_reg); |
| 3645 __ Cvtlsi2sd(xmm_scratch, output_reg); | 3645 __ Cvtlsi2sd(xmm_scratch, output_reg); |
| 3646 __ ucomisd(input_reg, xmm_scratch); | 3646 __ Ucomisd(input_reg, xmm_scratch); |
| 3647 __ j(equal, &done, Label::kNear); | 3647 __ j(equal, &done, Label::kNear); |
| 3648 __ subl(output_reg, Immediate(1)); | 3648 __ subl(output_reg, Immediate(1)); |
| 3649 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); | 3649 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); |
| 3650 | 3650 |
| 3651 __ bind(&done); | 3651 __ bind(&done); |
| 3652 } | 3652 } |
| 3653 } | 3653 } |
| 3654 | 3654 |
| 3655 | 3655 |
| 3656 void LCodeGen::DoMathRound(LMathRound* instr) { | 3656 void LCodeGen::DoMathRound(LMathRound* instr) { |
| 3657 const XMMRegister xmm_scratch = double_scratch0(); | 3657 const XMMRegister xmm_scratch = double_scratch0(); |
| 3658 Register output_reg = ToRegister(instr->result()); | 3658 Register output_reg = ToRegister(instr->result()); |
| 3659 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 3659 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3660 XMMRegister input_temp = ToDoubleRegister(instr->temp()); | 3660 XMMRegister input_temp = ToDoubleRegister(instr->temp()); |
| 3661 static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5 | 3661 static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5 |
| 3662 static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5 | 3662 static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5 |
| 3663 | 3663 |
| 3664 Label done, round_to_zero, below_one_half; | 3664 Label done, round_to_zero, below_one_half; |
| 3665 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; | 3665 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; |
| 3666 __ movq(kScratchRegister, one_half); | 3666 __ movq(kScratchRegister, one_half); |
| 3667 __ Movq(xmm_scratch, kScratchRegister); | 3667 __ Movq(xmm_scratch, kScratchRegister); |
| 3668 __ ucomisd(xmm_scratch, input_reg); | 3668 __ Ucomisd(xmm_scratch, input_reg); |
| 3669 __ j(above, &below_one_half, Label::kNear); | 3669 __ j(above, &below_one_half, Label::kNear); |
| 3670 | 3670 |
| 3671 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). | 3671 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). |
| 3672 __ addsd(xmm_scratch, input_reg); | 3672 __ addsd(xmm_scratch, input_reg); |
| 3673 __ Cvttsd2si(output_reg, xmm_scratch); | 3673 __ Cvttsd2si(output_reg, xmm_scratch); |
| 3674 // Overflow is signalled with minint. | 3674 // Overflow is signalled with minint. |
| 3675 __ cmpl(output_reg, Immediate(0x1)); | 3675 __ cmpl(output_reg, Immediate(0x1)); |
| 3676 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); | 3676 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); |
| 3677 __ jmp(&done, dist); | 3677 __ jmp(&done, dist); |
| 3678 | 3678 |
| 3679 __ bind(&below_one_half); | 3679 __ bind(&below_one_half); |
| 3680 __ movq(kScratchRegister, minus_one_half); | 3680 __ movq(kScratchRegister, minus_one_half); |
| 3681 __ Movq(xmm_scratch, kScratchRegister); | 3681 __ Movq(xmm_scratch, kScratchRegister); |
| 3682 __ ucomisd(xmm_scratch, input_reg); | 3682 __ Ucomisd(xmm_scratch, input_reg); |
| 3683 __ j(below_equal, &round_to_zero, Label::kNear); | 3683 __ j(below_equal, &round_to_zero, Label::kNear); |
| 3684 | 3684 |
| 3685 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then | 3685 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then |
| 3686 // compare and compensate. | 3686 // compare and compensate. |
| 3687 __ Movapd(input_temp, input_reg); // Do not alter input_reg. | 3687 __ Movapd(input_temp, input_reg); // Do not alter input_reg. |
| 3688 __ subsd(input_temp, xmm_scratch); | 3688 __ subsd(input_temp, xmm_scratch); |
| 3689 __ Cvttsd2si(output_reg, input_temp); | 3689 __ Cvttsd2si(output_reg, input_temp); |
| 3690 // Catch minint due to overflow, and to prevent overflow when compensating. | 3690 // Catch minint due to overflow, and to prevent overflow when compensating. |
| 3691 __ cmpl(output_reg, Immediate(0x1)); | 3691 __ cmpl(output_reg, Immediate(0x1)); |
| 3692 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); | 3692 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); |
| 3693 | 3693 |
| 3694 __ Cvtlsi2sd(xmm_scratch, output_reg); | 3694 __ Cvtlsi2sd(xmm_scratch, output_reg); |
| 3695 __ ucomisd(xmm_scratch, input_temp); | 3695 __ Ucomisd(xmm_scratch, input_temp); |
| 3696 __ j(equal, &done, dist); | 3696 __ j(equal, &done, dist); |
| 3697 __ subl(output_reg, Immediate(1)); | 3697 __ subl(output_reg, Immediate(1)); |
| 3698 // No overflow because we already ruled out minint. | 3698 // No overflow because we already ruled out minint. |
| 3699 __ jmp(&done, dist); | 3699 __ jmp(&done, dist); |
| 3700 | 3700 |
| 3701 __ bind(&round_to_zero); | 3701 __ bind(&round_to_zero); |
| 3702 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if | 3702 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if |
| 3703 // we can ignore the difference between a result of -0 and +0. | 3703 // we can ignore the difference between a result of -0 and +0. |
| 3704 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3704 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3705 __ Movq(output_reg, input_reg); | 3705 __ Movq(output_reg, input_reg); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3737 DCHECK(ToDoubleRegister(instr->result()).is(input_reg)); | 3737 DCHECK(ToDoubleRegister(instr->result()).is(input_reg)); |
| 3738 | 3738 |
| 3739 // Note that according to ECMA-262 15.8.2.13: | 3739 // Note that according to ECMA-262 15.8.2.13: |
| 3740 // Math.pow(-Infinity, 0.5) == Infinity | 3740 // Math.pow(-Infinity, 0.5) == Infinity |
| 3741 // Math.sqrt(-Infinity) == NaN | 3741 // Math.sqrt(-Infinity) == NaN |
| 3742 Label done, sqrt; | 3742 Label done, sqrt; |
| 3743 // Check base for -Infinity. According to IEEE-754, double-precision | 3743 // Check base for -Infinity. According to IEEE-754, double-precision |
| 3744 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared. | 3744 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared. |
| 3745 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000)); | 3745 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000)); |
| 3746 __ Movq(xmm_scratch, kScratchRegister); | 3746 __ Movq(xmm_scratch, kScratchRegister); |
| 3747 __ ucomisd(xmm_scratch, input_reg); | 3747 __ Ucomisd(xmm_scratch, input_reg); |
| 3748 // Comparing -Infinity with NaN results in "unordered", which sets the | 3748 // Comparing -Infinity with NaN results in "unordered", which sets the |
| 3749 // zero flag as if both were equal. However, it also sets the carry flag. | 3749 // zero flag as if both were equal. However, it also sets the carry flag. |
| 3750 __ j(not_equal, &sqrt, Label::kNear); | 3750 __ j(not_equal, &sqrt, Label::kNear); |
| 3751 __ j(carry, &sqrt, Label::kNear); | 3751 __ j(carry, &sqrt, Label::kNear); |
| 3752 // If input is -Infinity, return Infinity. | 3752 // If input is -Infinity, return Infinity. |
| 3753 __ Xorpd(input_reg, input_reg); | 3753 __ Xorpd(input_reg, input_reg); |
| 3754 __ subsd(input_reg, xmm_scratch); | 3754 __ subsd(input_reg, xmm_scratch); |
| 3755 __ jmp(&done, Label::kNear); | 3755 __ jmp(&done, Label::kNear); |
| 3756 | 3756 |
| 3757 // Square root. | 3757 // Square root. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3808 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2); | 3808 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2); |
| 3809 } | 3809 } |
| 3810 | 3810 |
| 3811 | 3811 |
| 3812 void LCodeGen::DoMathLog(LMathLog* instr) { | 3812 void LCodeGen::DoMathLog(LMathLog* instr) { |
| 3813 DCHECK(instr->value()->Equals(instr->result())); | 3813 DCHECK(instr->value()->Equals(instr->result())); |
| 3814 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 3814 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3815 XMMRegister xmm_scratch = double_scratch0(); | 3815 XMMRegister xmm_scratch = double_scratch0(); |
| 3816 Label positive, done, zero; | 3816 Label positive, done, zero; |
| 3817 __ Xorpd(xmm_scratch, xmm_scratch); | 3817 __ Xorpd(xmm_scratch, xmm_scratch); |
| 3818 __ ucomisd(input_reg, xmm_scratch); | 3818 __ Ucomisd(input_reg, xmm_scratch); |
| 3819 __ j(above, &positive, Label::kNear); | 3819 __ j(above, &positive, Label::kNear); |
| 3820 __ j(not_carry, &zero, Label::kNear); | 3820 __ j(not_carry, &zero, Label::kNear); |
| 3821 __ pcmpeqd(input_reg, input_reg); | 3821 __ pcmpeqd(input_reg, input_reg); |
| 3822 __ jmp(&done, Label::kNear); | 3822 __ jmp(&done, Label::kNear); |
| 3823 __ bind(&zero); | 3823 __ bind(&zero); |
| 3824 ExternalReference ninf = | 3824 ExternalReference ninf = |
| 3825 ExternalReference::address_of_negative_infinity(); | 3825 ExternalReference::address_of_negative_infinity(); |
| 3826 Operand ninf_operand = masm()->ExternalOperand(ninf); | 3826 Operand ninf_operand = masm()->ExternalOperand(ninf); |
| 3827 __ Movsd(input_reg, ninf_operand); | 3827 __ Movsd(input_reg, ninf_operand); |
| 3828 __ jmp(&done, Label::kNear); | 3828 __ jmp(&done, Label::kNear); |
| (...skipping 1088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4917 | 4917 |
| 4918 if (can_convert_undefined_to_nan) { | 4918 if (can_convert_undefined_to_nan) { |
| 4919 __ j(not_equal, &convert, Label::kNear); | 4919 __ j(not_equal, &convert, Label::kNear); |
| 4920 } else { | 4920 } else { |
| 4921 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); | 4921 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); |
| 4922 } | 4922 } |
| 4923 | 4923 |
| 4924 if (deoptimize_on_minus_zero) { | 4924 if (deoptimize_on_minus_zero) { |
| 4925 XMMRegister xmm_scratch = double_scratch0(); | 4925 XMMRegister xmm_scratch = double_scratch0(); |
| 4926 __ Xorpd(xmm_scratch, xmm_scratch); | 4926 __ Xorpd(xmm_scratch, xmm_scratch); |
| 4927 __ ucomisd(xmm_scratch, result_reg); | 4927 __ Ucomisd(xmm_scratch, result_reg); |
| 4928 __ j(not_equal, &done, Label::kNear); | 4928 __ j(not_equal, &done, Label::kNear); |
| 4929 __ Movmskpd(kScratchRegister, result_reg); | 4929 __ Movmskpd(kScratchRegister, result_reg); |
| 4930 __ testl(kScratchRegister, Immediate(1)); | 4930 __ testl(kScratchRegister, Immediate(1)); |
| 4931 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); | 4931 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); |
| 4932 } | 4932 } |
| 4933 __ jmp(&done, Label::kNear); | 4933 __ jmp(&done, Label::kNear); |
| 4934 | 4934 |
| 4935 if (can_convert_undefined_to_nan) { | 4935 if (can_convert_undefined_to_nan) { |
| 4936 __ bind(&convert); | 4936 __ bind(&convert); |
| 4937 | 4937 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4988 __ Set(input_reg, 0); | 4988 __ Set(input_reg, 0); |
| 4989 } else { | 4989 } else { |
| 4990 XMMRegister scratch = ToDoubleRegister(instr->temp()); | 4990 XMMRegister scratch = ToDoubleRegister(instr->temp()); |
| 4991 DCHECK(!scratch.is(xmm0)); | 4991 DCHECK(!scratch.is(xmm0)); |
| 4992 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), | 4992 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 4993 Heap::kHeapNumberMapRootIndex); | 4993 Heap::kHeapNumberMapRootIndex); |
| 4994 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); | 4994 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); |
| 4995 __ Movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 4995 __ Movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 4996 __ Cvttsd2si(input_reg, xmm0); | 4996 __ Cvttsd2si(input_reg, xmm0); |
| 4997 __ Cvtlsi2sd(scratch, input_reg); | 4997 __ Cvtlsi2sd(scratch, input_reg); |
| 4998 __ ucomisd(xmm0, scratch); | 4998 __ Ucomisd(xmm0, scratch); |
| 4999 DeoptimizeIf(not_equal, instr, Deoptimizer::kLostPrecision); | 4999 DeoptimizeIf(not_equal, instr, Deoptimizer::kLostPrecision); |
| 5000 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); | 5000 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); |
| 5001 if (instr->hydrogen()->GetMinusZeroMode() == FAIL_ON_MINUS_ZERO) { | 5001 if (instr->hydrogen()->GetMinusZeroMode() == FAIL_ON_MINUS_ZERO) { |
| 5002 __ testl(input_reg, input_reg); | 5002 __ testl(input_reg, input_reg); |
| 5003 __ j(not_zero, done); | 5003 __ j(not_zero, done); |
| 5004 __ Movmskpd(input_reg, xmm0); | 5004 __ Movmskpd(input_reg, xmm0); |
| 5005 __ andl(input_reg, Immediate(1)); | 5005 __ andl(input_reg, Immediate(1)); |
| 5006 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); | 5006 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); |
| 5007 } | 5007 } |
| 5008 } | 5008 } |
| (...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5904 RecordSafepoint(Safepoint::kNoLazyDeopt); | 5904 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 5905 } | 5905 } |
| 5906 | 5906 |
| 5907 | 5907 |
| 5908 #undef __ | 5908 #undef __ |
| 5909 | 5909 |
| 5910 } // namespace internal | 5910 } // namespace internal |
| 5911 } // namespace v8 | 5911 } // namespace v8 |
| 5912 | 5912 |
| 5913 #endif // V8_TARGET_ARCH_X64 | 5913 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |