Index: src/x64/lithium-codegen-x64.cc |
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
index dbdc12e63f207bfe1e35ef52ce50488ecd133980..91d14e7b5db5e8c19705841d54f4968825324b0e 100644 |
--- a/src/x64/lithium-codegen-x64.cc |
+++ b/src/x64/lithium-codegen-x64.cc |
@@ -64,6 +64,33 @@ class SafepointGenerator : public CallWrapper { |
}; |
+class LithiumSmiInstructionWrapper |
+ : public MacroAssembler::SmiInstructionWrapper { |
+ public: |
+ LithiumSmiInstructionWrapper(LCodeGen* codegen, |
+ LEnvironment* environment, |
+ bool check_overflow = false, |
+ bool check_minus_zero = false) |
+ : codegen_(codegen), |
+ environment_(environment), |
+ check_overflow_(check_overflow), |
+ check_minus_zero_(check_minus_zero) { } |
+ virtual ~LithiumSmiInstructionWrapper() { } |
+ virtual bool NeedsCheckOverflow() const { return check_overflow_; } |
+ virtual bool NeedsCheckMinusZero() const { return check_minus_zero_; } |
+ virtual bool NeedsKeepSourceOperandsIntact() const { return false; } |
+ virtual void BailoutIf(Condition cc) const { |
+ codegen_->DeoptimizeIf(cc, environment_); |
+ } |
+ |
+ private: |
+ LCodeGen* codegen_; |
+ LEnvironment* environment_; |
+ bool check_overflow_; |
+ bool check_minus_zero_; |
+}; |
+ |
+ |
#define __ masm()-> |
bool LCodeGen::GenerateCode() { |
@@ -416,8 +443,17 @@ bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const { |
int32_t LCodeGen::ToInteger32(LConstantOperand* op) const { |
+ return ToRepresentation(op, Representation::Integer32()); |
+} |
+ |
+ |
+int32_t LCodeGen::ToRepresentation(LConstantOperand* op, |
+ const Representation& r) const { |
HConstant* constant = chunk_->LookupConstant(op); |
- return constant->Integer32Value(); |
+ int32_t value = constant->Integer32Value(); |
+ if (r.IsInteger32()) return value; |
+ ASSERT(r.IsSmiOrTagged()); |
+ return static_cast<int32_t>(reinterpret_cast<intptr_t>(Smi::FromInt(value))); |
} |
@@ -1362,16 +1398,31 @@ void LCodeGen::DoBitI(LBitI* instr) { |
ASSERT(left->IsRegister()); |
if (right->IsConstantOperand()) { |
- int right_operand = ToInteger32(LConstantOperand::cast(right)); |
+ int32_t right_value = ToInteger32(LConstantOperand::cast(right)); |
switch (instr->op()) { |
case Token::BIT_AND: |
- __ andl(ToRegister(left), Immediate(right_operand)); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ SmiAndConstant(ToRegister(left), ToRegister(left), |
+ Smi::FromInt(right_value)); |
+ } else { |
+ __ andl(ToRegister(left), Immediate(right_value)); |
+ } |
break; |
case Token::BIT_OR: |
- __ orl(ToRegister(left), Immediate(right_operand)); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ SmiOrConstant(ToRegister(left), ToRegister(left), |
+ Smi::FromInt(right_value)); |
+ } else { |
+ __ orl(ToRegister(left), Immediate(right_value)); |
+ } |
break; |
case Token::BIT_XOR: |
- __ xorl(ToRegister(left), Immediate(right_operand)); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ SmiXorConstant(ToRegister(left), ToRegister(left), |
+ Smi::FromInt(right_value)); |
+ } else { |
+ __ xorl(ToRegister(left), Immediate(right_value)); |
+ } |
break; |
default: |
UNREACHABLE(); |
@@ -1466,7 +1517,14 @@ void LCodeGen::DoShiftI(LShiftI* instr) { |
case Token::SHL: |
if (shift_count != 0) { |
if (instr->hydrogen_value()->representation().IsSmi()) { |
- __ shl(ToRegister(left), Immediate(shift_count)); |
+ if (SmiValuesAre32Bits() || !instr->can_deopt()) { |
+ __ shl(ToRegister(left), Immediate(shift_count)); |
+ } else { |
+ ASSERT(SmiValuesAre31Bits() && instr->can_deopt()); |
+ LithiumSmiInstructionWrapper wrapper(this, instr->environment()); |
+ __ SmiShiftLeftConstant(ToRegister(left), ToRegister(left), |
+ shift_count, wrapper); |
+ } |
} else { |
__ shll(ToRegister(left), Immediate(shift_count)); |
} |
@@ -1485,24 +1543,33 @@ void LCodeGen::DoSubI(LSubI* instr) { |
LOperand* right = instr->right(); |
ASSERT(left->Equals(instr->result())); |
+ bool check_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
+ LithiumSmiInstructionWrapper wrapper(this, instr->environment(), |
+ check_overflow); |
if (right->IsConstantOperand()) { |
- __ subl(ToRegister(left), |
- Immediate(ToInteger32(LConstantOperand::cast(right)))); |
+ int32_t right_value = ToInteger32(LConstantOperand::cast(right)); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ SmiSubConstant(ToRegister(left), ToRegister(left), |
+ Smi::FromInt(right_value), wrapper); |
+ } else { |
+ __ subl(ToRegister(left), Immediate(right_value)); |
+ } |
} else if (right->IsRegister()) { |
if (instr->hydrogen_value()->representation().IsSmi()) { |
- __ subq(ToRegister(left), ToRegister(right)); |
+ __ SmiSub(ToRegister(left), ToRegister(left), ToRegister(right), wrapper); |
} else { |
__ subl(ToRegister(left), ToRegister(right)); |
} |
} else { |
if (instr->hydrogen_value()->representation().IsSmi()) { |
- __ subq(ToRegister(left), ToOperand(right)); |
+ __ SmiSub(ToRegister(left), ToRegister(left), ToOperand(right), wrapper); |
} else { |
__ subl(ToRegister(left), ToOperand(right)); |
} |
} |
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
+ if (instr->hydrogen_value()->representation().IsInteger32() && |
+ check_overflow) { |
DeoptimizeIf(overflow, instr->environment()); |
} |
} |
@@ -1680,9 +1747,15 @@ void LCodeGen::DoAddI(LAddI* instr) { |
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) { |
if (right->IsConstantOperand()) { |
- int32_t offset = ToInteger32(LConstantOperand::cast(right)); |
- __ leal(ToRegister(instr->result()), |
- MemOperand(ToRegister(left), offset)); |
+ int32_t offset = ToRepresentation(LConstantOperand::cast(right), |
+ instr->hydrogen()->representation()); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ lea(ToRegister(instr->result()), |
+ MemOperand(ToRegister(left), offset)); |
+ } else { |
+ __ leal(ToRegister(instr->result()), |
+ MemOperand(ToRegister(left), offset)); |
+ } |
} else { |
Operand address(ToRegister(left), ToRegister(right), times_1, 0); |
if (instr->hydrogen()->representation().IsSmi()) { |
@@ -1692,23 +1765,35 @@ void LCodeGen::DoAddI(LAddI* instr) { |
} |
} |
} else { |
+ bool check_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
+ LithiumSmiInstructionWrapper wrapper(this, instr->environment(), |
+ check_overflow); |
if (right->IsConstantOperand()) { |
- __ addl(ToRegister(left), |
- Immediate(ToInteger32(LConstantOperand::cast(right)))); |
+ int32_t right_value = ToInteger32(LConstantOperand::cast(right)); |
+ if (instr->hydrogen()->representation().IsSmi()) { |
+ __ SmiAddConstant(ToRegister(left), ToRegister(left), |
+ Smi::FromInt(right_value), wrapper); |
+ } else { |
+ __ addl(ToRegister(left), Immediate(right_value)); |
+ } |
} else if (right->IsRegister()) { |
if (instr->hydrogen_value()->representation().IsSmi()) { |
- __ addq(ToRegister(left), ToRegister(right)); |
+ __ SmiAdd(ToRegister(left), ToRegister(left), ToRegister(right), |
+ wrapper); |
} else { |
__ addl(ToRegister(left), ToRegister(right)); |
} |
} else { |
if (instr->hydrogen_value()->representation().IsSmi()) { |
- __ addq(ToRegister(left), ToOperand(right)); |
+ __ SmiAdd(ToRegister(left), ToRegister(left), ToOperand(right), |
+ wrapper); |
} else { |
__ addl(ToRegister(left), ToOperand(right)); |
} |
} |
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
+ |
+ if (instr->hydrogen_value()->representation().IsInteger32() && |
+ check_overflow) { |
DeoptimizeIf(overflow, instr->environment()); |
} |
} |
@@ -1728,8 +1813,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
Register left_reg = ToRegister(left); |
if (right->IsConstantOperand()) { |
Immediate right_imm = |
- Immediate(ToInteger32(LConstantOperand::cast(right))); |
- ASSERT(!instr->hydrogen_value()->representation().IsSmi()); |
+ Immediate(ToRepresentation(LConstantOperand::cast(right), |
+ instr->hydrogen()->representation())); |
__ cmpl(left_reg, right_imm); |
__ j(condition, &return_left, Label::kNear); |
__ movq(left_reg, right_imm); |
@@ -2927,7 +3012,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
// gets replaced during bound check elimination with the index argument |
// to the bounds check, which can be tagged, so that case must be |
// handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -2998,7 +3086,10 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
// representation for the key to be an integer, the input gets replaced |
// during bound check elimination with the index argument to the bounds |
// check, which can be tagged, so that case must be handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -3038,7 +3129,10 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { |
// gets replaced during bound check elimination with the index |
// argument to the bounds check, which can be tagged, so that |
// case must be handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -3426,12 +3520,17 @@ void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { |
} |
-void LCodeGen::EmitInteger64MathAbs(LMathAbs* instr) { |
+void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) { |
Register input_reg = ToRegister(instr->value()); |
__ testq(input_reg, input_reg); |
Label is_positive; |
__ j(not_sign, &is_positive, Label::kNear); |
- __ neg(input_reg); // Sets flags. |
+ if (SmiValuesAre32Bits()) { |
+ __ neg(input_reg); // Sets flags. |
+ } else { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ negl(input_reg); // Sets flags. |
+ } |
DeoptimizeIf(negative, instr->environment()); |
__ bind(&is_positive); |
} |
@@ -3463,16 +3562,14 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { |
} else if (r.IsInteger32()) { |
EmitIntegerMathAbs(instr); |
} else if (r.IsSmi()) { |
- EmitInteger64MathAbs(instr); |
+ EmitSmiMathAbs(instr); |
} else { // Tagged case. |
DeferredMathAbsTaggedHeapNumber* deferred = |
new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); |
Register input_reg = ToRegister(instr->value()); |
// Smi check. |
__ JumpIfNotSmi(input_reg, deferred->entry()); |
- __ SmiToInteger32(input_reg, input_reg); |
- EmitIntegerMathAbs(instr); |
- __ Integer32ToSmi(input_reg, input_reg); |
+ EmitSmiMathAbs(instr); |
__ bind(deferred->exit()); |
} |
} |
@@ -4140,7 +4237,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
// gets replaced during bound check elimination with the index |
// argument to the bounds check, which can be tagged, so that case |
// must be handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -4202,7 +4302,10 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { |
// input gets replaced during bound check elimination with the index |
// argument to the bounds check, which can be tagged, so that case |
// must be handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -4243,7 +4346,10 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { |
// input gets replaced during bound check elimination with the index |
// argument to the bounds check, which can be tagged, so that case |
// must be handled here, too. |
- if (instr->hydrogen()->IsDehoisted()) { |
+ if (instr->hydrogen()->key()->representation().IsSmi()) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ __ SmiToInteger64(key_reg, key_reg); |
+ } else if (instr->hydrogen()->IsDehoisted()) { |
// Sign extend key because it could be a 32 bit negative value |
// and the dehoisted address computation happens in 64 bits |
__ movsxlq(key_reg, key_reg); |
@@ -4500,11 +4606,77 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
- LOperand* input = instr->value(); |
- ASSERT(input->IsRegister() && input->Equals(instr->result())); |
- Register reg = ToRegister(input); |
+ if (SmiValuesAre32Bits()) { |
+ LOperand* input = instr->value(); |
+ ASSERT(input->IsRegister() && input->Equals(instr->result())); |
+ Register reg = ToRegister(input); |
- __ Integer32ToSmi(reg, reg); |
+ __ Integer32ToSmi(reg, reg); |
+ } else { |
+ ASSERT(SmiValuesAre31Bits()); |
+ class DeferredNumberTagI: public LDeferredCode { |
+ public: |
+ DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() { |
+ codegen()->DoDeferredNumberTagI(instr_); |
+ } |
+ virtual LInstruction* instr() { return instr_; } |
+ private: |
+ LNumberTagI* instr_; |
+ }; |
+ |
+ LOperand* input = instr->value(); |
+ ASSERT(input->IsRegister() && input->Equals(instr->result())); |
+ Register reg = ToRegister(input); |
+ |
+ DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); |
+ __ shll(reg, Immediate(kSmiTagSize + kSmiShiftSize)); |
+ __ j(overflow, deferred->entry()); |
+ __ movsxlq(reg, reg); |
+ __ bind(deferred->exit()); |
+ } |
+} |
+ |
+ |
+void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ Label slow; |
+ Register reg = ToRegister(instr->value()); |
+ Register tmp = reg.is(rax) ? kScratchRegister : rax; |
+ |
+ // Preserve the value of all registers. |
+ PushSafepointRegistersScope scope(this); |
+ |
+ Label done; |
+ // There was overflow, so bits 30 and 31 of the original integer |
+ // disagree. Try to allocate a heap number in new space and store |
+ // the value in there. If that fails, call the runtime system. |
+ __ SmiToInteger32(reg, reg); |
+ __ xorl(reg, Immediate(0x80000000)); |
+ __ cvtlsi2sd(xmm1, reg); |
+ |
+ if (FLAG_inline_new) { |
+ __ AllocateHeapNumber(reg, tmp, &slow); |
+ __ jmp(&done, Label::kNear); |
+ } |
+ |
+ // Slow case: Call the runtime system to do the number allocation. |
+ __ bind(&slow); |
+ |
+ // Put a valid pointer value in the stack slot where the result |
+ // register is stored, as this register is in the pointer map, but contains an |
+ // integer value. |
+ __ StoreToSafepointRegisterSlot(reg, Immediate(0)); |
+ CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); |
+ // Set the pointer to the new heap number in tmp. |
+ if (!reg.is(rax)) __ movq(reg, rax); |
+ |
+ // Heap number allocated. Put the value in xmm0 into the value of the |
+ // allocated heap number. |
+ __ bind(&done); |
+ __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm1); |
+ __ StoreToSafepointRegisterSlot(reg, reg); |
} |