| 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);
|
| }
|
|
|
|
|
|
|