From 42879d10388b1f354c2db1dc048ff33e8da6d811 Mon Sep 17 00:00:00 2001 From: "olivf@chromium.org" Date: Mon, 16 Sep 2013 15:24:49 +0000 Subject: [PATCH] Orthogonalize Lithium binary op instructions. BUG= R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/23703014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16739 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-arm.cc | 128 ++++++++++++++----------------- src/arm/lithium-arm.h | 4 +- src/arm/lithium-codegen-arm.cc | 20 +++-- src/ia32/lithium-codegen-ia32.cc | 24 +++--- src/ia32/lithium-ia32.cc | 120 +++++++++++------------------ src/ia32/lithium-ia32.h | 4 +- src/x64/lithium-codegen-x64.cc | 14 ++-- src/x64/lithium-x64.cc | 114 +++++++++++---------------- src/x64/lithium-x64.h | 4 +- 9 files changed, 185 insertions(+), 247 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index d3ac5e0dfe..ffadada845 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -710,51 +710,44 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { LInstruction* LChunkBuilder::DoShift(Token::Value op, HBitwiseBinaryOperation* instr) { - if (instr->representation().IsTagged()) { - ASSERT(instr->left()->representation().IsTagged()); - ASSERT(instr->right()->representation().IsTagged()); + if (instr->representation().IsSmiOrInteger32()) { + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* left = UseFixed(instr->left(), r1); - LOperand* right = UseFixed(instr->right(), r0); - LArithmeticT* result = new(zone()) LArithmeticT(op, left, right); - return MarkAsCall(DefineFixed(result, r0), instr); - } - - ASSERT(instr->representation().IsSmiOrInteger32()); - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); - LOperand* left = UseRegisterAtStart(instr->left()); - - HValue* right_value = instr->right(); - LOperand* right = NULL; - int constant_value = 0; - bool does_deopt = false; - if (right_value->IsConstant()) { - HConstant* constant = HConstant::cast(right_value); - right = chunk_->DefineConstantOperand(constant); - constant_value = constant->Integer32Value() & 0x1f; - // Left shifts can deoptimize if we shift by > 0 and the result cannot be - // truncated to smi. - if (instr->representation().IsSmi() && constant_value > 0) { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); - } - } else { - right = UseRegisterAtStart(right_value); - } - - // Shift operations can only deoptimize if we do a logical shift - // by 0 and the result cannot be truncated to int32. - if (op == Token::SHR && constant_value == 0) { - if (FLAG_opt_safe_uint32_operations) { - does_deopt = !instr->CheckFlag(HInstruction::kUint32); + HValue* right_value = instr->right(); + LOperand* right = NULL; + int constant_value = 0; + bool does_deopt = false; + if (right_value->IsConstant()) { + HConstant* constant = HConstant::cast(right_value); + right = chunk_->DefineConstantOperand(constant); + constant_value = constant->Integer32Value() & 0x1f; + // Left shifts can deoptimize if we shift by > 0 and the result cannot be + // truncated to smi. + if (instr->representation().IsSmi() && constant_value > 0) { + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); + } } else { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + right = UseRegisterAtStart(right_value); } - } - LInstruction* result = - DefineAsRegister(new(zone()) LShiftI(op, left, right, does_deopt)); - return does_deopt ? AssignEnvironment(result) : result; + // Shift operations can only deoptimize if we do a logical shift + // by 0 and the result cannot be truncated to int32. + if (op == Token::SHR && constant_value == 0) { + if (FLAG_opt_safe_uint32_operations) { + does_deopt = !instr->CheckFlag(HInstruction::kUint32); + } else { + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + } + } + + LInstruction* result = + DefineAsRegister(new(zone()) LShiftI(op, left, right, does_deopt)); + return does_deopt ? AssignEnvironment(result) : result; + } else { + return DoArithmeticT(op, instr); + } } @@ -763,21 +756,26 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, ASSERT(instr->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble()); - ASSERT(op != Token::MOD); - LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* right = UseRegisterAtStart(instr->right()); + LOperand* left = NULL; + LOperand* right = NULL; + if (op == Token::MOD) { + left = UseFixedDouble(instr->left(), d1); + right = UseFixedDouble(instr->right(), d2); + LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); + // We call a C function for double modulo. It can't trigger a GC. We need + // to use fixed result register for the call. + // TODO(fschneider): Allow any register as input registers. + return MarkAsCall(DefineFixedDouble(result, d1), instr); + } + left = UseRegisterAtStart(instr->left()); + right = UseRegisterAtStart(instr->right()); LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); return DefineAsRegister(result); } LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr) { - ASSERT(op == Token::ADD || - op == Token::DIV || - op == Token::MOD || - op == Token::MUL || - op == Token::SUB); + HBinaryOperation* instr) { HValue* left = instr->left(); HValue* right = instr->right(); ASSERT(left->representation().IsTagged()); @@ -1347,27 +1345,19 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); return DefineAsRegister(new(zone()) LBitI(left, right)); } else { - ASSERT(instr->representation().IsTagged()); - ASSERT(instr->left()->representation().IsTagged()); - ASSERT(instr->right()->representation().IsTagged()); - - LOperand* left = UseFixed(instr->left(), r1); - LOperand* right = UseFixed(instr->right(), r0); - LArithmeticT* result = new(zone()) LArithmeticT(instr->op(), left, right); - return MarkAsCall(DefineFixed(result, r0), instr); + return DoArithmeticT(instr->op(), instr); } } LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { - if (instr->representation().IsDouble()) { - return DoArithmeticD(Token::DIV, instr); - } else if (instr->representation().IsSmiOrInteger32()) { + if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); if (instr->HasPowerOf2Divisor()) { @@ -1381,6 +1371,8 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4); LDivI* div = new(zone()) LDivI(dividend, divisor, temp); return AssignEnvironment(DefineAsRegister(div)); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::DIV, instr); } else { return DoArithmeticT(Token::DIV, instr); } @@ -1501,17 +1493,10 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) { ? AssignEnvironment(result) : result; } - } else if (instr->representation().IsTagged()) { - return DoArithmeticT(Token::MOD, instr); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::MOD, instr); } else { - ASSERT(instr->representation().IsDouble()); - // We call a C function for double modulo. It can't trigger a GC. We need - // to use fixed result register for the call. - // TODO(fschneider): Allow any register as input registers. - LArithmeticD* mod = new(zone()) LArithmeticD(Token::MOD, - UseFixedDouble(left, d1), - UseFixedDouble(right, d2)); - return MarkAsCall(DefineFixedDouble(mod, d1), instr); + return DoArithmeticT(Token::MOD, instr); } } @@ -1678,7 +1663,6 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { return DoArithmeticD(Token::ADD, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::ADD, instr); } } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 98cacacae1..94b5e2a07a 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -2119,7 +2119,7 @@ class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 2> { LOperand* temp2() { return temps_[1]; } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") - DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) + DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } }; @@ -2778,7 +2778,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LInstruction* DoArithmeticD(Token::Value op, HArithmeticBinaryOperation* instr); LInstruction* DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr); + HBinaryOperation* instr); LPlatformChunk* chunk_; CompilationInfo* info_; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index b01f840c63..059aa13322 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5007,15 +5007,19 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { Register input_reg = ToRegister(input); - DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); + if (instr->hydrogen()->value()->representation().IsSmi()) { + __ SmiUntag(input_reg); + } else { + DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); - // Optimistically untag the input. - // If the input is a HeapObject, SmiUntag will set the carry flag. - __ SmiUntag(input_reg, SetCC); - // Branch to deferred code if the input was tagged. - // The deferred code will take care of restoring the tag. - __ b(cs, deferred->entry()); - __ bind(deferred->exit()); + // Optimistically untag the input. + // If the input is a HeapObject, SmiUntag will set the carry flag. + __ SmiUntag(input_reg, SetCC); + // Branch to deferred code if the input was tagged. + // The deferred code will take care of restoring the tag. + __ b(cs, deferred->entry()); + __ bind(deferred->exit()); + } } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index ec0d042224..d119111138 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1733,9 +1733,9 @@ void LCodeGen::DoMulI(LMulI* instr) { case 9: __ lea(left, Operand(left, left, times_8, 0)); break; - case 16: - __ shl(left, 4); - break; + case 16: + __ shl(left, 4); + break; default: __ imul(left, left, constant); break; @@ -2208,8 +2208,6 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { XMMRegister left = ToDoubleRegister(instr->left()); XMMRegister right = ToDoubleRegister(instr->right()); XMMRegister result = ToDoubleRegister(instr->result()); - // Modulo uses a fixed result register. - ASSERT(instr->op() == Token::MOD || left.is(result)); switch (instr->op()) { case Token::ADD: __ addsd(left, right); @@ -2236,7 +2234,7 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { 4); // Return value is in st(0) on ia32. - // Store it into the (fixed) result register. + // Store it into the result register. __ sub(Operand(esp), Immediate(kDoubleSize)); __ fstp_d(Operand(esp, 0)); __ movdbl(result, Operand(esp, 0)); @@ -5427,12 +5425,16 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { Register input_reg = ToRegister(input); ASSERT(input_reg.is(ToRegister(instr->result()))); - DeferredTaggedToI* deferred = - new(zone()) DeferredTaggedToI(this, instr, x87_stack_); + if (instr->hydrogen()->value()->representation().IsSmi()) { + __ SmiUntag(input_reg); + } else { + DeferredTaggedToI* deferred = + new(zone()) DeferredTaggedToI(this, instr, x87_stack_); - __ JumpIfNotSmi(input_reg, deferred->entry()); - __ SmiUntag(input_reg); - __ bind(deferred->exit()); + __ JumpIfNotSmi(input_reg, deferred->entry()); + __ SmiUntag(input_reg); + __ bind(deferred->exit()); + } } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index ca1e60d644..ebcf1b637c 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -762,52 +762,44 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { LInstruction* LChunkBuilder::DoShift(Token::Value op, HBitwiseBinaryOperation* instr) { - if (instr->representation().IsTagged()) { - ASSERT(instr->left()->representation().IsSmiOrTagged()); - ASSERT(instr->right()->representation().IsSmiOrTagged()); + if (instr->representation().IsSmiOrInteger32()) { + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* context = UseFixed(instr->context(), esi); - LOperand* left = UseFixed(instr->left(), edx); - LOperand* right = UseFixed(instr->right(), eax); - LArithmeticT* result = new(zone()) LArithmeticT(op, context, left, right); - return MarkAsCall(DefineFixed(result, eax), instr); - } - - ASSERT(instr->representation().IsSmiOrInteger32()); - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); - LOperand* left = UseRegisterAtStart(instr->left()); - - HValue* right_value = instr->right(); - LOperand* right = NULL; - int constant_value = 0; - bool does_deopt = false; - if (right_value->IsConstant()) { - HConstant* constant = HConstant::cast(right_value); - right = chunk_->DefineConstantOperand(constant); - constant_value = constant->Integer32Value() & 0x1f; - // Left shifts can deoptimize if we shift by > 0 and the result cannot be - // truncated to smi. - if (instr->representation().IsSmi() && constant_value > 0) { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); - } - } else { - right = UseFixed(right_value, ecx); - } - - // Shift operations can only deoptimize if we do a logical shift by 0 and - // the result cannot be truncated to int32. - if (op == Token::SHR && constant_value == 0) { - if (FLAG_opt_safe_uint32_operations) { - does_deopt = !instr->CheckFlag(HInstruction::kUint32); + HValue* right_value = instr->right(); + LOperand* right = NULL; + int constant_value = 0; + bool does_deopt = false; + if (right_value->IsConstant()) { + HConstant* constant = HConstant::cast(right_value); + right = chunk_->DefineConstantOperand(constant); + constant_value = constant->Integer32Value() & 0x1f; + // Left shifts can deoptimize if we shift by > 0 and the result cannot be + // truncated to smi. + if (instr->representation().IsSmi() && constant_value > 0) { + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); + } } else { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + right = UseFixed(right_value, ecx); } - } - LInstruction* result = - DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt)); - return does_deopt ? AssignEnvironment(result) : result; + // Shift operations can only deoptimize if we do a logical shift by 0 and + // the result cannot be truncated to int32. + if (op == Token::SHR && constant_value == 0) { + if (FLAG_opt_safe_uint32_operations) { + does_deopt = !instr->CheckFlag(HInstruction::kUint32); + } else { + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + } + } + + LInstruction* result = + DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt)); + return does_deopt ? AssignEnvironment(result) : result; + } else { + return DoArithmeticT(op, instr); + } } @@ -816,21 +808,16 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, ASSERT(instr->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble()); - ASSERT(op != Token::MOD); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); LOperand* right = UseRegisterAtStart(instr->BetterRightOperand()); LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); + if (op == Token::MOD) return MarkAsCall(DefineSameAsFirst(result), instr); return DefineSameAsFirst(result); } LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr) { - ASSERT(op == Token::ADD || - op == Token::DIV || - op == Token::MOD || - op == Token::MUL || - op == Token::SUB); + HBinaryOperation* instr) { HValue* left = instr->left(); HValue* right = instr->right(); ASSERT(left->representation().IsTagged()); @@ -1442,29 +1429,19 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); return DefineSameAsFirst(new(zone()) LBitI(left, right)); } else { - ASSERT(instr->representation().IsSmiOrTagged()); - ASSERT(instr->left()->representation().IsSmiOrTagged()); - ASSERT(instr->right()->representation().IsSmiOrTagged()); - - LOperand* context = UseFixed(instr->context(), esi); - LOperand* left = UseFixed(instr->left(), edx); - LOperand* right = UseFixed(instr->right(), eax); - LArithmeticT* result = - new(zone()) LArithmeticT(instr->op(), context, left, right); - return MarkAsCall(DefineFixed(result, eax), instr); + return DoArithmeticT(instr->op(), instr); } } LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { - if (instr->representation().IsDouble()) { - return DoArithmeticD(Token::DIV, instr); - } else if (instr->representation().IsSmiOrInteger32()) { + if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); if (instr->HasPowerOf2Divisor()) { @@ -1481,8 +1458,9 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { LOperand* divisor = UseRegister(instr->right()); LDivI* result = new(zone()) LDivI(dividend, divisor, temp); return AssignEnvironment(DefineFixed(result, eax)); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::DIV, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::DIV, instr); } } @@ -1584,17 +1562,10 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) { ? AssignEnvironment(result) : result; } - } else if (instr->representation().IsSmiOrTagged()) { - return DoArithmeticT(Token::MOD, instr); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::MOD, instr); } else { - ASSERT(instr->representation().IsDouble()); - // We call a C function for double modulo. It can't trigger a GC. We need - // to use fixed result register for the call. - // TODO(fschneider): Allow any register as input registers. - LArithmeticD* mod = new(zone()) LArithmeticD(Token::MOD, - UseFixedDouble(left, xmm2), - UseFixedDouble(right, xmm1)); - return MarkAsCall(DefineFixedDouble(mod, xmm1), instr); + return DoArithmeticT(Token::MOD, instr); } } @@ -1618,7 +1589,6 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::MUL, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::MUL, instr); } } @@ -1639,7 +1609,6 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::SUB, instr); } else { - ASSERT(instr->representation().IsSmiOrTagged()); return DoArithmeticT(Token::SUB, instr); } } @@ -1671,7 +1640,6 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::ADD, instr); } else { - ASSERT(instr->representation().IsSmiOrTagged()); return DoArithmeticT(Token::ADD, instr); } } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 3a609c991a..0e615f257d 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -2189,7 +2189,7 @@ class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 1> { LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") - DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) + DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } }; @@ -2907,7 +2907,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LInstruction* DoArithmeticD(Token::Value op, HArithmeticBinaryOperation* instr); LInstruction* DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr); + HBinaryOperation* instr); LOperand* GetStoreKeyedValueOperand(HStoreKeyed* instr); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 6f4d3e309f..e224fba9b6 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -4725,12 +4725,16 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); - Register input_reg = ToRegister(input); - DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); - __ JumpIfNotSmi(input_reg, deferred->entry()); - __ SmiToInteger32(input_reg, input_reg); - __ bind(deferred->exit()); + + if (instr->hydrogen()->value()->representation().IsSmi()) { + __ SmiToInteger32(input_reg, input_reg); + } else { + DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); + __ JumpIfNotSmi(input_reg, deferred->entry()); + __ SmiToInteger32(input_reg, input_reg); + __ bind(deferred->exit()); + } } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index d9daaacca0..662cfce6a0 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -719,46 +719,39 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { LInstruction* LChunkBuilder::DoShift(Token::Value op, HBitwiseBinaryOperation* instr) { - if (instr->representation().IsTagged()) { - ASSERT(instr->left()->representation().IsTagged()); - ASSERT(instr->right()->representation().IsTagged()); + if (instr->representation().IsSmiOrInteger32()) { + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* left = UseFixed(instr->left(), rdx); - LOperand* right = UseFixed(instr->right(), rax); - LArithmeticT* result = new(zone()) LArithmeticT(op, left, right); - return MarkAsCall(DefineFixed(result, rax), instr); - } - - ASSERT(instr->representation().IsSmiOrInteger32()); - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); - LOperand* left = UseRegisterAtStart(instr->left()); - - HValue* right_value = instr->right(); - LOperand* right = NULL; - int constant_value = 0; - if (right_value->IsConstant()) { - HConstant* constant = HConstant::cast(right_value); - right = chunk_->DefineConstantOperand(constant); - constant_value = constant->Integer32Value() & 0x1f; - } else { - right = UseFixed(right_value, rcx); - } - - // Shift operations can only deoptimize if we do a logical shift by 0 and - // the result cannot be truncated to int32. - bool does_deopt = false; - if (op == Token::SHR && constant_value == 0) { - if (FLAG_opt_safe_uint32_operations) { - does_deopt = !instr->CheckFlag(HInstruction::kUint32); + HValue* right_value = instr->right(); + LOperand* right = NULL; + int constant_value = 0; + if (right_value->IsConstant()) { + HConstant* constant = HConstant::cast(right_value); + right = chunk_->DefineConstantOperand(constant); + constant_value = constant->Integer32Value() & 0x1f; } else { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + right = UseFixed(right_value, rcx); } - } - LInstruction* result = - DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt)); - return does_deopt ? AssignEnvironment(result) : result; + // Shift operations can only deoptimize if we do a logical shift by 0 and + // the result cannot be truncated to int32. + bool does_deopt = false; + if (op == Token::SHR && constant_value == 0) { + if (FLAG_opt_safe_uint32_operations) { + does_deopt = !instr->CheckFlag(HInstruction::kUint32); + } else { + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); + } + } + + LInstruction* result = + DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt)); + return does_deopt ? AssignEnvironment(result) : result; + } else { + return DoArithmeticT(op, instr); + } } @@ -767,21 +760,21 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, ASSERT(instr->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble()); - ASSERT(op != Token::MOD); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); - LOperand* right = UseRegisterAtStart(instr->BetterRightOperand()); + LOperand* right = NULL; + if (op == Token::MOD) { + right = UseFixedDouble(instr->BetterRightOperand(), xmm1); + LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); + return MarkAsCall(DefineSameAsFirst(result), instr); + } + right = UseRegisterAtStart(instr->BetterRightOperand()); LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); return DefineSameAsFirst(result); } LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr) { - ASSERT(op == Token::ADD || - op == Token::DIV || - op == Token::MOD || - op == Token::MUL || - op == Token::SUB); + HBinaryOperation* instr) { HValue* left = instr->left(); HValue* right = instr->right(); ASSERT(left->representation().IsTagged()); @@ -1348,27 +1341,19 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); return DefineSameAsFirst(new(zone()) LBitI(left, right)); } else { - ASSERT(instr->representation().IsTagged()); - ASSERT(instr->left()->representation().IsTagged()); - ASSERT(instr->right()->representation().IsTagged()); - - LOperand* left = UseFixed(instr->left(), rdx); - LOperand* right = UseFixed(instr->right(), rax); - LArithmeticT* result = new(zone()) LArithmeticT(instr->op(), left, right); - return MarkAsCall(DefineFixed(result, rax), instr); + return DoArithmeticT(instr->op(), instr); } } LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { - if (instr->representation().IsDouble()) { - return DoArithmeticD(Token::DIV, instr); - } else if (instr->representation().IsSmiOrInteger32()) { + if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); if (instr->HasPowerOf2Divisor()) { @@ -1385,8 +1370,9 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { LOperand* divisor = UseRegister(instr->right()); LDivI* result = new(zone()) LDivI(dividend, divisor, temp); return AssignEnvironment(DefineFixed(result, rax)); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::DIV, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::DIV, instr); } } @@ -1485,17 +1471,10 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) { ? AssignEnvironment(result) : result; } - } else if (instr->representation().IsTagged()) { - return DoArithmeticT(Token::MOD, instr); + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::MOD, instr); } else { - ASSERT(instr->representation().IsDouble()); - // We call a C function for double modulo. It can't trigger a GC. We need to - // use fixed result register for the call. - // TODO(fschneider): Allow any register as input registers. - LArithmeticD* mod = new(zone()) LArithmeticD(Token::MOD, - UseFixedDouble(left, xmm2), - UseFixedDouble(right, xmm1)); - return MarkAsCall(DefineFixedDouble(mod, xmm1), instr); + return DoArithmeticT(Token::MOD, instr); } } @@ -1515,7 +1494,6 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::MUL, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::MUL, instr); } } @@ -1536,7 +1514,6 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::SUB, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::SUB, instr); } } @@ -1568,7 +1545,6 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::ADD, instr); } else { - ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::ADD, instr); } return NULL; diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index b3d08c8a4c..8496deb081 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -2049,7 +2049,7 @@ class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 1> { LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") - DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) + DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } }; @@ -2701,7 +2701,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LInstruction* DoArithmeticD(Token::Value op, HArithmeticBinaryOperation* instr); LInstruction* DoArithmeticT(Token::Value op, - HArithmeticBinaryOperation* instr); + HBinaryOperation* instr); LPlatformChunk* chunk_; CompilationInfo* info_;