Chromium Code Reviews| Index: runtime/vm/intermediate_language_ia32.cc |
| diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc |
| index d3cf96f2d48b2e25499580adf751714da298d901..38a6152e8ab68cb06aee030e2d51c15debfc4334 100644 |
| --- a/runtime/vm/intermediate_language_ia32.cc |
| +++ b/runtime/vm/intermediate_language_ia32.cc |
| @@ -175,15 +175,25 @@ LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Isolate* isolate, |
| void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| // The register allocator drops constant definitions that have no uses. |
| if (!locs()->out(0).IsInvalid()) { |
| - XmmRegister result = locs()->out(0).fpu_reg(); |
| - if (constant_address() == 0) { |
| - Register boxed = locs()->temp(0).reg(); |
| - __ LoadObjectSafely(boxed, value()); |
| - __ movsd(result, FieldAddress(boxed, Double::value_offset())); |
| - } else if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) { |
| - __ xorps(result, result); |
| - } else { |
| - __ movsd(result, Address::Absolute(constant_address())); |
| + switch (representation()) { |
| + case kUnboxedDouble: { |
| + XmmRegister result = locs()->out(0).fpu_reg(); |
| + if (constant_address() == 0) { |
| + Register boxed = locs()->temp(0).reg(); |
| + __ LoadObjectSafely(boxed, value()); |
| + __ movsd(result, FieldAddress(boxed, Double::value_offset())); |
| + } else if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) { |
| + __ xorps(result, result); |
| + } else { |
| + __ movsd(result, Address::Absolute(constant_address())); |
| + } |
| + break; |
| + } |
| + case kUnboxedInt32: |
| + __ movl(locs()->out(0).reg(), Immediate(Smi::Cast(value()).Value())); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| } |
| } |
| } |
| @@ -1042,7 +1052,7 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary(Isolate* isolate, |
| locs->set_in(0, Location::RequiresRegister()); |
| if (CanBeImmediateIndex(index(), class_id())) { |
| // CanBeImmediateIndex must return false for unsafe smis. |
| - locs->set_in(1, Location::Constant(index()->BoundConstant())); |
| + locs->set_in(1, Location::Constant(index()->definition()->AsConstant())); |
| } else { |
| // The index is either untagged (element size == 1) or a smi (for all |
| // element sizes > 1). |
| @@ -1238,7 +1248,7 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Isolate* isolate, |
| locs->set_in(0, Location::RequiresRegister()); |
| if (CanBeImmediateIndex(index(), class_id())) { |
| // CanBeImmediateIndex must return false for unsafe smis. |
| - locs->set_in(1, Location::Constant(index()->BoundConstant())); |
| + locs->set_in(1, Location::Constant(index()->definition()->AsConstant())); |
| } else { |
| // The index is either untagged (element size == 1) or a smi (for all |
| // element sizes > 1). |
| @@ -2775,7 +2785,7 @@ LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, |
| summary->set_in(0, Location::RequiresRegister()); |
| ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| // The programmer only controls one bit, so the constant is safe. |
| - summary->set_in(1, Location::Constant(right_constant->value())); |
| + summary->set_in(1, Location::Constant(right_constant)); |
| summary->set_temp(0, Location::RequiresRegister()); |
| summary->set_out(0, Location::SameAsFirstInput()); |
| } else { |
| @@ -3139,6 +3149,294 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| } |
| +LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t kNumInputs = 2; |
| + if (op_kind() == Token::kTRUNCDIV) { |
| + UNREACHABLE(); |
| + return NULL; |
| + } else if (op_kind() == Token::kMOD) { |
| + UNREACHABLE(); |
| + return NULL; |
| + } else if (op_kind() == Token::kSHR) { |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| + } else if (op_kind() == Token::kSHL) { |
| + const intptr_t kNumTemps = !IsTruncating() ? 1 : 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| + if (!IsTruncating()) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + } |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| + } else { |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + ConstantInstr* constant = right()->definition()->AsConstant(); |
| + if (constant == NULL) { |
| + if (right()->definition()->IsUnboxedConstant()) { |
| + asm("int $3"); |
|
Florian Schneider
2014/08/27 09:36:51
Remove debugging left-over?
Vyacheslav Egorov (Google)
2014/08/27 11:45:37
Done.
|
| + } |
| + } |
| + if (constant != NULL) { |
| + summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| + } else { |
| + summary->set_in(1, Location::PrefersRegister()); |
| + } |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| + } |
| +} |
| + |
| + |
| +static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, |
| + BinaryInt32OpInstr* shift_left) { |
| + const bool is_truncating = shift_left->IsTruncating(); |
| + const LocationSummary& locs = *shift_left->locs(); |
| + Register left = locs.in(0).reg(); |
| + Register result = locs.out(0).reg(); |
| + ASSERT(left == result); |
| + Label* deopt = shift_left->CanDeoptimize() ? |
| + compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| + : NULL; |
| + ASSERT(locs.in(1).IsConstant()); |
| + |
| + const Object& constant = locs.in(1).constant(); |
| + ASSERT(constant.IsSmi()); |
| + // shll operation masks the count to 5 bits. |
| + const intptr_t kCountLimit = 0x1F; |
| + const intptr_t value = Smi::Cast(constant).Value(); |
| + if (value == 0) { |
| + // No code needed. |
| + } else if ((value < 0) || (value >= kCountLimit)) { |
| + // This condition may not be known earlier in some cases because |
| + // of constant propagation, inlining, etc. |
| + if ((value >= kCountLimit) && is_truncating) { |
| + __ xorl(result, result); |
| + } else { |
| + // Result is Mint or exception. |
| + __ jmp(deopt); |
| + } |
| + } else { |
| + if (!is_truncating) { |
| + // Check for overflow. |
| + Register temp = locs.temp(0).reg(); |
| + __ movl(temp, left); |
| + __ shll(left, Immediate(value)); |
| + __ sarl(left, Immediate(value)); |
| + __ cmpl(left, temp); |
| + __ j(NOT_EQUAL, deopt); // Overflow. |
| + } |
| + // Shift for result now we know there is no overflow. |
| + __ shll(left, Immediate(value)); |
| + } |
| +} |
| + |
| + |
| +void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + if (op_kind() == Token::kSHL) { |
| + EmitInt32ShiftLeft(compiler, this); |
| + return; |
| + } |
| + |
| + Register left = locs()->in(0).reg(); |
| + Register result = locs()->out(0).reg(); |
| + ASSERT(left == result); |
| + Label* deopt = NULL; |
| + if (CanDeoptimize()) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| + } |
| + |
| + if (locs()->in(1).IsConstant()) { |
| + const Object& constant = locs()->in(1).constant(); |
| + ASSERT(constant.IsSmi()); |
| + const intptr_t value = Smi::Cast(constant).Value(); |
| + switch (op_kind()) { |
| + case Token::kADD: |
| + if (value != 0) { |
| + // Checking overflow without emitting an instruction would be wrong. |
| + __ addl(left, Immediate(value)); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + } |
| + break; |
| + case Token::kSUB: { |
| + if (value != 0) { |
| + // Checking overflow without emitting an instruction would be wrong. |
| + __ subl(left, Immediate(value)); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + } |
| + break; |
| + } |
| + case Token::kMUL: { |
| + if (value == 2) { |
| + __ shll(left, Immediate(1)); |
| + } else { |
| + __ imull(left, Immediate(value)); |
| + } |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kTRUNCDIV: { |
| + UNREACHABLE(); |
|
Florian Schneider
2014/08/27 09:36:51
UNIMPLEMENTED?
Vyacheslav Egorov (Google)
2014/08/27 11:45:37
UNREACHABLE() is more meaningful because supported
|
| + break; |
| + } |
| + case Token::kBIT_AND: { |
| + // No overflow check. |
| + __ andl(left, Immediate(value)); |
| + break; |
| + } |
| + case Token::kBIT_OR: { |
| + // No overflow check. |
| + __ orl(left, Immediate(value)); |
| + break; |
| + } |
| + case Token::kBIT_XOR: { |
| + // No overflow check. |
| + __ xorl(left, Immediate(value)); |
| + break; |
| + } |
| + case Token::kSHR: { |
| + // sarl operation masks the count to 5 bits. |
| + const intptr_t kCountLimit = 0x1F; |
| + if (value == 0) { |
| + // TODO(vegorov): should be handled outside. |
| + break; |
| + } else if (value < 0) { |
| + // TODO(vegorov): should be handled outside. |
| + __ jmp(deopt); |
| + break; |
| + } |
| + |
| + if (value >= kCountLimit) { |
| + __ sarl(left, Immediate(kCountLimit)); |
| + } else { |
| + __ sarl(left, Immediate(value)); |
| + } |
| + |
| + break; |
| + } |
| + |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + return; |
| + } // if locs()->in(1).IsConstant() |
| + |
| + if (locs()->in(1).IsStackSlot()) { |
| + const Address& right = locs()->in(1).ToStackSlotAddress(); |
| + switch (op_kind()) { |
| + case Token::kADD: { |
| + __ addl(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kSUB: { |
| + __ subl(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kMUL: { |
| + __ imull(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kBIT_AND: { |
| + // No overflow check. |
| + __ andl(left, right); |
| + break; |
| + } |
| + case Token::kBIT_OR: { |
| + // No overflow check. |
| + __ orl(left, right); |
| + break; |
| + } |
| + case Token::kBIT_XOR: { |
| + // No overflow check. |
| + __ xorl(left, right); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| + return; |
| + } // if locs()->in(1).IsStackSlot. |
| + |
| + // if locs()->in(1).IsRegister. |
| + Register right = locs()->in(1).reg(); |
| + switch (op_kind()) { |
| + case Token::kADD: { |
| + __ addl(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kSUB: { |
| + __ subl(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kMUL: { |
| + __ imull(left, right); |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| + break; |
| + } |
| + case Token::kBIT_AND: { |
| + // No overflow check. |
| + __ andl(left, right); |
| + break; |
| + } |
| + case Token::kBIT_OR: { |
| + // No overflow check. |
| + __ orl(left, right); |
| + break; |
| + } |
| + case Token::kBIT_XOR: { |
| + // No overflow check. |
| + __ xorl(left, right); |
| + break; |
| + } |
| + case Token::kTRUNCDIV: { |
| + UNREACHABLE(); |
|
Florian Schneider
2014/08/27 09:36:51
UNIMPLEMENTED?
Vyacheslav Egorov (Google)
2014/08/27 11:45:37
Ditto.
|
| + break; |
| + } |
| + case Token::kMOD: { |
| + UNREACHABLE(); |
|
Florian Schneider
2014/08/27 09:36:51
UNIMPLEMENTED?
Vyacheslav Egorov (Google)
2014/08/27 11:45:37
Ditto
|
| + break; |
| + } |
| + case Token::kSHR: { |
| + UNREACHABLE(); |
|
Florian Schneider
2014/08/27 09:36:51
UNIMPLEMENTED?
Vyacheslav Egorov (Google)
2014/08/27 11:45:37
Ditto.
|
| + break; |
| + } |
| + case Token::kDIV: { |
| + // Dispatches to 'Double./'. |
| + // TODO(srdjan): Implement as conversion to double and double division. |
| + UNREACHABLE(); |
| + break; |
| + } |
| + case Token::kOR: |
| + case Token::kAND: { |
| + // Flow graph builder has dissected this operation to guarantee correct |
| + // behavior (short-circuit evaluation). |
| + UNREACHABLE(); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| +} |
| + |
| + |
| LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| intptr_t left_cid = left()->Type()->ToCid(); |
| @@ -4673,6 +4971,25 @@ void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| } |
| +LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* result = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + result->set_in(0, Location::WritableRegister()); |
| + result->set_out(0, Location::RequiresFpuRegister()); |
| + return result; |
| +} |
| + |
| + |
| +void Int32ToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + Register value = locs()->in(0).reg(); |
| + FpuRegister result = locs()->out(0).fpu_reg(); |
| + __ cvtsi2sd(result, value); |
| +} |
| + |
| + |
| LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| const intptr_t kNumInputs = 1; |
| @@ -5910,16 +6227,6 @@ CompileType UnaryUint32OpInstr::ComputeType() const { |
| } |
| -CompileType BoxUint32Instr::ComputeType() const { |
| - return CompileType::Int(); |
| -} |
| - |
| - |
| -CompileType UnboxUint32Instr::ComputeType() const { |
| - return CompileType::Int(); |
| -} |
| - |
| - |
| LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| const intptr_t kNumInputs = 2; |
| @@ -6092,9 +6399,14 @@ LocationSummary* BoxUint32Instr::MakeLocationSummary(Isolate* isolate, |
| const intptr_t kNumInputs = 1; |
| const intptr_t kNumTemps = 0; |
| LocationSummary* summary = new(isolate) LocationSummary( |
| - isolate, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath); |
| + isolate, |
| + kNumInputs, |
| + kNumTemps, |
| + ValueFitsSmi() ? LocationSummary::kNoCall |
| + : LocationSummary::kCallOnSlowPath); |
| summary->set_in(0, Location::RequiresRegister()); |
| - summary->set_out(0, Location::RequiresRegister()); |
| + summary->set_out(0, ValueFitsSmi() ? Location::SameAsFirstInput() |
| + : Location::RequiresRegister()); |
| return summary; |
| } |
| @@ -6102,27 +6414,68 @@ LocationSummary* BoxUint32Instr::MakeLocationSummary(Isolate* isolate, |
| void BoxUint32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| Register value = locs()->in(0).reg(); |
| Register out = locs()->out(0).reg(); |
| - ASSERT(value != out); |
| Label not_smi, done; |
| - // TODO(johnmccutchan): Use range information to fast path smi / mint boxing. |
| - // Test if this value is <= kSmiMax. |
| - __ cmpl(value, Immediate(kSmiMax)); |
| - __ j(ABOVE, ¬_smi); |
| - // Smi. |
| - __ movl(out, value); |
| - __ SmiTag(out); |
| - __ jmp(&done); |
| - __ Bind(¬_smi); |
| - // Allocate a mint. |
| - BoxAllocationSlowPath::Allocate( |
| - compiler, this, compiler->mint_class(), out, kNoRegister); |
| - // Copy low word into mint. |
| - __ movl(FieldAddress(out, Mint::value_offset()), value); |
| - // Zero high word. |
| - __ movl(FieldAddress(out, Mint::value_offset() + kWordSize), Immediate(0)); |
| - __ Bind(&done); |
| + if (ValueFitsSmi()) { |
| + ASSERT(value == out); |
| + __ SmiTag(value); |
| + } else { |
| + ASSERT(value != out); |
| + __ cmpl(value, Immediate(kSmiMax)); |
| + __ j(ABOVE, ¬_smi); |
| + // Smi. |
| + __ movl(out, value); |
| + __ SmiTag(out); |
| + __ jmp(&done); |
| + __ Bind(¬_smi); |
| + // Allocate a mint. |
| + BoxAllocationSlowPath::Allocate( |
| + compiler, this, compiler->mint_class(), out, kNoRegister); |
| + // Copy low word into mint. |
| + __ movl(FieldAddress(out, Mint::value_offset()), value); |
| + // Zero high word. |
| + __ movl(FieldAddress(out, Mint::value_offset() + kWordSize), Immediate(0)); |
| + __ Bind(&done); |
| + } |
| +} |
| + |
| + |
| +LocationSummary* BoxInt32Instr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, |
| + ValueFitsSmi() ? LocationSummary::kNoCall |
| + : LocationSummary::kCallOnSlowPath); |
| + summary->set_in(0, ValueFitsSmi() ? Location::RequiresRegister() |
| + : Location::WritableRegister()); |
| + summary->set_out(0, ValueFitsSmi() ? Location::SameAsFirstInput() |
| + : Location::RequiresRegister()); |
| + return summary; |
| +} |
| + |
| + |
| +void BoxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + Register value = locs()->in(0).reg(); |
| + Register out = locs()->out(0).reg(); |
| + |
| + if (out != value) { |
| + __ movl(out, value); |
| + } |
| + __ shll(out, Immediate(1)); |
| + if (!ValueFitsSmi()) { |
| + Label done; |
| + __ j(NO_OVERFLOW, &done); |
| + // Allocate a mint. |
| + BoxAllocationSlowPath::Allocate( |
| + compiler, this, compiler->mint_class(), out, kNoRegister); |
| + __ movl(FieldAddress(out, Mint::value_offset()), value); |
| + __ sarl(value, Immediate(31)); // Sign extend. |
| + __ movl(FieldAddress(out, Mint::value_offset() + kWordSize), value); |
| + __ Bind(&done); |
| + } |
| } |
| @@ -6171,35 +6524,142 @@ void UnboxUint32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| } |
| +LocationSummary* UnboxInt32Instr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t value_cid = value()->Type()->ToCid(); |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + if (kNumTemps > 0) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + } |
| + summary->set_out(0, (value_cid == kSmiCid) ? Location::SameAsFirstInput() |
| + : Location::RequiresRegister()); |
| + return summary; |
| +} |
| + |
| + |
| +static void LoadInt32FromMint(FlowGraphCompiler* compiler, |
| + Register mint, |
| + Register result, |
| + Register temp, |
| + Label* deopt) { |
| + __ movl(result, FieldAddress(mint, Mint::value_offset())); |
| + if (deopt != NULL) { |
| + __ movl(temp, result); |
| + __ sarl(temp, Immediate(31)); |
| + __ cmpl(temp, FieldAddress(mint, Mint::value_offset() + kWordSize)); |
| + __ j(NOT_EQUAL, deopt); |
| + } |
| +} |
| + |
| + |
| +void UnboxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + const intptr_t value_cid = value()->Type()->ToCid(); |
| + const Register value = locs()->in(0).reg(); |
| + const Register result = locs()->out(0).reg(); |
| + |
| + // TODO(johnmccutchan): Emit better code for constant inputs. |
| + if (value_cid == kMintCid) { |
| + Register temp = CanDeoptimize() ? locs()->temp(0).reg() : kNoRegister; |
| + Label* deopt = CanDeoptimize() ? |
| + compiler->AddDeoptStub(deopt_id_, ICData::kDeoptUnboxInteger) : NULL; |
| + LoadInt32FromMint(compiler, |
| + value, |
| + result, |
| + temp, |
| + deopt); |
| + } else if (value_cid == kSmiCid) { |
| + ASSERT(value == result); |
| + __ SmiUntag(value); |
| + } else { |
| + Register temp = locs()->temp(0).reg(); |
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, |
| + ICData::kDeoptUnboxInteger); |
| + Label is_smi, done; |
| + __ testl(value, Immediate(kSmiTagMask)); |
| + __ j(ZERO, &is_smi); |
| + __ CompareClassId(value, kMintCid, temp); |
| + __ j(NOT_EQUAL, deopt); |
| + LoadInt32FromMint(compiler, |
| + value, |
| + result, |
| + temp, |
| + deopt); |
| + __ movl(value, FieldAddress(value, Mint::value_offset())); |
| + __ jmp(&done); |
| + __ Bind(&is_smi); |
| + __ SmiUntag(value); |
| + __ Bind(&done); |
| + } |
| +} |
| + |
| + |
| LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| const intptr_t kNumInputs = 1; |
| const intptr_t kNumTemps = 0; |
| LocationSummary* summary = new(isolate) LocationSummary( |
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| - if (from() == kUnboxedMint) { |
| - summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| - Location::RequiresRegister())); |
| + if ((from() == kUnboxedInt32 || from() == kUnboxedUint32) && |
| + (to() == kUnboxedInt32 || to() == kUnboxedUint32)) { |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + } else if (from() == kUnboxedMint) { |
| + summary->set_in(0, Location::Pair( |
| + CanDeoptimize() ? Location::WritableRegister() |
| + : Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| summary->set_out(0, Location::RequiresRegister()); |
| - } else { |
| - ASSERT(from() == kUnboxedUint32); |
| + } else if (from() == kUnboxedUint32) { |
| summary->set_in(0, Location::RequiresRegister()); |
| summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| Location::RequiresRegister())); |
| + } else if (from() == kUnboxedInt32) { |
| + summary->set_in(0, Location::RegisterLocation(EAX)); |
| + summary->set_out(0, Location::Pair(Location::RegisterLocation(EAX), |
| + Location::RegisterLocation(EDX))); |
| } |
| return summary; |
| } |
| void UnboxedIntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - if (from() == kUnboxedMint) { |
| + if (from() == kUnboxedInt32 && to() == kUnboxedUint32) { |
| + // Representations are bitwise equivalent. |
| + ASSERT(locs()->out(0).reg() == locs()->in(0).reg()); |
| + } else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) { |
| + // Representations are bitwise equivalent. |
| + ASSERT(locs()->out(0).reg() == locs()->in(0).reg()); |
| + if (CanDeoptimize()) { |
| + Label* deopt = |
| + compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger); |
| + __ testl(locs()->out(0).reg(), locs()->out(0).reg()); |
| + __ j(NEGATIVE, deopt); |
| + } |
| + } else if (from() == kUnboxedMint) { |
| + // TODO(vegorov) kUnboxedMint -> kInt32 conversion is currently usually |
| + // dominated by a CheckSmi(BoxInteger(val)) which is an artifact of ordering |
| + // of optimization passes and the way we check smi-ness of values. |
| + // Optimize it away. |
| + ASSERT(to() == kUnboxedInt32 || to() == kUnboxedUint32); |
| PairLocation* in_pair = locs()->in(0).AsPairLocation(); |
| Register in_lo = in_pair->At(0).reg(); |
| + Register in_hi = in_pair->At(1).reg(); |
| Register out = locs()->out(0).reg(); |
| // Copy low word. |
| __ movl(out, in_lo); |
| - } else { |
| - ASSERT(from() == kUnboxedUint32); |
| + if (CanDeoptimize()) { |
| + Label* deopt = |
| + compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger); |
| + __ sarl(in_lo, Immediate(31)); |
| + __ cmpl(in_lo, in_hi); |
| + __ j(NOT_EQUAL, deopt); |
| + } |
| + } else if (from() == kUnboxedUint32) { |
| + ASSERT(to() == kUnboxedMint); |
| Register in = locs()->in(0).reg(); |
| PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| Register out_lo = out_pair->At(0).reg(); |
| @@ -6208,6 +6668,16 @@ void UnboxedIntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| __ movl(out_lo, in); |
| // Zero upper word. |
| __ xorl(out_hi, out_hi); |
| + } else if (from() == kUnboxedInt32) { |
| + ASSERT(to() == kUnboxedMint); |
| + PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| + Register out_lo = out_pair->At(0).reg(); |
| + Register out_hi = out_pair->At(1).reg(); |
| + ASSERT(locs()->in(0).reg() == EAX); |
| + ASSERT(out_lo == EAX && out_hi == EDX); |
| + __ cdq(); |
| + } else { |
| + UNREACHABLE(); |
| } |
| } |