diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 5cf1d59e49..d46998ffd2 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -1521,6 +1521,7 @@ void LCodeGen::DoShiftI(LShiftI* instr) { LOperand* right_op = instr->right(); Register left = ToRegister(instr->left()); Register result = ToRegister(instr->result()); + Register scratch = scratch0(); if (right_op->IsRegister()) { // No need to mask the right operand on MIPS, it is built into the variable @@ -1577,7 +1578,14 @@ void LCodeGen::DoShiftI(LShiftI* instr) { break; case Token::SHL: if (shift_count != 0) { - __ sll(result, left, shift_count); + if (instr->hydrogen_value()->representation().IsSmi() && + instr->can_deopt()) { + __ sll(result, left, shift_count - 1); + __ SmiTagCheckOverflow(result, result, scratch); + DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg)); + } else { + __ sll(result, left, shift_count); + } } else { __ Move(result, left); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index b03cea44cb..c938f534d2 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -713,9 +713,9 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { LInstruction* LChunkBuilder::DoShift(Token::Value op, HBitwiseBinaryOperation* instr) { - if (instr->representation().IsSmiOrTagged()) { - ASSERT(instr->left()->representation().IsSmiOrTagged()); - ASSERT(instr->right()->representation().IsSmiOrTagged()); + if (instr->representation().IsTagged()) { + ASSERT(instr->left()->representation().IsTagged()); + ASSERT(instr->right()->representation().IsTagged()); LOperand* left = UseFixed(instr->left(), a1); LOperand* right = UseFixed(instr->right(), a0); @@ -723,25 +723,35 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, return MarkAsCall(DefineFixed(result, v0), instr); } - ASSERT(instr->representation().IsInteger32()); - ASSERT(instr->left()->representation().IsInteger32()); - ASSERT(instr->right()->representation().IsInteger32()); + 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) { + for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { + if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) { + does_deopt = true; + break; + } + } + } } else { right = UseRegisterAtStart(right_value); } - // Shift operations can only deoptimize if we do a logical shift + // Shift operations can 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);