OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1323 __ bind(&runtime_call); | 1323 __ bind(&runtime_call); |
1324 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | 1324 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
1325 } | 1325 } |
1326 | 1326 |
1327 | 1327 |
1328 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 1328 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
1329 switch (type_) { | 1329 switch (type_) { |
1330 // Add more cases when necessary. | 1330 // Add more cases when necessary. |
1331 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 1331 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
1332 case TranscendentalCache::COS: return Runtime::kMath_cos; | 1332 case TranscendentalCache::COS: return Runtime::kMath_cos; |
| 1333 case TranscendentalCache::LOG: return Runtime::kMath_log; |
1333 default: | 1334 default: |
1334 UNIMPLEMENTED(); | 1335 UNIMPLEMENTED(); |
1335 return Runtime::kAbort; | 1336 return Runtime::kAbort; |
1336 } | 1337 } |
1337 } | 1338 } |
1338 | 1339 |
1339 | 1340 |
1340 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { | 1341 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { |
1341 // Only free register is edi. | 1342 // Only free register is edi. |
| 1343 // Input value is on FP stack, and also in ebx/edx. Address of result |
| 1344 // (a newly allocated HeapNumber) is in eax. |
1342 NearLabel done; | 1345 NearLabel done; |
1343 ASSERT(type_ == TranscendentalCache::SIN || | 1346 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { |
1344 type_ == TranscendentalCache::COS); | 1347 // Both fsin and fcos require arguments in the range +/-2^63 and |
1345 // More transcendental types can be added later. | 1348 // return NaN for infinities and NaN. They can share all code except |
| 1349 // the actual fsin/fcos operation. |
| 1350 NearLabel in_range; |
| 1351 // If argument is outside the range -2^63..2^63, fsin/cos doesn't |
| 1352 // work. We must reduce it to the appropriate range. |
| 1353 __ mov(edi, edx); |
| 1354 __ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only. |
| 1355 int supported_exponent_limit = |
| 1356 (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; |
| 1357 __ cmp(Operand(edi), Immediate(supported_exponent_limit)); |
| 1358 __ j(below, &in_range, taken); |
| 1359 // Check for infinity and NaN. Both return NaN for sin. |
| 1360 __ cmp(Operand(edi), Immediate(0x7ff00000)); |
| 1361 NearLabel non_nan_result; |
| 1362 __ j(not_equal, &non_nan_result, taken); |
| 1363 // Input is +/-Infinity or NaN. Result is NaN. |
| 1364 __ fstp(0); |
| 1365 // NaN is represented by 0x7ff8000000000000. |
| 1366 __ push(Immediate(0x7ff80000)); |
| 1367 __ push(Immediate(0)); |
| 1368 __ fld_d(Operand(esp, 0)); |
| 1369 __ add(Operand(esp), Immediate(2 * kPointerSize)); |
| 1370 __ jmp(&done); |
1346 | 1371 |
1347 // Both fsin and fcos require arguments in the range +/-2^63 and | 1372 __ bind(&non_nan_result); |
1348 // return NaN for infinities and NaN. They can share all code except | |
1349 // the actual fsin/fcos operation. | |
1350 NearLabel in_range; | |
1351 // If argument is outside the range -2^63..2^63, fsin/cos doesn't | |
1352 // work. We must reduce it to the appropriate range. | |
1353 __ mov(edi, edx); | |
1354 __ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only. | |
1355 int supported_exponent_limit = | |
1356 (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; | |
1357 __ cmp(Operand(edi), Immediate(supported_exponent_limit)); | |
1358 __ j(below, &in_range, taken); | |
1359 // Check for infinity and NaN. Both return NaN for sin. | |
1360 __ cmp(Operand(edi), Immediate(0x7ff00000)); | |
1361 NearLabel non_nan_result; | |
1362 __ j(not_equal, &non_nan_result, taken); | |
1363 // Input is +/-Infinity or NaN. Result is NaN. | |
1364 __ fstp(0); | |
1365 // NaN is represented by 0x7ff8000000000000. | |
1366 __ push(Immediate(0x7ff80000)); | |
1367 __ push(Immediate(0)); | |
1368 __ fld_d(Operand(esp, 0)); | |
1369 __ add(Operand(esp), Immediate(2 * kPointerSize)); | |
1370 __ jmp(&done); | |
1371 | 1373 |
1372 __ bind(&non_nan_result); | 1374 // Use fpmod to restrict argument to the range +/-2*PI. |
| 1375 __ mov(edi, eax); // Save eax before using fnstsw_ax. |
| 1376 __ fldpi(); |
| 1377 __ fadd(0); |
| 1378 __ fld(1); |
| 1379 // FPU Stack: input, 2*pi, input. |
| 1380 { |
| 1381 NearLabel no_exceptions; |
| 1382 __ fwait(); |
| 1383 __ fnstsw_ax(); |
| 1384 // Clear if Illegal Operand or Zero Division exceptions are set. |
| 1385 __ test(Operand(eax), Immediate(5)); |
| 1386 __ j(zero, &no_exceptions); |
| 1387 __ fnclex(); |
| 1388 __ bind(&no_exceptions); |
| 1389 } |
1373 | 1390 |
1374 // Use fpmod to restrict argument to the range +/-2*PI. | 1391 // Compute st(0) % st(1) |
1375 __ mov(edi, eax); // Save eax before using fnstsw_ax. | 1392 { |
1376 __ fldpi(); | 1393 NearLabel partial_remainder_loop; |
1377 __ fadd(0); | 1394 __ bind(&partial_remainder_loop); |
1378 __ fld(1); | 1395 __ fprem1(); |
1379 // FPU Stack: input, 2*pi, input. | 1396 __ fwait(); |
1380 { | 1397 __ fnstsw_ax(); |
1381 NearLabel no_exceptions; | 1398 __ test(Operand(eax), Immediate(0x400 /* C2 */)); |
1382 __ fwait(); | 1399 // If C2 is set, computation only has partial result. Loop to |
1383 __ fnstsw_ax(); | 1400 // continue computation. |
1384 // Clear if Illegal Operand or Zero Division exceptions are set. | 1401 __ j(not_zero, &partial_remainder_loop); |
1385 __ test(Operand(eax), Immediate(5)); | 1402 } |
1386 __ j(zero, &no_exceptions); | 1403 // FPU Stack: input, 2*pi, input % 2*pi |
1387 __ fnclex(); | 1404 __ fstp(2); |
1388 __ bind(&no_exceptions); | 1405 __ fstp(0); |
| 1406 __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). |
| 1407 |
| 1408 // FPU Stack: input % 2*pi |
| 1409 __ bind(&in_range); |
| 1410 switch (type_) { |
| 1411 case TranscendentalCache::SIN: |
| 1412 __ fsin(); |
| 1413 break; |
| 1414 case TranscendentalCache::COS: |
| 1415 __ fcos(); |
| 1416 break; |
| 1417 default: |
| 1418 UNREACHABLE(); |
| 1419 } |
| 1420 __ bind(&done); |
| 1421 } else { |
| 1422 ASSERT(type_ == TranscendentalCache::LOG); |
| 1423 __ fldln2(); |
| 1424 __ fxch(); |
| 1425 __ fyl2x(); |
1389 } | 1426 } |
1390 | |
1391 // Compute st(0) % st(1) | |
1392 { | |
1393 NearLabel partial_remainder_loop; | |
1394 __ bind(&partial_remainder_loop); | |
1395 __ fprem1(); | |
1396 __ fwait(); | |
1397 __ fnstsw_ax(); | |
1398 __ test(Operand(eax), Immediate(0x400 /* C2 */)); | |
1399 // If C2 is set, computation only has partial result. Loop to | |
1400 // continue computation. | |
1401 __ j(not_zero, &partial_remainder_loop); | |
1402 } | |
1403 // FPU Stack: input, 2*pi, input % 2*pi | |
1404 __ fstp(2); | |
1405 __ fstp(0); | |
1406 __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). | |
1407 | |
1408 // FPU Stack: input % 2*pi | |
1409 __ bind(&in_range); | |
1410 switch (type_) { | |
1411 case TranscendentalCache::SIN: | |
1412 __ fsin(); | |
1413 break; | |
1414 case TranscendentalCache::COS: | |
1415 __ fcos(); | |
1416 break; | |
1417 default: | |
1418 UNREACHABLE(); | |
1419 } | |
1420 __ bind(&done); | |
1421 } | 1427 } |
1422 | 1428 |
1423 | 1429 |
1424 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 1430 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
1425 // is faster than using the built-in instructions on floating point registers. | 1431 // is faster than using the built-in instructions on floating point registers. |
1426 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 1432 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
1427 // trashed registers. | 1433 // trashed registers. |
1428 void IntegerConvert(MacroAssembler* masm, | 1434 void IntegerConvert(MacroAssembler* masm, |
1429 Register source, | 1435 Register source, |
1430 TypeInfo type_info, | 1436 TypeInfo type_info, |
(...skipping 3140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4571 // tagged as a small integer. | 4577 // tagged as a small integer. |
4572 __ bind(&runtime); | 4578 __ bind(&runtime); |
4573 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4579 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
4574 } | 4580 } |
4575 | 4581 |
4576 #undef __ | 4582 #undef __ |
4577 | 4583 |
4578 } } // namespace v8::internal | 4584 } } // namespace v8::internal |
4579 | 4585 |
4580 #endif // V8_TARGET_ARCH_IA32 | 4586 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |