Index: runtime/vm/intermediate_language_arm.cc |
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc |
index 073e59d46df7c6bb3ce0aa2ae5906dba77f83c77..14ab139fba4a7f315d63e62f09f893afbea99771 100644 |
--- a/runtime/vm/intermediate_language_arm.cc |
+++ b/runtime/vm/intermediate_language_arm.cc |
@@ -305,14 +305,24 @@ 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()) { |
- if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0) && |
- TargetCPUFeatures::neon_supported()) { |
- const QRegister dst = locs()->out(0).fpu_reg(); |
- __ veorq(dst, dst, dst); |
- } else { |
- const DRegister dst = EvenDRegisterOf(locs()->out(0).fpu_reg()); |
- const Register temp = locs()->temp(0).reg(); |
- __ LoadDImmediate(dst, Double::Cast(value()).value(), temp); |
+ switch (representation_) { |
+ case kUnboxedDouble: |
+ if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0) && |
+ TargetCPUFeatures::neon_supported()) { |
+ const QRegister dst = locs()->out(0).fpu_reg(); |
+ __ veorq(dst, dst, dst); |
+ } else { |
+ const DRegister dst = EvenDRegisterOf(locs()->out(0).fpu_reg()); |
+ const Register temp = locs()->temp(0).reg(); |
+ __ LoadDImmediate(dst, Double::Cast(value()).value(), temp); |
+ } |
+ break; |
+ case kUnboxedInt32: |
+ __ LoadImmediate(locs()->out(0).reg(), Smi::Cast(value()).Value()); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
} |
} |
} |
@@ -1186,7 +1196,7 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary(Isolate* isolate, |
true, // Load. |
&needs_base)) { |
// 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 { |
locs->set_in(1, Location::RequiresRegister()); |
} |
@@ -1387,7 +1397,7 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Isolate* isolate, |
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
// CanBeImmediateIndex must return false for unsafe smis. |
- locs->set_in(1, Location::Constant(index()->BoundConstant())); |
+ locs->set_in(1, Location::Constant(index()->definition()->AsConstant())); |
if (needs_base) { |
locs->set_temp(0, Location::RequiresRegister()); |
} |
@@ -2960,7 +2970,7 @@ LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, |
summary->set_in(0, Location::RequiresRegister()); |
if (RightIsPowerOfTwoConstant()) { |
ConstantInstr* right_constant = right()->definition()->AsConstant(); |
- summary->set_in(1, Location::Constant(right_constant->value())); |
+ summary->set_in(1, Location::Constant(right_constant)); |
summary->set_temp(0, Location::RequiresRegister()); |
} else { |
summary->set_in(1, Location::RequiresRegister()); |
@@ -3066,6 +3076,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); |
__ mul(result, left, IP); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
} |
@@ -3206,6 +3218,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ CheckMultSignedOverflow(IP, right, result, dtmp0, dtmp1, deopt); |
__ mul(result, IP, right); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
} |
@@ -3239,6 +3253,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ SmiUntag(IP, right); |
__ IntegerDivide(result, temp, IP, dtemp, DTMP); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
@@ -3262,6 +3278,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ SmiUntag(IP, right); |
__ IntegerDivide(result, temp, IP, dtemp, DTMP); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
__ SmiUntag(IP, right); |
@@ -3324,6 +3342,280 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
} |
+static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, |
+ BinaryInt32OpInstr* shift_left) { |
+ const bool is_truncating = shift_left->IsTruncating(); |
+ const LocationSummary& locs = *shift_left->locs(); |
+ const Register left = locs.in(0).reg(); |
+ const Register result = locs.out(0).reg(); |
+ 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()); |
+ // Immediate shift operation takes 5 bits for the count. |
+ const intptr_t kCountLimit = 0x1F; |
+ const intptr_t value = Smi::Cast(constant).Value(); |
+ if (value == 0) { |
+ __ MoveRegister(result, left); |
+ } 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) { |
+ __ mov(result, Operand(0)); |
+ } else { |
+ // Result is Mint or exception. |
+ __ b(deopt); |
+ } |
+ } else { |
+ if (!is_truncating) { |
+ // Check for overflow (preserve left). |
+ __ Lsl(IP, left, value); |
+ __ cmp(left, Operand(IP, ASR, value)); |
+ __ b(deopt, NE); // Overflow. |
+ } |
+ // Shift for result now we know there is no overflow. |
+ __ Lsl(result, left, value); |
+ } |
+} |
+ |
+ |
+LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate, |
+ bool opt) const { |
+ const intptr_t kNumInputs = 2; |
+ // Calculate number of temporaries. |
+ intptr_t num_temps = 0; |
+ if (((op_kind() == Token::kSHL) && !IsTruncating()) || |
+ (op_kind() == Token::kSHR)) { |
+ num_temps = 1; |
+ } else if ((op_kind() == Token::kMUL) && |
+ (TargetCPUFeatures::arm_version() != ARMv7)) { |
+ num_temps = 1; |
+ } |
+ LocationSummary* summary = new(isolate) LocationSummary( |
+ isolate, kNumInputs, num_temps, LocationSummary::kNoCall); |
+ summary->set_in(0, Location::RequiresRegister()); |
+ summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
+ if (((op_kind() == Token::kSHL) && !IsTruncating()) || |
+ (op_kind() == Token::kSHR)) { |
+ summary->set_temp(0, Location::RequiresRegister()); |
+ } |
+ if (op_kind() == Token::kMUL) { |
+ if (TargetCPUFeatures::arm_version() != ARMv7) { |
+ summary->set_temp(0, Location::RequiresFpuRegister()); |
+ } |
+ } |
+ // We make use of 3-operand instructions by not requiring result register |
+ // to be identical to first input register as on Intel. |
+ summary->set_out(0, Location::RequiresRegister()); |
+ return summary; |
+} |
+ |
+ |
+void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ if (op_kind() == Token::kSHL) { |
+ EmitInt32ShiftLeft(compiler, this); |
+ return; |
+ } |
+ |
+ const Register left = locs()->in(0).reg(); |
+ const Register result = locs()->out(0).reg(); |
+ 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 int32_t value = Smi::Cast(constant).Value(); |
+ switch (op_kind()) { |
+ case Token::kADD: { |
+ if (deopt == NULL) { |
+ __ AddImmediate(result, left, value); |
+ } else { |
+ __ AddImmediateSetFlags(result, left, value); |
+ __ b(deopt, VS); |
+ } |
+ break; |
+ } |
+ case Token::kSUB: { |
+ if (deopt == NULL) { |
+ __ AddImmediate(result, left, -value); |
+ } else { |
+ // Negating value and using AddImmediateSetFlags would not detect the |
+ // overflow when value == kMinInt32. |
+ __ SubImmediateSetFlags(result, left, value); |
+ __ b(deopt, VS); |
+ } |
+ break; |
+ } |
+ case Token::kMUL: { |
+ if (deopt == NULL) { |
+ if (value == 2) { |
+ __ mov(result, Operand(left, LSL, 1)); |
+ } else { |
+ __ LoadImmediate(IP, value); |
+ __ mul(result, left, IP); |
+ } |
+ } else { |
+ if (value == 2) { |
+ __ CompareImmediate(left, 0xC0000000); |
+ __ b(deopt, MI); |
+ __ mov(result, Operand(left, LSL, 1)); |
+ } else { |
+ if (TargetCPUFeatures::arm_version() == ARMv7) { |
+ __ LoadImmediate(IP, value); |
+ __ smull(result, IP, left, IP); |
+ // IP: result bits 32..63. |
+ __ cmp(IP, Operand(result, ASR, 31)); |
+ __ b(deopt, NE); |
+ } else if (TargetCPUFeatures::can_divide()) { |
+ const QRegister qtmp = locs()->temp(0).fpu_reg(); |
+ const DRegister dtmp0 = EvenDRegisterOf(qtmp); |
+ const DRegister dtmp1 = OddDRegisterOf(qtmp); |
+ __ LoadImmediate(IP, value); |
+ __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); |
+ __ mul(result, left, IP); |
+ } else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
+ __ b(deopt); |
+ } |
+ } |
+ } |
+ break; |
+ } |
+ case Token::kBIT_AND: { |
+ // No overflow check. |
+ Operand o; |
+ if (Operand::CanHold(value, &o)) { |
+ __ and_(result, left, o); |
+ } else if (Operand::CanHold(~value, &o)) { |
+ __ bic(result, left, o); |
+ } else { |
+ __ LoadImmediate(IP, value); |
+ __ and_(result, left, Operand(IP)); |
+ } |
+ break; |
+ } |
+ case Token::kBIT_OR: { |
+ // No overflow check. |
+ Operand o; |
+ if (Operand::CanHold(value, &o)) { |
+ __ orr(result, left, o); |
+ } else { |
+ __ LoadImmediate(IP, value); |
+ __ orr(result, left, Operand(IP)); |
+ } |
+ break; |
+ } |
+ case Token::kBIT_XOR: { |
+ // No overflow check. |
+ Operand o; |
+ if (Operand::CanHold(value, &o)) { |
+ __ eor(result, left, o); |
+ } else { |
+ __ LoadImmediate(IP, value); |
+ __ eor(result, left, Operand(IP)); |
+ } |
+ 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. |
+ __ MoveRegister(result, left); |
+ break; |
+ } else if (value < 0) { |
+ // TODO(vegorov): should be handled outside. |
+ __ b(deopt); |
+ break; |
+ } |
+ |
+ if (value >= kCountLimit) { |
+ __ Asr(result, left, kCountLimit); |
+ } else { |
+ __ Asr(result, left, value); |
+ } |
+ break; |
+ } |
+ |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ |
+ const Register right = locs()->in(1).reg(); |
+ switch (op_kind()) { |
+ case Token::kADD: { |
+ if (deopt == NULL) { |
+ __ add(result, left, Operand(right)); |
+ } else { |
+ __ adds(result, left, Operand(right)); |
+ __ b(deopt, VS); |
+ } |
+ break; |
+ } |
+ case Token::kSUB: { |
+ if (deopt == NULL) { |
+ __ sub(result, left, Operand(right)); |
+ } else { |
+ __ subs(result, left, Operand(right)); |
+ __ b(deopt, VS); |
+ } |
+ break; |
+ } |
+ case Token::kMUL: { |
+ if (deopt == NULL) { |
+ __ mul(result, left, right); |
+ } else { |
+ if (TargetCPUFeatures::arm_version() == ARMv7) { |
+ __ smull(result, IP, left, right); |
+ // IP: result bits 32..63. |
+ __ cmp(IP, Operand(result, ASR, 31)); |
+ __ b(deopt, NE); |
+ } else if (TargetCPUFeatures::can_divide()) { |
+ const QRegister qtmp = locs()->temp(0).fpu_reg(); |
+ const DRegister dtmp0 = EvenDRegisterOf(qtmp); |
+ const DRegister dtmp1 = OddDRegisterOf(qtmp); |
+ __ CheckMultSignedOverflow(left, right, result, dtmp0, dtmp1, deopt); |
+ __ mul(result, left, right); |
+ } else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
+ __ b(deopt); |
+ } |
+ } |
+ break; |
+ } |
+ case Token::kBIT_AND: { |
+ // No overflow check. |
+ __ and_(result, left, Operand(right)); |
+ break; |
+ } |
+ case Token::kBIT_OR: { |
+ // No overflow check. |
+ __ orr(result, left, Operand(right)); |
+ break; |
+ } |
+ case Token::kBIT_XOR: { |
+ // No overflow check. |
+ __ eor(result, left, Operand(right)); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+} |
+ |
+ |
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate, |
bool opt) const { |
intptr_t left_cid = left()->Type()->ToCid(); |
@@ -5039,6 +5331,26 @@ 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::RequiresRegister()); |
+ result->set_out(0, Location::RequiresFpuRegister()); |
+ return result; |
+} |
+ |
+ |
+void Int32ToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ const Register value = locs()->in(0).reg(); |
+ const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg()); |
+ __ vmovsr(STMP, value); |
+ __ vcvtdi(result, STMP); |
+} |
+ |
+ |
LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Isolate* isolate, |
bool opt) const { |
const intptr_t kNumInputs = 1; |
@@ -5482,6 +5794,8 @@ void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ SmiUntag(IP, right); |
__ IntegerDivide(result_div, temp, IP, dtemp, DTMP); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
@@ -6001,6 +6315,8 @@ void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
__ b(deopt, NE); |
__ smull(out_lo, out_hi, left_lo, right_lo); |
} else { |
+ // TODO(vegorov): never emit this instruction if hardware does not |
+ // support it! This will lead to deopt cycle penalizing the code. |
__ b(deopt); |
} |
break; |
@@ -6218,16 +6534,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; |
@@ -6480,6 +6786,134 @@ void UnboxUint32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
} |
+LocationSummary* BoxInt32Instr::MakeLocationSummary(Isolate* isolate, |
+ bool opt) const { |
+ const intptr_t kNumInputs = 1; |
+ const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1; |
+ LocationSummary* summary = new(isolate) LocationSummary( |
+ isolate, |
+ kNumInputs, |
+ kNumTemps, |
+ ValueFitsSmi() ? LocationSummary::kNoCall |
+ : LocationSummary::kCallOnSlowPath); |
+ summary->set_in(0, Location::RequiresRegister()); |
+ if (!ValueFitsSmi()) { |
+ summary->set_temp(0, Location::RequiresRegister()); |
+ } |
+ summary->set_out(0, Location::RequiresRegister()); |
+ return summary; |
+} |
+ |
+ |
+void BoxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ Register value = locs()->in(0).reg(); |
+ Register out = locs()->out(0).reg(); |
+ ASSERT(value != out); |
+ |
+ __ Lsl(out, value, 1); |
+ if (!ValueFitsSmi()) { |
+ Register temp = locs()->temp(0).reg(); |
+ Label done; |
+ __ cmp(value, Operand(out, ASR, 1)); |
+ __ b(&done, EQ); |
+ BoxAllocationSlowPath::Allocate( |
+ compiler, |
+ this, |
+ compiler->mint_class(), |
+ out, |
+ temp); |
+ __ Asr(temp, value, kBitsPerWord - 1); |
+ __ StoreToOffset(kWord, |
+ value, |
+ out, |
+ Mint::value_offset() - kHeapObjectTag); |
+ __ StoreToOffset(kWord, |
+ temp, |
+ out, |
+ Mint::value_offset() - kHeapObjectTag + kWordSize); |
+ __ Bind(&done); |
+ } |
+} |
+ |
+ |
+ |
+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 = |
+ ((value_cid == kMintCid) || (value_cid == kSmiCid)) ? 0 : 1; |
+ 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, Location::RequiresRegister()); |
+ return summary; |
+} |
+ |
+ |
+static void LoadInt32FromMint(FlowGraphCompiler* compiler, |
+ Register mint, |
+ Register result, |
+ Register temp, |
+ Label* deopt) { |
+ __ LoadFromOffset(kWord, |
+ result, |
+ mint, |
+ Mint::value_offset() - kHeapObjectTag); |
+ if (deopt != NULL) { |
+ __ LoadFromOffset(kWord, |
+ temp, |
+ mint, |
+ Mint::value_offset() - kHeapObjectTag + kWordSize); |
+ __ cmp(temp, Operand(result, ASR, kBitsPerWord - 1)); |
+ __ b(deopt, NE); |
+ } |
+} |
+ |
+ |
+void UnboxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ const intptr_t value_cid = value()->Type()->ToCid(); |
+ const Register value = locs()->in(0).reg(); |
+ const Register out = locs()->out(0).reg(); |
+ ASSERT(value != out); |
+ |
+ 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, |
+ out, |
+ temp, |
+ deopt); |
+ } else if (value_cid == kSmiCid) { |
+ __ SmiUntag(out, value); |
+ } else { |
+ Register temp = locs()->temp(0).reg(); |
+ Label* deopt = compiler->AddDeoptStub(deopt_id_, |
+ ICData::kDeoptUnboxInteger); |
+ Label done; |
+ __ tst(value, Operand(kSmiTagMask)); |
+ // Smi case. |
+ __ mov(out, Operand(value), EQ); |
+ __ SmiUntag(out, EQ); |
+ __ b(&done, EQ); |
+ // Mint case. |
+ __ CompareClassId(value, kMintCid, temp); |
+ __ b(deopt, NE); |
+ LoadInt32FromMint(compiler, |
+ value, |
+ out, |
+ temp, |
+ deopt); |
+ __ Bind(&done); |
+ } |
+} |
+ |
+ |
LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate, |
bool opt) const { |
const intptr_t kNumInputs = 1; |
@@ -6487,36 +6921,71 @@ LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate, |
LocationSummary* summary = new(isolate) LocationSummary( |
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
if (from() == kUnboxedMint) { |
+ ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32)); |
summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
Location::RequiresRegister())); |
summary->set_out(0, Location::RequiresRegister()); |
- } else { |
- ASSERT(from() == kUnboxedUint32); |
+ } else if (to() == kUnboxedMint) { |
+ ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32)); |
summary->set_in(0, Location::RequiresRegister()); |
summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
Location::RequiresRegister())); |
+ } else { |
+ ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32)); |
+ ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32)); |
+ summary->set_in(0, Location::RequiresRegister()); |
+ summary->set_out(0, Location::SameAsFirstInput()); |
} |
return summary; |
} |
void UnboxedIntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
- if (from() == kUnboxedMint) { |
+ if (from() == kUnboxedInt32 && to() == kUnboxedUint32) { |
+ const Register out = locs()->out(0).reg(); |
+ // Representations are bitwise equivalent. |
+ ASSERT(out == locs()->in(0).reg()); |
+ } else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) { |
+ const Register out = locs()->out(0).reg(); |
+ // Representations are bitwise equivalent. |
+ ASSERT(out == locs()->in(0).reg()); |
+ if (CanDeoptimize()) { |
+ Label* deopt = |
+ compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger); |
+ __ tst(out, Operand(out)); |
+ __ b(deopt, MI); |
+ } |
+ } else if (from() == kUnboxedMint) { |
+ ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32); |
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. |
__ mov(out, Operand(in_lo)); |
- } else { |
- ASSERT(from() == kUnboxedUint32); |
+ if (CanDeoptimize()) { |
+ Label* deopt = |
+ compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger); |
+ ASSERT(to() == kUnboxedInt32); |
+ __ cmp(in_hi, Operand(in_lo, ASR, kBitsPerWord - 1)); |
+ __ b(deopt, NE); |
+ } |
+ } else if (from() == kUnboxedUint32 || from() == kUnboxedInt32) { |
+ ASSERT(to() == kUnboxedMint); |
Register in = locs()->in(0).reg(); |
PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
Register out_lo = out_pair->At(0).reg(); |
Register out_hi = out_pair->At(1).reg(); |
// Copy low word. |
__ mov(out_lo, Operand(in)); |
- // Zero upper word. |
- __ eor(out_hi, out_hi, Operand(out_hi)); |
+ if (from() == kUnboxedUint32) { |
+ __ eor(out_hi, out_hi, Operand(out_hi)); |
+ } else { |
+ ASSERT(from() == kUnboxedInt32); |
+ __ mov(out_hi, Operand(in, ASR, kBitsPerWord - 1)); |
+ } |
+ } else { |
+ UNREACHABLE(); |
} |
} |