Chromium Code Reviews| Index: runtime/vm/intermediate_language_x64.cc |
| diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc |
| index 741698aceb24da4e444c8194a451bb5c3b2e3460..d271c1340a1bd3fdffe7980a958d76574aa339f2 100644 |
| --- a/runtime/vm/intermediate_language_x64.cc |
| +++ b/runtime/vm/intermediate_language_x64.cc |
| @@ -373,6 +373,15 @@ static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| LocationSummary* EqualityCompareInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| const intptr_t kNumInputs = 2; |
| + if (operation_cid() == kMintCid) { |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* locs = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + locs->set_in(0, Location::RequiresRegister()); |
| + locs->set_in(1, Location::RequiresRegister()); |
| + locs->set_out(0, Location::RequiresRegister()); |
| + return locs; |
| + } |
| if (operation_cid() == kDoubleCid) { |
| const intptr_t kNumTemps = 0; |
| LocationSummary* locs = new(isolate) LocationSummary( |
| @@ -482,6 +491,37 @@ static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| } |
| +static Condition TokenKindToMintCondition(Token::Kind kind) { |
|
Vyacheslav Egorov (Google)
2014/10/05 18:46:59
I don't think there is a need to have this duplica
Cutch
2014/10/06 23:55:25
Done.
|
| + switch (kind) { |
| + case Token::kEQ: return EQUAL; |
| + case Token::kNE: return NOT_EQUAL; |
| + case Token::kLT: return LESS; |
| + case Token::kGT: return GREATER; |
| + case Token::kLTE: return LESS_EQUAL; |
| + case Token::kGTE: return GREATER_EQUAL; |
| + default: |
| + UNREACHABLE(); |
| + return OVERFLOW; |
| + } |
| +} |
| + |
| + |
| +static Condition EmitMintComparisonOp(FlowGraphCompiler* compiler, |
|
Vyacheslav Egorov (Google)
2014/10/05 18:47:00
This is essentially the same as EmitSmiComparisonO
Cutch
2014/10/06 23:55:25
Done.
|
| + const LocationSummary& locs, |
| + Token::Kind kind, |
| + BranchLabels labels) { |
| + const Location left = locs.in(0); |
| + const Location right = locs.in(1); |
| + |
| + ASSERT(!left.IsConstant() || !right.IsConstant()); |
| + |
| + Condition true_condition = TokenKindToMintCondition(kind); |
| + |
| + __ cmpq(left.reg(), right.reg()); |
| + |
| + return true_condition; |
| +} |
| + |
| static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| switch (kind) { |
| case Token::kEQ: return EQUAL; |
| @@ -518,6 +558,8 @@ Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| BranchLabels labels) { |
| if (operation_cid() == kSmiCid) { |
| return EmitSmiComparisonOp(compiler, *locs(), kind(), labels); |
| + } else if (operation_cid() == kMintCid) { |
| + return EmitMintComparisonOp(compiler, *locs(), kind(), labels); |
| } else { |
| ASSERT(operation_cid() == kDoubleCid); |
| return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); |
| @@ -683,6 +725,13 @@ LocationSummary* RelationalOpInstr::MakeLocationSummary(Isolate* isolate, |
| summary->set_in(1, Location::RequiresFpuRegister()); |
| summary->set_out(0, Location::RequiresRegister()); |
| return summary; |
| + } else if (operation_cid() == kMintCid) { |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_in(1, Location::RequiresRegister()); |
| + summary->set_out(0, Location::RequiresRegister()); |
| + return summary; |
| } |
| ASSERT(operation_cid() == kSmiCid); |
| LocationSummary* summary = new(isolate) LocationSummary( |
| @@ -702,6 +751,8 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| BranchLabels labels) { |
| if (operation_cid() == kSmiCid) { |
| return EmitSmiComparisonOp(compiler, *locs(), kind(), labels); |
| + } else if (operation_cid() == kMintCid) { |
| + return EmitMintComparisonOp(compiler, *locs(), kind(), labels); |
| } else { |
| ASSERT(operation_cid() == kDoubleCid); |
| return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); |
| @@ -948,6 +999,9 @@ CompileType LoadIndexedInstr::ComputeType() const { |
| case kTypedDataUint32ArrayCid: |
| return CompileType::FromCid(kSmiCid); |
| + case kTypedDataInt64ArrayCid: |
| + return CompileType::Int(); |
| + |
| default: |
| UNIMPLEMENTED(); |
| return CompileType::Dynamic(); |
| @@ -971,6 +1025,8 @@ Representation LoadIndexedInstr::representation() const { |
| case kTypedDataInt32ArrayCid: |
| case kTypedDataUint32ArrayCid: |
| return kTagged; |
| + case kTypedDataInt64ArrayCid: |
| + return kUnboxedMint; |
| case kTypedDataFloat32ArrayCid: |
| case kTypedDataFloat64ArrayCid: |
| return kUnboxedDouble; |
| @@ -1086,6 +1142,9 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| __ movl(result, element_address); |
| __ SmiTag(result); |
| break; |
| + case kTypedDataInt64ArrayCid: |
| + __ movq(result, element_address); |
| + break; |
| default: |
| ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); |
| __ movq(result, element_address); |
| @@ -1114,6 +1173,8 @@ Representation StoreIndexedInstr::RequiredInputRepresentation( |
| return kUnboxedInt32; |
| case kTypedDataUint32ArrayCid: |
| return kUnboxedUint32; |
| + case kTypedDataInt64ArrayCid: |
| + return kUnboxedMint; |
| case kTypedDataFloat32ArrayCid: |
| case kTypedDataFloat64ArrayCid: |
| return kUnboxedDouble; |
| @@ -1171,6 +1232,9 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Isolate* isolate, |
| // Writable register because the value must be untagged before storing. |
| locs->set_in(2, Location::WritableRegister()); |
| break; |
| + case kTypedDataInt64ArrayCid: |
| + locs->set_in(2, Location::RequiresRegister()); |
| + break; |
| case kTypedDataFloat32ArrayCid: |
| case kTypedDataFloat64ArrayCid: |
| // TODO(srdjan): Support Float64 constants. |
| @@ -1272,7 +1336,12 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| case kTypedDataUint32ArrayCid: { |
| Register value = locs()->in(2).reg(); |
| __ movl(element_address, value); |
| - break; |
| + break; |
| + } |
| + case kTypedDataInt64ArrayCid: { |
| + Register value = locs()->in(2).reg(); |
| + __ movq(element_address, value); |
| + break; |
| } |
| case kTypedDataFloat32ArrayCid: |
| __ movss(element_address, locs()->in(2).fpu_reg()); |
| @@ -5440,67 +5509,284 @@ void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| LocationSummary* UnboxIntegerInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* locs = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + locs->set_in(0, Location::RequiresRegister()); |
| + locs->set_out(0, Location::RequiresRegister()); |
| + return locs; |
| } |
| void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + const intptr_t value_cid = value()->Type()->ToCid(); |
| + const Register value = locs()->in(0).reg(); |
| + const Register result = locs()->out(0).reg(); |
| + |
| + if (value_cid == kMintCid) { |
| + __ movq(result, FieldAddress(value, Mint::value_offset())); |
| + } else if (value_cid == kSmiCid) { |
| + __ movq(result, value); |
| + __ SmiUntag(result); |
| + } else { |
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, |
| + ICData::kDeoptUnboxInteger); |
| + Label is_smi, done; |
| + __ testq(value, Immediate(kSmiTagMask)); |
|
Vyacheslav Egorov (Google)
2014/10/05 18:46:59
You can produce much smaller instruction sequence
Cutch
2014/10/06 23:55:26
Done.
|
| + __ j(ZERO, &is_smi); |
| + __ CompareClassId(value, kMintCid); |
| + __ j(NOT_EQUAL, deopt); |
| + __ movq(result, FieldAddress(value, Mint::value_offset())); |
| + __ jmp(&done); |
| + __ Bind(&is_smi); |
| + __ movq(result, value); |
| + __ SmiUntag(result); |
| + __ Bind(&done); |
| + } |
| } |
| LocationSummary* BoxIntegerInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, is_smi() |
| + ? LocationSummary::kNoCall |
| + : LocationSummary::kCallOnSlowPath); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::RequiresRegister()); |
| + return summary; |
| } |
| void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + const Register out = locs()->out(0).reg(); |
| + const Register value = locs()->in(0).reg(); |
| + |
| + if (is_smi()) { |
| + __ movq(out, value); |
| + __ SmiTag(out); |
| + return; |
| + } |
| + |
| + Label is_smi; |
| + Label done; |
| + // Tag, Untag, and then compare with original value. |
| + __ movq(out, value); |
| + __ SmiTag(out); |
| + __ SmiUntag(out); |
|
Vyacheslav Egorov (Google)
2014/10/05 18:46:59
__ movq(out, value);
__ SmiTag(out); // shrl set
Cutch
2014/10/06 23:55:25
Done.
|
| + __ cmpq(out, value); |
| + __ j(EQUAL, &is_smi); |
| + BoxAllocationSlowPath::Allocate( |
| + compiler, this, compiler->mint_class(), out); |
| + __ movq(FieldAddress(out, Mint::value_offset()), value); |
| + __ jmp(&done); |
| + __ Bind(&is_smi); |
| + __ movq(out, value); |
| + __ SmiTag(out); |
| + __ Bind(&done); |
| } |
| LocationSummary* BinaryMintOpInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 2; |
| + 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::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| } |
| void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + const Register left = locs()->in(0).reg(); |
| + const Register right = locs()->in(1).reg(); |
| + const Register out = locs()->out(0).reg(); |
| + |
| + ASSERT(out == left); |
| + |
| + Label* deopt = NULL; |
| + if (CanDeoptimize()) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp); |
| + } |
| + |
| + switch (op_kind()) { |
|
Vyacheslav Egorov (Google)
2014/10/05 18:46:59
use EmitIntegerArithmetic
Cutch
2014/10/06 23:55:25
EmitIntegerArithmetic does 32-bit operations, thes
Vyacheslav Egorov (Google)
2014/10/07 12:03:50
Ack, true, shame on me!
I was dwelling in ia32-t
Cutch
2014/10/21 17:42:11
Done.
|
| + case Token::kBIT_AND: |
| + __ andq(left, right); |
| + break; |
| + case Token::kBIT_OR: |
| + __ orq(left, right); |
| + break; |
| + case Token::kBIT_XOR: |
| + __ xorq(left, right); |
| + break; |
| + case Token::kADD: |
| + case Token::kSUB: { |
| + if (op_kind() == Token::kADD) { |
| + __ addq(left, right); |
| + } else { |
| + __ subq(left, right); |
| + } |
| + if (can_overflow()) { |
| + ASSERT(deopt != NULL); |
| + __ j(OVERFLOW, deopt); |
| + } |
| + break; |
| + } |
| + case Token::kMUL: |
| + __ imulq(left, right); |
| + ASSERT(deopt != NULL); |
| + __ j(OVERFLOW, deopt); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + EmitJavascriptOverflowCheck(compiler, range(), deopt, out); |
| + } |
| } |
| LocationSummary* UnaryMintOpInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| } |
| void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + ASSERT(op_kind() == Token::kBIT_NOT); |
| + const Register left = locs()->in(0).reg(); |
| + const Register out = locs()->out(0).reg(); |
| + ASSERT(out == left); |
| + |
| + Label* deopt = NULL; |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp); |
| + } |
| + |
| + __ notq(left); |
| + |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + EmitJavascriptOverflowCheck(compiler, range(), deopt, out); |
| + } |
| } |
| +static const intptr_t kMintShiftCountLimit = 63; |
| + |
| bool ShiftMintOpInstr::has_shift_count_check() const { |
| - UNREACHABLE(); |
| - return false; |
| + return !RangeUtils::IsWithin( |
| + right()->definition()->range(), 0, kMintShiftCountLimit); |
| } |
| LocationSummary* ShiftMintOpInstr::MakeLocationSummary(Isolate* isolate, |
| bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 2; |
| + const intptr_t kNumTemps = can_overflow() ? 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(), RCX)); |
| + if (kNumTemps > 0) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + } |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| } |
| void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + const Register left = locs()->in(0).reg(); |
| + const Register out = locs()->out(0).reg(); |
| + ASSERT(left == out); |
| + |
| + Label* deopt = NULL; |
| + if (CanDeoptimize()) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp); |
| + } |
| + if (locs()->in(1).IsConstant()) { |
| + // Code for a constant shift amount. |
| + ASSERT(locs()->in(1).constant().IsSmi()); |
| + const int64_t shift = |
| + reinterpret_cast<int64_t>(locs()->in(1).constant().raw()) >> 1; |
| + if ((shift < 0) || (shift > kMintShiftCountLimit)) { |
|
Vyacheslav Egorov (Google)
2014/10/05 18:47:00
These cases should be handled in the Canonicalize
Cutch
2014/10/06 23:55:26
Done.
|
| + __ jmp(deopt); |
| + return; |
| + } else if (shift == 0) { |
| + // Nothing to do for zero shift amount. |
| + return; |
| + } |
| + switch (op_kind()) { |
| + case Token::kSHR: |
| + __ sarq(left, Immediate(shift)); |
| + break; |
| + case Token::kSHL: { |
| + if (can_overflow()) { |
| + // Check for overflow. |
| + Register temp = locs()->temp(0).reg(); |
| + __ movq(temp, left); |
| + __ shlq(left, Immediate(shift)); |
| + __ sarq(left, Immediate(shift)); |
| + __ cmpq(left, temp); |
| + __ j(NOT_EQUAL, deopt); // Overflow. |
| + } |
| + // Shift for result now we know there is no overflow. |
| + __ shlq(left, Immediate(shift)); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } else { |
| + // Code for a variable shift amount. |
| + // Deoptimize if shift count is > 63. |
| + // sarl operation masks the count to 5 bits and |
| + // shrd is undefined with count > operand size (32) |
| + __ SmiUntag(RCX); |
| + if (has_shift_count_check()) { |
| + __ cmpq(RCX, Immediate(kMintShiftCountLimit)); |
| + __ j(ABOVE, deopt); |
| + } |
| + Label done, large_shift; |
| + switch (op_kind()) { |
| + case Token::kSHR: { |
| + __ sarq(left, RCX); |
| + break; |
| + } |
| + case Token::kSHL: { |
| + if (can_overflow()) { |
| + // Check for overflow. |
| + Register temp = locs()->temp(0).reg(); |
| + __ movq(temp, left); |
| + __ shlq(left, RCX); |
| + __ sarq(left, RCX); |
| + __ cmpq(left, temp); |
| + __ j(NOT_EQUAL, deopt); // Overflow. |
| + } |
| + // Shift for result now we know there is no overflow. |
| + __ shlq(left, RCX); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + EmitJavascriptOverflowCheck(compiler, range(), deopt, out); |
| + } |
| } |
| @@ -5519,9 +5805,188 @@ CompileType UnaryUint32OpInstr::ComputeType() const { |
| } |
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(BinaryUint32OpInstr) |
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(ShiftUint32OpInstr) |
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(UnaryUint32OpInstr) |
| +LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t kNumInputs = 2; |
| + const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0; |
| + LocationSummary* summary = new(isolate) LocationSummary( |
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_in(1, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| +} |
| + |
| + |
| +template<typename OperandType> |
| +static void EmitIntegerArithmetic(FlowGraphCompiler* compiler, |
| + Token::Kind op_kind, |
| + Register left, |
| + const OperandType& right, |
| + Label* deopt) { |
| + switch (op_kind) { |
| + case Token::kADD: |
| + __ addl(left, right); |
| + break; |
| + case Token::kSUB: |
| + __ subl(left, right); |
| + break; |
| + case Token::kBIT_AND: |
| + __ andl(left, right); |
| + break; |
| + case Token::kBIT_OR: |
| + __ orl(left, right); |
| + break; |
| + case Token::kBIT_XOR: |
| + __ xorl(left, right); |
| + break; |
| + case Token::kMUL: |
| + __ imull(left, right); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + if (deopt != NULL) __ j(OVERFLOW, deopt); |
| +} |
| + |
| + |
| +void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + Register left = locs()->in(0).reg(); |
| + Register right = locs()->in(1).reg(); |
| + Register out = locs()->out(0).reg(); |
| + ASSERT(out == left); |
| + switch (op_kind()) { |
| + case Token::kBIT_AND: |
| + case Token::kBIT_OR: |
| + case Token::kBIT_XOR: |
| + case Token::kADD: |
| + case Token::kSUB: |
| + case Token::kMUL: |
| + EmitIntegerArithmetic(compiler, op_kind(), left, right, NULL); |
| + return; |
| + default: |
| + UNREACHABLE(); |
| + } |
| +} |
| + |
| + |
| +LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Isolate* isolate, |
| + bool opt) const { |
| + const intptr_t kNumInputs = 2; |
| + 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(), RCX)); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| +} |
| + |
| + |
| +void ShiftUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + const intptr_t kShifterLimit = 31; |
| + |
| + Register left = locs()->in(0).reg(); |
| + Register out = locs()->out(0).reg(); |
| + ASSERT(left == out); |
| + |
| + |
| + Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp); |
| + |
| + if (locs()->in(1).IsConstant()) { |
| + // Shifter is constant. |
| + |
| + const Object& constant = locs()->in(1).constant(); |
| + ASSERT(constant.IsSmi()); |
| + const intptr_t shift_value = Smi::Cast(constant).Value(); |
| + |
| + // Check constant shift value. |
| + if (shift_value == 0) { |
|
Vyacheslav Egorov (Google)
2014/10/05 18:46:59
Should be handled in the Canonicalize
Cutch
2014/10/06 23:55:25
Done.
|
| + // Nothing to do. |
| + } else if (shift_value < 0) { |
| + // Invalid shift value. |
| + __ jmp(deopt); |
| + } else if (shift_value > kShifterLimit) { |
| + // Result is 0. |
| + __ xorq(left, left); |
| + } else { |
| + // Do the shift: (shift_value > 0) && (shift_value <= kShifterLimit). |
| + switch (op_kind()) { |
| + case Token::kSHR: |
| + __ shrl(left, Immediate(shift_value)); |
| + break; |
| + case Token::kSHL: |
| + __ shll(left, Immediate(shift_value)); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| + return; |
| + } |
| + |
| + // Non constant shift value. |
| + |
| + Register shifter = locs()->in(1).reg(); |
| + ASSERT(shifter == RCX); |
| + |
| + Label done; |
| + Label zero; |
| + |
| + // TODO(johnmccutchan): Use range information to avoid these checks. |
| + __ SmiUntag(shifter); |
| + __ cmpq(shifter, Immediate(0)); |
| + // If shift value is < 0, deoptimize. |
| + __ j(NEGATIVE, deopt); |
| + __ cmpq(shifter, Immediate(kShifterLimit)); |
| + // If shift value is >= 32, return zero. |
| + __ j(ABOVE, &zero); |
| + |
| + // Do the shift. |
| + switch (op_kind()) { |
| + case Token::kSHR: |
| + __ shrl(left, shifter); |
| + __ jmp(&done); |
| + break; |
| + case Token::kSHL: |
| + __ shll(left, shifter); |
| + __ jmp(&done); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + |
| + __ Bind(&zero); |
| + // Shift was greater than 31 bits, just return zero. |
| + __ xorq(left, left); |
| + |
| + // Exit path. |
| + __ Bind(&done); |
| +} |
| + |
| + |
| +LocationSummary* UnaryUint32OpInstr::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); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| + return summary; |
| +} |
| + |
| + |
| +void UnaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + Register out = locs()->out(0).reg(); |
| + ASSERT(locs()->in(0).reg() == out); |
| + |
| + ASSERT(op_kind() == Token::kBIT_NOT); |
| + |
| + __ notl(out); |
| +} |
| + |
| + |
| DEFINE_UNIMPLEMENTED_INSTRUCTION(BinaryInt32OpInstr) |
| @@ -5613,9 +6078,13 @@ LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate, |
| LocationSummary* summary = new(isolate) LocationSummary( |
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| if (from() == kUnboxedMint) { |
| - UNREACHABLE(); |
| + ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32)); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| } else if (to() == kUnboxedMint) { |
| - UNREACHABLE(); |
| + ASSERT((from() == kUnboxedInt32) || (from() == kUnboxedUint32)); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::SameAsFirstInput()); |
| } else { |
| ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32)); |
| ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32)); |
| @@ -5647,10 +6116,33 @@ void UnboxedIntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| __ j(NEGATIVE, deopt); |
| } |
| } else if (from() == kUnboxedMint) { |
| - UNREACHABLE(); |
| + ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32)); |
| + const Register value = locs()->in(0).reg(); |
| + const Register out = locs()->out(0).reg(); |
| + // Copy low. |
| + __ movl(out, value); |
| + if (CanDeoptimize()) { |
| + Label* deopt = |
| + compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger); |
| + // Sign extend. |
| + __ movsxd(out, out); |
|
Vyacheslav Egorov (Google)
2014/10/05 18:47:00
you could do __ movsxd(out, value) to begin with.
Cutch
2014/10/06 23:55:26
Done.
|
| + // Compare with original value. |
| + __ cmpq(out, value); |
| + // Value cannot be held in Int32, deopt. |
| + __ j(NOT_EQUAL, deopt); |
| + } |
| } else if (to() == kUnboxedMint) { |
| ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32)); |
| - UNREACHABLE(); |
| + const Register value = locs()->in(0).reg(); |
| + const Register out = locs()->out(0).reg(); |
| + if (from() == kUnboxedUint32) { |
| + // Zero extend. |
| + __ movl(out, value); |
| + } else { |
| + // Sign extend. |
| + ASSERT(from() == kUnboxedInt32); |
| + __ movsxd(out, value); |
| + } |
| } else { |
| UNREACHABLE(); |
| } |