| Index: runtime/vm/intermediate_language_arm.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_arm.cc (revision 34252)
|
| +++ 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(0, 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(0).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,24 @@
|
| QRegister result = locs()->out(0).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.
|
| + // Sign-extend into idx.
|
| + __ Asr(idx, TMP, 31);
|
| + __ 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.
|
| + __ LoadImmediate(idx, 0);
|
| + __ vmovdrr(dresult0, TMP, idx);
|
| break;
|
| case kTypedDataFloat32ArrayCid:
|
| // Load single precision float.
|
| @@ -1041,7 +1166,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 +1239,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 +1377,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 +3852,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 +4501,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 +5317,371 @@
|
| }
|
|
|
|
|
| +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(0, 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(0).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);
|
| + // Sign extend value into temp.
|
| + __ Asr(temp, value, 31);
|
| + __ vmovdrr(EvenDRegisterOf(result), value, temp);
|
| + } 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);
|
| + // Sign extend into temp.
|
| + __ Asr(temp, value, 31);
|
| + __ 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(0, 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(0));
|
| +
|
| + compiler->SaveLiveRegisters(locs);
|
| + compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
| + &label,
|
| + PcDescriptors::kOther,
|
| + locs);
|
| + __ mov(locs->out(0).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(0).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(0, 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(0).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(0, 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(0).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(0, 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(0).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);
|
| + }
|
| }
|
|
|
|
|
|
|