Commit d5fdb760 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Implement Math.pow using FPU instructions and inline it in crankshaft (ia32).

Review URL: http://codereview.chromium.org/8749002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10133 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8f7a1f78
......@@ -2938,7 +2938,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
MathPowStub stub;
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(r0);
}
......
......@@ -1113,6 +1113,9 @@ double power_double_int(double x, int y) {
double power_double_double(double x, double y) {
// The checks for special cases can be dropped in ia32 because it has already
// been done in generated code before bailing out here.
#if !defined(V8_TARGET_ARCH_IA32)
int y_int = static_cast<int>(y);
if (y == y_int) {
return power_double_int(x, y_int); // Returns 1.0 for exponent 0.
......@@ -1121,6 +1124,7 @@ double power_double_double(double x, double y) {
if (y == 0.5) return sqrt(x + 0.0); // -0 must be converted to +0.
if (y == -0.5) return 1.0 / sqrt(x + 0.0);
}
#endif
if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
return OS::nan_value();
}
......
......@@ -442,12 +442,17 @@ class InstanceofStub: public CodeStub {
class MathPowStub: public CodeStub {
public:
MathPowStub() {}
enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK};
explicit MathPowStub(ExponentType exponent_type)
: exponent_type_(exponent_type) { }
virtual void Generate(MacroAssembler* masm);
private:
virtual CodeStub::Major MajorKey() { return MathPow; }
virtual int MinorKey() { return 0; }
virtual int MinorKey() { return exponent_type_; }
ExponentType exponent_type_;
};
......
......@@ -1640,6 +1640,27 @@ void Assembler::fyl2x() {
}
void Assembler::f2xm1() {
EnsureSpace ensure_space(this);
EMIT(0xD9);
EMIT(0xF0);
}
void Assembler::fscale() {
EnsureSpace ensure_space(this);
EMIT(0xD9);
EMIT(0xFD);
}
void Assembler::fninit() {
EnsureSpace ensure_space(this);
EMIT(0xDB);
EMIT(0xE3);
}
void Assembler::fadd(int i) {
EnsureSpace ensure_space(this);
emit_farith(0xDC, 0xC0, i);
......@@ -2158,6 +2179,19 @@ void Assembler::movd(const Operand& dst, XMMRegister src) {
}
void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
ASSERT(CpuFeatures::IsSupported(SSE4_1));
ASSERT(is_uint8(imm8));
EnsureSpace ensure_space(this);
EMIT(0x66);
EMIT(0x0F);
EMIT(0x3A);
EMIT(0x17);
emit_sse_operand(dst, src);
EMIT(imm8);
}
void Assembler::pand(XMMRegister dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
......
......@@ -926,6 +926,9 @@ class Assembler : public AssemblerBase {
void fsin();
void fptan();
void fyl2x();
void f2xm1();
void fscale();
void fninit();
void fadd(int i);
void fsub(int i);
......@@ -1017,6 +1020,7 @@ class Assembler : public AssemblerBase {
void movss(XMMRegister dst, const Operand& src);
void movss(const Operand& dst, XMMRegister src);
void movss(XMMRegister dst, XMMRegister src);
void extractps(Register dst, XMMRegister src, byte imm8);
void pand(XMMRegister dst, XMMRegister src);
void pxor(XMMRegister dst, XMMRegister src);
......
This diff is collapsed.
......@@ -763,10 +763,13 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
case 0xEB: mnem = "fldpi"; break;
case 0xED: mnem = "fldln2"; break;
case 0xEE: mnem = "fldz"; break;
case 0xF0: mnem = "f2xm1"; break;
case 0xF1: mnem = "fyl2x"; break;
case 0xF5: mnem = "fprem1"; break;
case 0xF7: mnem = "fincstp"; break;
case 0xF8: mnem = "fprem"; break;
case 0xFC: mnem = "frndint"; break;
case 0xFD: mnem = "fscale"; break;
case 0xFE: mnem = "fsin"; break;
case 0xFF: mnem = "fcos"; break;
default: UnimplementedInstruction();
......@@ -788,6 +791,8 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
has_register = true;
} else if (modrm_byte == 0xE2) {
mnem = "fclex";
} else if (modrm_byte == 0xE3) {
mnem = "fninit";
} else {
UnimplementedInstruction();
}
......@@ -1185,6 +1190,16 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
} else if (*data == 0x17){
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
int8_t imm8 = static_cast<int8_t>(data[1]);
AppendToBuffer("extractps %s,%s,%d",
NameOfCPURegister(regop),
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
} else if (*data == 0x22) {
data++;
int mod, regop, rm;
......
......@@ -2883,7 +2883,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
VisitForStackValue(args->at(1));
if (CpuFeatures::IsSupported(SSE2)) {
MathPowStub stub;
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kMath_pow, 2);
......
......@@ -2945,61 +2945,32 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
void LCodeGen::DoPower(LPower* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
DoubleRegister result_reg = ToDoubleRegister(instr->result());
Representation exponent_type = instr->hydrogen()->right()->representation();
if (exponent_type.IsDouble()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
__ CallCFunction(ExternalReference::power_double_double_function(isolate()),
4);
// Having marked this as a call, we can use any registers.
// Just make sure that the input registers are the expected ones.
ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
ToDoubleRegister(instr->InputAt(1)).is(xmm2));
ASSERT(!instr->InputAt(1)->IsRegister() ||
ToRegister(instr->InputAt(1)).is(eax));
ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm1));
ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
if (exponent_type.IsTagged()) {
Label no_deopt;
__ JumpIfSmi(eax, &no_deopt);
__ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
DeoptimizeIf(not_equal, instr->environment());
__ bind(&no_deopt);
MathPowStub stub(MathPowStub::TAGGED);
__ CallStub(&stub);
} else if (exponent_type.IsInteger32()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
ASSERT(!ToRegister(right).is(ebx));
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
__ CallCFunction(ExternalReference::power_double_int_function(isolate()),
4);
MathPowStub stub(MathPowStub::INTEGER);
__ CallStub(&stub);
} else {
ASSERT(exponent_type.IsTagged());
CpuFeatures::Scope scope(SSE2);
Register right_reg = ToRegister(right);
Label non_smi, call;
__ JumpIfNotSmi(right_reg, &non_smi);
__ SmiUntag(right_reg);
__ cvtsi2sd(result_reg, Operand(right_reg));
__ jmp(&call);
__ bind(&non_smi);
// It is safe to use ebx directly since the instruction is marked
// as a call.
ASSERT(!right_reg.is(ebx));
__ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
DeoptimizeIf(not_equal, instr->environment());
__ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
__ bind(&call);
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
__ CallCFunction(ExternalReference::power_double_double_function(isolate()),
4);
ASSERT(exponent_type.IsDouble());
MathPowStub stub(MathPowStub::DOUBLE);
__ CallStub(&stub);
}
// Return value is in st(0) on ia32.
// Store it into the (fixed) result register.
__ sub(Operand(esp), Immediate(kDoubleSize));
__ fstp_d(Operand(esp, 0));
__ movdbl(result_reg, Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
}
......
......@@ -2958,7 +2958,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
MathPowStub stub;
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(v0);
}
......
......@@ -2572,7 +2572,8 @@ void Assembler::movdqa(XMMRegister dst, const Operand& src) {
void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
ASSERT(is_uint2(imm8));
ASSERT(CpuFeatures::IsSupported(SSE4_1));
ASSERT(is_uint8(imm8));
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(dst, src);
......
......@@ -2820,7 +2820,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
MathPowStub stub;
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(rax);
}
......
......@@ -25,118 +25,127 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Tests the special cases specified by ES 15.8.2.13
// Simple sanity check
assertEquals(4, Math.pow(2, 2));
assertEquals(2147483648, Math.pow(2, 31));
assertEquals(0.25, Math.pow(2, -2));
assertEquals(0.0625, Math.pow(2, -4));
assertEquals(1, Math.pow(1, 100));
assertEquals(0, Math.pow(0, 1000));
// Spec tests
assertEquals(NaN, Math.pow(2, NaN));
assertEquals(NaN, Math.pow(+0, NaN));
assertEquals(NaN, Math.pow(-0, NaN));
assertEquals(NaN, Math.pow(Infinity, NaN));
assertEquals(NaN, Math.pow(-Infinity, NaN));
assertEquals(1, Math.pow(NaN, +0));
assertEquals(1, Math.pow(NaN, -0));
assertEquals(NaN, Math.pow(NaN, NaN));
assertEquals(NaN, Math.pow(NaN, 2.2));
assertEquals(NaN, Math.pow(NaN, 1));
assertEquals(NaN, Math.pow(NaN, -1));
assertEquals(NaN, Math.pow(NaN, -2.2));
assertEquals(NaN, Math.pow(NaN, Infinity));
assertEquals(NaN, Math.pow(NaN, -Infinity));
assertEquals(Infinity, Math.pow(1.1, Infinity));
assertEquals(Infinity, Math.pow(-1.1, Infinity));
assertEquals(Infinity, Math.pow(2, Infinity));
assertEquals(Infinity, Math.pow(-2, Infinity));
// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity
assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity));
assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity));
assertEquals(+Infinity, 1/Math.pow(2, -Infinity));
assertEquals(+Infinity, 1/Math.pow(-2, -Infinity));
assertEquals(NaN, Math.pow(1, Infinity));
assertEquals(NaN, Math.pow(1, -Infinity));
assertEquals(NaN, Math.pow(-1, Infinity));
assertEquals(NaN, Math.pow(-1, -Infinity));
assertEquals(+0, Math.pow(0.1, Infinity));
assertEquals(+0, Math.pow(-0.1, Infinity));
assertEquals(+0, Math.pow(0.999, Infinity));
assertEquals(+0, Math.pow(-0.999, Infinity));
assertEquals(Infinity, Math.pow(0.1, -Infinity));
assertEquals(Infinity, Math.pow(-0.1, -Infinity));
assertEquals(Infinity, Math.pow(0.999, -Infinity));
assertEquals(Infinity, Math.pow(-0.999, -Infinity));
assertEquals(Infinity, Math.pow(Infinity, 0.1));
assertEquals(Infinity, Math.pow(Infinity, 2));
assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1));
assertEquals(+Infinity, 1/Math.pow(Infinity, -2));
assertEquals(-Infinity, Math.pow(-Infinity, 3));
assertEquals(-Infinity, Math.pow(-Infinity, 13));
assertEquals(Infinity, Math.pow(-Infinity, 3.1));
assertEquals(Infinity, Math.pow(-Infinity, 2));
assertEquals(-Infinity, 1/Math.pow(-Infinity, -3));
assertEquals(-Infinity, 1/Math.pow(-Infinity, -13));
assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1));
assertEquals(+Infinity, 1/Math.pow(-Infinity, -2));
assertEquals(+Infinity, 1/Math.pow(+0, 1.1));
assertEquals(+Infinity, 1/Math.pow(+0, 2));
assertEquals(Infinity, Math.pow(+0, -1.1));
assertEquals(Infinity, Math.pow(+0, -2));
assertEquals(-Infinity, 1/Math.pow(-0, 3));
assertEquals(-Infinity, 1/Math.pow(-0, 13));
assertEquals(+Infinity, 1/Math.pow(-0, 3.1));
assertEquals(+Infinity, 1/Math.pow(-0, 2));
assertEquals(-Infinity, Math.pow(-0, -3));
assertEquals(-Infinity, Math.pow(-0, -13));
assertEquals(Infinity, Math.pow(-0, -3.1));
assertEquals(Infinity, Math.pow(-0, -2));
assertEquals(NaN, Math.pow(-0.00001, 1.1));
assertEquals(NaN, Math.pow(-0.00001, -1.1));
assertEquals(NaN, Math.pow(-1.1, 1.1));
assertEquals(NaN, Math.pow(-1.1, -1.1));
assertEquals(NaN, Math.pow(-2, 1.1));
assertEquals(NaN, Math.pow(-2, -1.1));
assertEquals(NaN, Math.pow(-1000, 1.1));
assertEquals(NaN, Math.pow(-1000, -1.1));
assertEquals(+Infinity, 1/Math.pow(-0, 0.5));
assertEquals(+Infinity, 1/Math.pow(-0, 0.6));
assertEquals(-Infinity, 1/Math.pow(-0, 1));
assertEquals(-Infinity, 1/Math.pow(-0, 10000000001));
assertEquals(+Infinity, Math.pow(-0, -0.5));
assertEquals(+Infinity, Math.pow(-0, -0.6));
assertEquals(-Infinity, Math.pow(-0, -1));
assertEquals(-Infinity, Math.pow(-0, -10000000001));
// Tests from Sputnik S8.5_A13_T1.
assertTrue((1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308);
assertTrue((1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308);
assertTrue((-1*(Math.pow(2,52))*(Math.pow(2,-1074))) === -2.2250738585072014e-308);
function test() {
// Simple sanity check
assertEquals(4, Math.pow(2, 2));
assertEquals(2147483648, Math.pow(2, 31));
assertEquals(0.25, Math.pow(2, -2));
assertEquals(0.0625, Math.pow(2, -4));
assertEquals(1, Math.pow(1, 100));
assertEquals(0, Math.pow(0, 1000));
// Spec tests
assertEquals(NaN, Math.pow(2, NaN));
assertEquals(NaN, Math.pow(+0, NaN));
assertEquals(NaN, Math.pow(-0, NaN));
assertEquals(NaN, Math.pow(Infinity, NaN));
assertEquals(NaN, Math.pow(-Infinity, NaN));
assertEquals(1, Math.pow(NaN, +0));
assertEquals(1, Math.pow(NaN, -0));
assertEquals(NaN, Math.pow(NaN, NaN));
assertEquals(NaN, Math.pow(NaN, 2.2));
assertEquals(NaN, Math.pow(NaN, 1));
assertEquals(NaN, Math.pow(NaN, -1));
assertEquals(NaN, Math.pow(NaN, -2.2));
assertEquals(NaN, Math.pow(NaN, Infinity));
assertEquals(NaN, Math.pow(NaN, -Infinity));
assertEquals(Infinity, Math.pow(1.1, Infinity));
assertEquals(Infinity, Math.pow(-1.1, Infinity));
assertEquals(Infinity, Math.pow(2, Infinity));
assertEquals(Infinity, Math.pow(-2, Infinity));
// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity
assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity));
assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity));
assertEquals(+Infinity, 1/Math.pow(2, -Infinity));
assertEquals(+Infinity, 1/Math.pow(-2, -Infinity));
assertEquals(NaN, Math.pow(1, Infinity));
assertEquals(NaN, Math.pow(1, -Infinity));
assertEquals(NaN, Math.pow(-1, Infinity));
assertEquals(NaN, Math.pow(-1, -Infinity));
assertEquals(+0, Math.pow(0.1, Infinity));
assertEquals(+0, Math.pow(-0.1, Infinity));
assertEquals(+0, Math.pow(0.999, Infinity));
assertEquals(+0, Math.pow(-0.999, Infinity));
assertEquals(Infinity, Math.pow(0.1, -Infinity));
assertEquals(Infinity, Math.pow(-0.1, -Infinity));
assertEquals(Infinity, Math.pow(0.999, -Infinity));
assertEquals(Infinity, Math.pow(-0.999, -Infinity));
assertEquals(Infinity, Math.pow(Infinity, 0.1));
assertEquals(Infinity, Math.pow(Infinity, 2));
assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1));
assertEquals(+Infinity, 1/Math.pow(Infinity, -2));
assertEquals(-Infinity, Math.pow(-Infinity, 3));
assertEquals(-Infinity, Math.pow(-Infinity, 13));
assertEquals(Infinity, Math.pow(-Infinity, 3.1));
assertEquals(Infinity, Math.pow(-Infinity, 2));
assertEquals(-Infinity, 1/Math.pow(-Infinity, -3));
assertEquals(-Infinity, 1/Math.pow(-Infinity, -13));
assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1));
assertEquals(+Infinity, 1/Math.pow(-Infinity, -2));
assertEquals(+Infinity, 1/Math.pow(+0, 1.1));
assertEquals(+Infinity, 1/Math.pow(+0, 2));
assertEquals(Infinity, Math.pow(+0, -1.1));
assertEquals(Infinity, Math.pow(+0, -2));
assertEquals(-Infinity, 1/Math.pow(-0, 3));
assertEquals(-Infinity, 1/Math.pow(-0, 13));
assertEquals(+Infinity, 1/Math.pow(-0, 3.1));
assertEquals(+Infinity, 1/Math.pow(-0, 2));
assertEquals(-Infinity, Math.pow(-0, -3));
assertEquals(-Infinity, Math.pow(-0, -13));
assertEquals(Infinity, Math.pow(-0, -3.1));
assertEquals(Infinity, Math.pow(-0, -2));
assertEquals(NaN, Math.pow(-0.00001, 1.1));
assertEquals(NaN, Math.pow(-0.00001, -1.1));
assertEquals(NaN, Math.pow(-1.1, 1.1));
assertEquals(NaN, Math.pow(-1.1, -1.1));
assertEquals(NaN, Math.pow(-2, 1.1));
assertEquals(NaN, Math.pow(-2, -1.1));
assertEquals(NaN, Math.pow(-1000, 1.1));
assertEquals(NaN, Math.pow(-1000, -1.1));
assertEquals(+Infinity, 1/Math.pow(-0, 0.5));
assertEquals(+Infinity, 1/Math.pow(-0, 0.6));
assertEquals(-Infinity, 1/Math.pow(-0, 1));
assertEquals(-Infinity, 1/Math.pow(-0, 10000000001));
assertEquals(+Infinity, Math.pow(-0, -0.5));
assertEquals(+Infinity, Math.pow(-0, -0.6));
assertEquals(-Infinity, Math.pow(-0, -1));
assertEquals(-Infinity, Math.pow(-0, -10000000001));
// Tests from Sputnik S8.5_A13_T1.
assertTrue(
(1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308);
assertTrue(
(1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308);
assertTrue(
(-1*(Math.pow(2,52))*(Math.pow(2,-1074))) === -2.2250738585072014e-308);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment