Chromium Code Reviews| Index: runtime/vm/intermediate_language_arm.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language_arm.cc (revision 34189) |
| +++ runtime/vm/intermediate_language_arm.cc (working copy) |
| @@ -332,12 +332,14 @@ |
| LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 2; |
| if (operation_cid() == kMintCid) { |
| - const intptr_t kNumTemps = 1; |
| + const intptr_t kNumTemps = 3; |
| LocationSummary* locs = |
| new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| locs->set_in(0, Location::RequiresFpuRegister()); |
| locs->set_in(1, Location::RequiresFpuRegister()); |
| - locs->set_temp(0, Location::RequiresRegister()); |
| + locs->set_temp(0, Location::RequiresFpuRegister()); |
| + locs->set_temp(1, Location::RequiresRegister()); |
| + locs->set_temp(2, Location::RequiresRegister()); |
| locs->set_out(Location::RequiresRegister()); |
| return locs; |
| } |
| @@ -446,6 +448,101 @@ |
| } |
| +static Condition TokenKindToMintCondition(Token::Kind kind) { |
| + switch (kind) { |
| + case Token::kEQ: return EQ; |
| + case Token::kNE: return NE; |
| + case Token::kLT: return LT; |
| + case Token::kGT: return GT; |
| + case Token::kLTE: return LE; |
| + case Token::kGTE: return GE; |
| + default: |
| + UNREACHABLE(); |
| + return VS; |
| + } |
| +} |
| + |
| + |
| +static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| + LocationSummary* locs, |
| + Token::Kind kind) { |
| + ASSERT(Token::IsEqualityOperator(kind)); |
| + QRegister left = locs->in(0).fpu_reg(); |
| + QRegister right = locs->in(1).fpu_reg(); |
| + QRegister tmpq = locs->temp(0).fpu_reg(); |
| + Register tmp_lo = locs->temp(1).reg(); |
| + Register tmp_hi = locs->temp(2).reg(); |
| + |
| + __ vceqqi(kWord, tmpq, left, right); |
| + __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(tmpq)); |
| + // tmp_lo and tmp_hi must both be 0xffffffff. |
| + __ and_(tmp_lo, tmp_lo, ShifterOperand(tmp_hi)); |
| + |
| + Condition true_condition = TokenKindToMintCondition(kind); |
| + __ CompareImmediate(tmp_lo, 0xffffffff); |
| + return true_condition; |
| +} |
| + |
| + |
| +static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
| + LocationSummary* locs, |
| + Token::Kind kind) { |
| + QRegister left = locs->in(0).fpu_reg(); |
| + QRegister right = locs->in(1).fpu_reg(); |
| + DRegister dleft0 = EvenDRegisterOf(left); |
| + DRegister dright0 = EvenDRegisterOf(right); |
| + SRegister sleft0 = EvenSRegisterOf(dleft0); |
| + SRegister sleft1 = OddSRegisterOf(dleft0); |
| + SRegister sright0 = EvenSRegisterOf(dright0); |
| + SRegister sright1 = OddSRegisterOf(dright0); |
| + |
| + Register tmp_left = locs->temp(0).reg(); |
| + Register tmp_right = locs->temp(1).reg(); |
| + |
| + // 64-bit comparison |
| + Condition hi_true_cond, hi_false_cond, lo_false_cond; |
| + switch (kind) { |
| + case Token::kLT: |
| + case Token::kLTE: |
| + hi_true_cond = LT; |
| + hi_false_cond = GT; |
| + lo_false_cond = (kind == Token::kLT) ? CS : HI; |
| + break; |
| + case Token::kGT: |
| + case Token::kGTE: |
| + hi_true_cond = GT; |
| + hi_false_cond = LT; |
| + lo_false_cond = (kind == Token::kGT) ? LS : CC; |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + hi_true_cond = hi_false_cond = lo_false_cond = VS; |
| + } |
| + |
| + Label is_true, is_false, done; |
| + __ vmovrs(tmp_left, sleft1); |
| + __ vmovrs(tmp_right, sright1); |
| + __ cmp(tmp_left, ShifterOperand(tmp_right)); |
| + __ b(&is_false, hi_false_cond); |
| + __ b(&is_true, hi_true_cond); |
| + |
| + __ vmovrs(tmp_left, sleft0); |
| + __ vmovrs(tmp_right, sright0); |
| + __ cmp(tmp_left, ShifterOperand(tmp_right)); |
| + __ b(&is_false, lo_false_cond); |
| + // Else is true. |
| + __ b(&is_true); |
| + |
| + __ Bind(&is_false); |
| + __ LoadImmediate(tmp_left, 0); |
| + __ b(&done); |
| + __ Bind(&is_true); |
| + __ LoadImmediate(tmp_left, 1); |
| + __ Bind(&done); |
| + return NegateCondition(lo_false_cond); |
| +} |
| + |
| + |
| static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| switch (kind) { |
| case Token::kEQ: return EQ; |
| @@ -479,6 +576,8 @@ |
| BranchLabels labels) { |
| if (operation_cid() == kSmiCid) { |
| return EmitSmiComparisonOp(compiler, locs(), kind()); |
| + } else if (operation_cid() == kMintCid) { |
| + return EmitUnboxedMintEqualityOp(compiler, locs(), kind()); |
| } else { |
| ASSERT(operation_cid() == kDoubleCid); |
| return EmitDoubleComparisonOp(compiler, locs(), kind()); |
| @@ -494,7 +593,7 @@ |
| Condition true_condition = EmitComparisonCode(compiler, labels); |
| Register result = locs()->out().reg(); |
| - if (operation_cid() == kSmiCid) { |
| + if ((operation_cid() == kSmiCid) || (operation_cid() == kMintCid)) { |
| __ LoadObject(result, Bool::True(), true_condition); |
| __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); |
| } else { |
| @@ -609,6 +708,8 @@ |
| BranchLabels labels) { |
| if (operation_cid() == kSmiCid) { |
| return EmitSmiComparisonOp(compiler, locs(), kind()); |
| + } else if (operation_cid() == kMintCid) { |
| + return EmitUnboxedMintComparisonOp(compiler, locs(), kind()); |
| } else { |
| ASSERT(operation_cid() == kDoubleCid); |
| return EmitDoubleComparisonOp(compiler, locs(), kind()); |
| @@ -625,6 +726,11 @@ |
| if (operation_cid() == kSmiCid) { |
| __ LoadObject(result, Bool::True(), true_condition); |
| __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); |
| + } else if (operation_cid() == kMintCid) { |
| + Register cr = locs()->temp(0).reg(); |
| + __ LoadObject(result, Bool::True()); |
| + __ CompareImmediate(cr, 1); |
| + __ LoadObject(result, Bool::False(), NE); |
| } else { |
| ASSERT(operation_cid() == kDoubleCid); |
| Label done; |
| @@ -643,12 +749,19 @@ |
| BranchLabels labels = compiler->CreateBranchLabels(branch); |
| Condition true_condition = EmitComparisonCode(compiler, labels); |
| - if (operation_cid() == kDoubleCid) { |
| + if (operation_cid() == kSmiCid) { |
| + EmitBranchOnCondition(compiler, true_condition, labels); |
| + } else if (operation_cid() == kMintCid) { |
| + Register result = locs()->temp(0).reg(); |
| + __ CompareImmediate(result, 1); |
| + __ b(labels.true_label, EQ); |
| + __ b(labels.false_label, NE); |
| + } else if (operation_cid() == kDoubleCid) { |
| Label* nan_result = (true_condition == NE) ? |
| labels.true_label : labels.false_label; |
| __ b(nan_result, VS); |
| + EmitBranchOnCondition(compiler, true_condition, labels); |
| } |
| - EmitBranchOnCondition(compiler, true_condition, labels); |
| } |
| @@ -971,12 +1084,26 @@ |
| QRegister result = locs()->out().fpu_reg(); |
| DRegister dresult0 = EvenDRegisterOf(result); |
| DRegister dresult1 = OddDRegisterOf(result); |
| + Register idx = index.reg(); |
| switch (class_id()) { |
| case kTypedDataInt32ArrayCid: |
| - UNIMPLEMENTED(); |
| + __ veorq(result, result, result); |
| + __ ldr(TMP, element_address); |
| + // Re-use the index register so we don't have to require a low-numbered |
| + // Q register. |
| + __ eor(idx, idx, ShifterOperand(idx)); |
|
regis
2014/03/20 20:39:35
Wouldn't __ LoadImmediate(idx, 0) be clearer?
zra
2014/03/20 23:49:25
Done.
|
| + __ cmp(TMP, ShifterOperand(0)); |
| + // Sign-extend if the element is < 0; |
| + __ LoadImmediate(idx, -1, LT); |
|
regis
2014/03/20 20:39:35
Instead of the 3 instructions above (including a b
zra
2014/03/20 23:49:25
Done.
|
| + __ vmovdrr(dresult0, TMP, idx); |
| break; |
| case kTypedDataUint32ArrayCid: |
| - UNIMPLEMENTED(); |
| + __ veorq(result, result, result); |
| + __ ldr(TMP, element_address); |
| + // Re-use the index register so we don't have to require a low-numbered |
| + // Q register. |
| + __ eor(idx, idx, ShifterOperand(idx)); |
|
regis
2014/03/20 20:39:35
Wouldn't __ LoadImmediate(idx, 0) be clearer?
zra
2014/03/20 23:49:25
Done.
|
| + __ vmovdrr(dresult0, TMP, idx); |
| break; |
| case kTypedDataFloat32ArrayCid: |
| // Load single precision float. |
| @@ -1041,7 +1168,7 @@ |
| Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load); |
| __ ldr(result, element_address); |
| // Verify that the unsigned value in 'result' can fit inside a Smi. |
| - __ tst(result, ShifterOperand(0xC0000000)); |
| + __ TestImmediate(result, 0xC0000000); |
| __ b(deopt, NE); |
| __ SmiTag(result); |
| } |
| @@ -1114,9 +1241,15 @@ |
| case kOneByteStringCid: |
| case kTypedDataInt16ArrayCid: |
| case kTypedDataUint16ArrayCid: |
| + locs->set_in(2, Location::WritableRegister()); |
| + break; |
| case kTypedDataInt32ArrayCid: |
| case kTypedDataUint32ArrayCid: |
| - locs->set_in(2, Location::WritableRegister()); |
| + // Mints are stored in Q registers. For smis, use a writable register |
| + // because the value must be untagged before storing. |
| + locs->set_in(2, value()->IsSmiValue() |
| + ? Location::WritableRegister() |
| + : Location::FpuRegisterLocation(Q7)); |
| break; |
| case kTypedDataFloat32ArrayCid: |
| // Need low register (<= Q7). |
| @@ -1246,7 +1379,11 @@ |
| __ SmiUntag(value); |
| __ str(value, element_address); |
| } else { |
| - UNIMPLEMENTED(); |
| + ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); |
| + QRegister value = locs()->in(2).fpu_reg(); |
| + ASSERT(value == Q7); |
| + __ vmovrs(TMP, EvenSRegisterOf(EvenDRegisterOf(value))); |
| + __ str(TMP, element_address); |
| } |
| break; |
| } |
| @@ -3717,8 +3854,7 @@ |
| case MethodRecognizer::kFloat32x4NotEqual: |
| __ vceqqs(result, left, right); |
| // Invert the result. |
| - __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. |
| - __ vornq(result, QTMP, result); // result <- ~result. |
| + __ vmvnq(result, result); |
| break; |
| case MethodRecognizer::kFloat32x4GreaterThan: |
| __ vcgtqs(result, left, right); |
| @@ -4367,8 +4503,7 @@ |
| // Copy mask. |
| __ vmovq(temp, mask); |
| // Invert it. |
| - __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. |
| - __ vornq(temp, QTMP, temp); // temp <- ~temp. |
| + __ vmvnq(temp, temp); |
| // mask = mask & trueValue. |
| __ vandq(mask, mask, trueValue); |
| // temp = temp & falseValue. |
| @@ -5184,58 +5319,373 @@ |
| } |
| +static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
| + Label* overflow, |
| + QRegister result, |
| + Register tmp_hi, Register tmp_lo) { |
| + __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(result)); |
| + // Compare upper half. |
| + Label check_lower; |
| + __ CompareImmediate(tmp_hi, 0x00200000); |
| + __ b(overflow, GT); |
| + __ b(&check_lower, NE); |
| + |
| + __ CompareImmediate(tmp_lo, 0); |
| + __ b(overflow, HI); |
| + |
| + __ Bind(&check_lower); |
| + __ CompareImmediate(tmp_hi, -0x00200000); |
| + __ b(overflow, LT); |
| + // Anything in the lower part would make the number bigger than the lower |
| + // bound, so we are done. |
| +} |
| + |
| + |
| LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t value_cid = value()->Type()->ToCid(); |
| + const bool needs_writable_input = (value_cid != kMintCid); |
| + const bool needs_temp = (value_cid != kMintCid); |
| + const intptr_t kNumTemps = needs_temp ? 1 : 0; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, needs_writable_input |
| + ? Location::WritableRegister() |
| + : Location::RequiresRegister()); |
| + if (needs_temp) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + } |
| + summary->set_out(Location::RequiresFpuRegister()); |
| + return summary; |
| } |
| void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + const intptr_t value_cid = value()->Type()->ToCid(); |
| + const Register value = locs()->in(0).reg(); |
| + const QRegister result = locs()->out().fpu_reg(); |
| + |
| + __ Comment("UnboxIntegerInstr"); |
| + __ veorq(result, result, result); |
| + if (value_cid == kMintCid) { |
| + __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| + Mint::value_offset() - kHeapObjectTag); |
| + } else if (value_cid == kSmiCid) { |
| + Register temp = locs()->temp(0).reg(); |
| + __ SmiUntag(value); |
| + __ LoadImmediate(temp, 0); |
| + __ CompareImmediate(value, 0); |
| + __ LoadImmediate(temp, -1, LT); |
| + __ vmovdrr(EvenDRegisterOf(result), value, temp); |
|
regis
2014/03/20 20:39:35
Replace 3 instructions above with:
__ Lsl(temp,
zra
2014/03/20 23:49:25
Done.
|
| + } else { |
| + Register temp = locs()->temp(0).reg(); |
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptUnboxInteger); |
| + Label is_smi, done; |
| + __ tst(value, ShifterOperand(kSmiTagMask)); |
| + __ b(&is_smi, EQ); |
| + __ CompareClassId(value, kMintCid, temp); |
| + __ b(deopt, NE); |
| + |
| + // It's a Mint. |
| + __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| + Mint::value_offset() - kHeapObjectTag); |
| + __ b(&done); |
| + |
| + // It's a Smi. |
| + __ Bind(&is_smi); |
| + __ SmiUntag(value); |
| + __ LoadImmediate(temp, 0); |
| + __ CompareImmediate(value, 0); |
| + __ LoadImmediate(temp, -1, LT); |
|
regis
2014/03/20 20:39:35
ditto
zra
2014/03/20 23:49:25
Done.
|
| + __ vmovdrr(EvenDRegisterOf(result), value, temp); |
| + __ Bind(&done); |
| + } |
| } |
| LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 2; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, |
| + kNumTemps, |
| + LocationSummary::kCallOnSlowPath); |
| + summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_temp(1, Location::RequiresRegister()); |
| + summary->set_out(Location::RequiresRegister()); |
| + return summary; |
| } |
| +class BoxIntegerSlowPath : public SlowPathCode { |
| + public: |
| + explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) |
| + : instruction_(instruction) { } |
| + |
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| + __ Comment("BoxIntegerSlowPath"); |
| + __ Bind(entry_label()); |
| + const Class& mint_class = |
| + Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()); |
| + const Code& stub = |
| + Code::Handle(StubCode::GetAllocationStubForClass(mint_class)); |
| + const ExternalLabel label(mint_class.ToCString(), stub.EntryPoint()); |
| + |
| + LocationSummary* locs = instruction_->locs(); |
| + locs->live_registers()->Remove(locs->out()); |
| + |
| + compiler->SaveLiveRegisters(locs); |
| + compiler->GenerateCall(Scanner::kNoSourcePos, // No token position. |
| + &label, |
| + PcDescriptors::kOther, |
| + locs); |
| + __ mov(locs->out().reg(), ShifterOperand(R0)); |
| + compiler->RestoreLiveRegisters(locs); |
| + |
| + __ b(exit_label()); |
| + } |
| + |
| + private: |
| + BoxIntegerInstr* instruction_; |
| +}; |
| + |
| + |
| void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| + compiler->AddSlowPathCode(slow_path); |
| + |
| + Register out_reg = locs()->out().reg(); |
| + QRegister value = locs()->in(0).fpu_reg(); |
| + DRegister dvalue0 = EvenDRegisterOf(value); |
| + Register lo = locs()->temp(0).reg(); |
| + Register hi = locs()->temp(1).reg(); |
| + |
| + // Unboxed operations produce smis or mint-sized values. |
| + // Check if value fits into a smi. |
| + __ Comment("BoxIntegerInstr"); |
| + Label not_smi, done, maybe_pos_smi, maybe_neg_smi, is_smi; |
| + __ vmovrrd(lo, hi, dvalue0); |
| + __ CompareImmediate(hi, 0); |
| + __ b(&maybe_pos_smi, EQ); |
| + |
| + __ CompareImmediate(hi, -1); |
| + __ b(&maybe_neg_smi, EQ); |
| + __ b(¬_smi); |
| + |
| + __ Bind(&maybe_pos_smi); |
| + __ CompareImmediate(lo, kSmiMax); |
| + __ b(&is_smi, LS); // unsigned lower or same. |
| + __ b(¬_smi); |
| + |
| + __ Bind(&maybe_neg_smi); |
| + __ CompareImmediate(lo, 0); |
| + __ b(¬_smi, GE); |
| + __ CompareImmediate(lo, kSmiMin); |
| + __ b(¬_smi, LT); |
| + |
| + // lo is a Smi. Tag it and return. |
| + __ Bind(&is_smi); |
| + __ SmiTag(lo); |
| + __ mov(out_reg, ShifterOperand(lo)); |
| + __ b(&done); |
| + |
| + // Not a smi. Box it. |
| + __ Bind(¬_smi); |
| + __ TryAllocate( |
| + Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
| + slow_path->entry_label(), |
| + out_reg, |
| + lo); |
| + __ Bind(slow_path->exit_label()); |
| + __ StoreDToOffset(dvalue0, out_reg, Mint::value_offset() - kHeapObjectTag); |
| + __ Bind(&done); |
| } |
| LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 2; |
| + const intptr_t kNumTemps = |
| + FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_in(1, Location::RequiresFpuRegister()); |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_temp(1, Location::RequiresRegister()); |
| + } |
| + if ((op_kind() == Token::kADD) || (op_kind() == Token::kSUB)) { |
| + // Need another temp for checking for overflow. |
| + summary->AddTemp(Location::RequiresFpuRegister()); |
| + summary->AddTemp(Location::FpuRegisterLocation(Q7)); |
| + } |
| + summary->set_out(Location::RequiresFpuRegister()); |
| + return summary; |
| } |
| void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + QRegister left = locs()->in(0).fpu_reg(); |
| + QRegister right = locs()->in(1).fpu_reg(); |
| + QRegister out = locs()->out().fpu_reg(); |
| + |
| + Label* deopt = NULL; |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); |
| + } |
| + switch (op_kind()) { |
| + case Token::kBIT_AND: __ vandq(out, left, right); break; |
| + case Token::kBIT_OR: __ vorrq(out, left, right); break; |
| + case Token::kBIT_XOR: __ veorq(out, left, right); break; |
| + case Token::kADD: |
| + case Token::kSUB: { |
| + const intptr_t tmpidx = FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| + QRegister tmp = locs()->temp(tmpidx).fpu_reg(); |
| + QRegister ro = locs()->temp(tmpidx + 1).fpu_reg(); |
| + ASSERT(ro == Q7); |
| + if (!FLAG_throw_on_javascript_int_overflow) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); |
| + } |
| + if (op_kind() == Token::kADD) { |
| + __ vaddqi(kWordPair, out, left, right); |
| + } else { |
| + ASSERT(op_kind() == Token::kSUB); |
| + __ vsubqi(kWordPair, out, left, right); |
| + } |
| + __ veorq(ro, out, left); |
| + __ veorq(tmp, left, right); |
| + __ vandq(ro, tmp, ro); |
| + __ vmovrs(TMP, OddSRegisterOf(EvenDRegisterOf(ro))); |
| + // If TMP < 0, there was overflow. |
| + __ cmp(TMP, ShifterOperand(0)); |
| + __ b(deopt, LT); |
| + break; |
| + } |
| + default: UNREACHABLE(); break; |
| + } |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + Register tmp1 = locs()->temp(0).reg(); |
| + Register tmp2 = locs()->temp(1).reg(); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| + } |
| } |
| LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 2; |
| + const intptr_t kNumTemps = |
| + FLAG_throw_on_javascript_int_overflow ? 2 : 1; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_in(1, Location::WritableRegister()); |
| + summary->set_temp(0, Location::FpuRegisterLocation(Q7)); |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + summary->set_temp(1, Location::RequiresRegister()); |
| + } |
| + summary->set_out(Location::RequiresFpuRegister()); |
| + return summary; |
| } |
| void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + QRegister value = locs()->in(0).fpu_reg(); |
| + Register shift = locs()->in(1).reg(); |
| + QRegister temp = locs()->temp(0).fpu_reg(); |
| + ASSERT(temp == Q7); |
| + QRegister out = locs()->out().fpu_reg(); |
| + DRegister dtemp0 = EvenDRegisterOf(temp); |
| + SRegister stemp0 = EvenSRegisterOf(dtemp0); |
| + SRegister stemp1 = OddSRegisterOf(dtemp0); |
| + |
| + Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptShiftMintOp); |
| + Label done; |
| + |
| + __ CompareImmediate(shift, 0); |
| + __ vmovq(out, value); |
| + __ b(&done, EQ); |
| + __ SmiUntag(shift); |
| + |
| + // vshlq takes the shift value from low byte. Deopt if shift is |
| + // outside of [0, 127]. |
| + __ CompareImmediate(shift, 127); |
| + __ b(deopt, GT); |
| + __ CompareImmediate(shift, 0); |
| + __ b(deopt, LT); |
| + |
| + __ veorq(temp, temp, temp); // Zero out temp. |
| + switch (op_kind()) { |
| + case Token::kSHR: { |
| + __ rsb(shift, shift, ShifterOperand(0)); // Negate shift. |
| + __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
| + __ vshlqi(kWordPair, out, value, temp); |
| + break; |
| + } |
| + case Token::kSHL: { |
| + __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
| + __ vshlqu(kWordPair, out, value, temp); |
| + |
| + // check for overflow by shifting back and comparing. |
| + __ rsb(shift, shift, ShifterOperand(0)); |
| + __ vmovsr(stemp0, shift); |
| + __ vshlqi(kWordPair, temp, out, temp); |
| + __ vceqqi(kWord, temp, temp, value); |
| + // Low 64 bits of temp should be all 1's, otherwise temp != value and |
| + // we deopt. |
| + __ vmovrs(shift, stemp0); |
| + __ CompareImmediate(shift, -1); |
| + __ b(deopt, NE); |
| + __ vmovrs(shift, stemp1); |
| + __ CompareImmediate(shift, -1); |
| + __ b(deopt, NE); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + |
| + __ Bind(&done); |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + Register tmp1 = locs()->in(1).reg(); |
| + Register tmp2 = locs()->temp(1).reg(); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| + } |
| } |
| LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| - UNIMPLEMENTED(); |
| - return NULL; |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = |
| + FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_out(Location::RequiresFpuRegister()); |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_temp(1, Location::RequiresRegister()); |
| + } |
| + return summary; |
| } |
| void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - UNIMPLEMENTED(); |
| + ASSERT(op_kind() == Token::kBIT_NOT); |
| + QRegister value = locs()->in(0).fpu_reg(); |
| + QRegister out = locs()->out().fpu_reg(); |
| + Label* deopt = NULL; |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + deopt = compiler->AddDeoptStub(deopt_id(), |
| + kDeoptUnaryMintOp); |
| + } |
| + __ vmvnq(out, value); |
| + if (FLAG_throw_on_javascript_int_overflow) { |
| + Register tmp1 = locs()->temp(0).reg(); |
| + Register tmp2 = locs()->temp(1).reg(); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| + } |
| } |