Chromium Code Reviews| Index: runtime/vm/intermediate_language_arm.cc |
| diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc |
| index a44f1b5bcd44184ab77f12d5b2e492a902902d75..e5f9d8d81e53c43dc72c0a8332ccb762212b55d7 100644 |
| --- a/runtime/vm/intermediate_language_arm.cc |
| +++ b/runtime/vm/intermediate_language_arm.cc |
| @@ -379,14 +379,13 @@ static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 2; |
| if (operation_cid() == kMintCid) { |
| - const intptr_t kNumTemps = 3; |
| + const intptr_t kNumTemps = 0; |
| 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::RequiresFpuRegister()); |
| - locs->set_temp(1, Location::RequiresRegister()); |
| - locs->set_temp(2, Location::RequiresRegister()); |
| + locs->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| + locs->set_in(1, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| locs->set_out(0, Location::RequiresRegister()); |
| return locs; |
| } |
| @@ -514,37 +513,36 @@ 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(); |
| + PairLocation* left_pair = locs->in(0).AsPairLocation(); |
| + Register left1 = left_pair->At(0).reg(); |
|
zra
2014/05/14 18:27:41
optional: rename to {left, right}_{lo, hi}.
Cutch
2014/05/15 18:26:08
Done.
|
| + Register left2 = left_pair->At(1).reg(); |
| + PairLocation* right_pair = locs->in(1).AsPairLocation(); |
| + Register right1 = right_pair->At(0).reg(); |
| + Register right2 = right_pair->At(1).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)); |
| + Label done; |
| - Condition true_condition = TokenKindToMintCondition(kind); |
| - __ CompareImmediate(tmp_lo, 0xffffffff); |
| - return true_condition; |
| + // Compare lower. |
| + __ cmp(left1, ShifterOperand(right1)); |
| + __ b(&done, NE); |
| + // Lower is equal, compare upper. |
| + __ cmp(left2, ShifterOperand(right2)); |
|
zra
2014/05/14 18:27:41
Remove branch, instead:
__ cmp(left2, ShifterOpera
Cutch
2014/05/15 18:26:08
Done but I think you meant EQ instead of NE.
zra
2014/05/15 18:30:45
Yes, you're right.
|
| + __ Bind(&done); |
| + return TokenKindToMintCondition(kind); |
| } |
| 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); |
| + PairLocation* left_pair = locs->in(0).AsPairLocation(); |
| + Register left1 = left_pair->At(0).reg(); |
|
zra
2014/05/14 18:27:41
optional: rename to {left, right}_{lo, hi}.
Cutch
2014/05/15 18:26:08
Done.
|
| + Register left2 = left_pair->At(1).reg(); |
| + PairLocation* right_pair = locs->in(1).AsPairLocation(); |
| + Register right1 = right_pair->At(0).reg(); |
| + Register right2 = right_pair->At(1).reg(); |
| - Register tmp_left = locs->temp(0).reg(); |
| - Register tmp_right = locs->temp(1).reg(); |
| + Register out = locs->temp(0).reg(); |
| // 64-bit comparison |
| Condition hi_true_cond, hi_false_cond, lo_false_cond; |
| @@ -567,24 +565,23 @@ static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
| } |
| Label is_true, is_false, done; |
| - __ vmovrs(tmp_left, sleft1); |
| - __ vmovrs(tmp_right, sright1); |
| - __ cmp(tmp_left, ShifterOperand(tmp_right)); |
| + // Compare upper halves first. |
| + __ cmp(left2, ShifterOperand(right2)); |
| __ b(&is_false, hi_false_cond); |
| __ b(&is_true, hi_true_cond); |
|
zra
2014/05/14 18:27:41
Instead, to avoid so many branches:
__ cmp(left2,
Cutch
2014/05/15 18:26:08
Done.
|
| - __ vmovrs(tmp_left, sleft0); |
| - __ vmovrs(tmp_right, sright0); |
| - __ cmp(tmp_left, ShifterOperand(tmp_right)); |
| + // If upper is equal, compare lower half. |
| + __ cmp(left1, ShifterOperand(right1)); |
| __ b(&is_false, lo_false_cond); |
| + |
| // Else is true. |
| __ b(&is_true); |
| __ Bind(&is_false); |
| - __ LoadImmediate(tmp_left, 0); |
| + __ LoadImmediate(out, 0); |
| __ b(&done); |
| __ Bind(&is_true); |
| - __ LoadImmediate(tmp_left, 1); |
| + __ LoadImmediate(out, 1); |
| __ Bind(&done); |
| return NegateCondition(lo_false_cond); |
| } |
| @@ -792,13 +789,14 @@ LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 2; |
| const intptr_t kNumTemps = 0; |
| if (operation_cid() == kMintCid) { |
| - const intptr_t kNumTemps = 2; |
| + const intptr_t kNumTemps = 1; |
| LocationSummary* locs = |
| new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| - locs->set_in(0, Location::RequiresFpuRegister()); |
| - locs->set_in(1, Location::RequiresFpuRegister()); |
| + locs->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| + locs->set_in(1, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| locs->set_temp(0, Location::RequiresRegister()); |
| - locs->set_temp(1, Location::RequiresRegister()); |
| locs->set_out(0, Location::RequiresRegister()); |
| return locs; |
| } |
| @@ -1148,7 +1146,11 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const { |
| } else { |
| locs->set_out(0, Location::RequiresFpuRegister()); |
| } |
| + } else if (representation() == kUnboxedMint) { |
| + locs->set_out(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| } else { |
| + ASSERT(representation() == kTagged); |
| locs->set_out(0, Location::RequiresRegister()); |
| } |
| return locs; |
| @@ -1157,7 +1159,6 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const { |
| void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| if ((representation() == kUnboxedDouble) || |
| - (representation() == kUnboxedMint) || |
| (representation() == kUnboxedFloat32x4) || |
| (representation() == kUnboxedInt32x4) || |
| (representation() == kUnboxedFloat64x2)) { |
| @@ -1189,23 +1190,6 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| const QRegister result = locs()->out(0).fpu_reg(); |
| const DRegister dresult0 = EvenDRegisterOf(result); |
| switch (class_id()) { |
| - case kTypedDataInt32ArrayCid: |
| - __ 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: |
| - __ 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. |
| // vldrs does not support indexed addressing. |
| @@ -1220,6 +1204,8 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| case kTypedDataFloat32x4ArrayCid: |
| __ vldmd(IA, idx, dresult0, 2); |
| break; |
| + default: |
| + UNREACHABLE(); |
| } |
| return; |
| } |
| @@ -1263,6 +1249,34 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag); |
| } |
| element_address = Address(array, index.reg(), LSL, 0); |
| + |
| + if (representation() == kUnboxedMint) { |
| + ASSERT(locs()->out(0).IsPairLocation()); |
| + PairLocation* result_pair = locs()->out(0).AsPairLocation(); |
| + Register result1 = result_pair->At(0).reg(); |
| + Register result2 = result_pair->At(1).reg(); |
| + switch (class_id()) { |
| + case kTypedDataInt32ArrayCid: |
| + // Load low word. |
| + __ ldr(result1, element_address); |
| + // Sign extend into high word. |
| + __ SignFill(result2, result1); |
| + break; |
| + case kTypedDataUint32ArrayCid: |
| + // Load low word. |
| + __ ldr(result1, element_address); |
| + // Zero high word. |
| + __ eor(result2, result2, ShifterOperand(result2)); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + return; |
| + } |
| + |
| + ASSERT(representation() == kTagged); |
| + |
| Register result = locs()->out(0).reg(); |
| switch (class_id()) { |
| case kTypedDataInt8ArrayCid: |
| @@ -1380,11 +1394,16 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const { |
| break; |
| case kTypedDataInt32ArrayCid: |
| case kTypedDataUint32ArrayCid: |
| - // 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)); |
| + // For smis, use a writable register because the value must be untagged |
| + // before storing. Mints are stored in register pairs. |
| + if (value()->IsSmiValue()) { |
| + locs->set_in(2, Location::WritableRegister()); |
| + } else { |
| + // We only move the lower 32-bits so we don't care where the high bits |
| + // are located. |
| + locs->set_in(2, Location::Pair(Location::RequiresRegister(), |
| + Location::Any())); |
| + } |
| break; |
| case kTypedDataFloat32ArrayCid: |
| // Need low register (<= Q7). |
| @@ -1515,10 +1534,9 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| __ str(value, element_address); |
| } else { |
| ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); |
| - QRegister value = locs()->in(2).fpu_reg(); |
| - ASSERT(value == Q7); |
| - __ vmovrs(TMP, EvenSRegisterOf(EvenDRegisterOf(value))); |
| - __ str(TMP, element_address); |
| + PairLocation* value_pair = locs()->in(2).AsPairLocation(); |
| + Register value1 = value_pair->At(0).reg(); |
| + __ str(value1, element_address); |
| } |
| break; |
| } |
| @@ -5599,20 +5617,19 @@ void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
| Label* overflow, |
| - QRegister result, |
| - Register tmp_hi, Register tmp_lo) { |
| - __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(result)); |
| + Register result_lo, |
| + Register result_hi) { |
| // Compare upper half. |
| Label check_lower; |
| - __ CompareImmediate(tmp_hi, 0x00200000); |
| + __ CompareImmediate(result_hi, 0x00200000); |
| __ b(overflow, GT); |
| __ b(&check_lower, NE); |
| - __ CompareImmediate(tmp_lo, 0); |
| + __ CompareImmediate(result_lo, 0); |
| __ b(overflow, HI); |
| __ Bind(&check_lower); |
| - __ CompareImmediate(tmp_hi, -0x00200000); |
| + __ CompareImmediate(result_hi, -0x00200000); |
| __ b(overflow, LT); |
| // Anything in the lower part would make the number bigger than the lower |
| // bound, so we are done. |
| @@ -5621,19 +5638,13 @@ static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
| LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
| 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; |
| + const intptr_t kNumTemps = 1; |
| 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()); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| return summary; |
| } |
| @@ -5641,19 +5652,30 @@ LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
| void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| const intptr_t value_cid = value()->Type()->ToCid(); |
| const Register value = locs()->in(0).reg(); |
| - const QRegister result = locs()->out(0).fpu_reg(); |
| + PairLocation* result_pair = locs()->out(0).AsPairLocation(); |
| + Register result1 = result_pair->At(0).reg(); |
| + Register result2 = result_pair->At(1).reg(); |
| + ASSERT(value != result1); |
| + ASSERT(value != result2); |
| __ Comment("UnboxIntegerInstr"); |
| - __ veorq(result, result, result); |
| if (value_cid == kMintCid) { |
| - __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| - Mint::value_offset() - kHeapObjectTag); |
| + // Load low word. |
| + __ LoadFromOffset(kWord, |
| + result1, |
| + value, |
| + Mint::value_offset() - kHeapObjectTag); |
| + // Load high word. |
| + __ LoadFromOffset(kWord, |
| + result2, |
| + value, |
| + Mint::value_offset() - kHeapObjectTag + kWordSize); |
| } 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); |
| + // Load Smi into result1. |
| + __ mov(result1, ShifterOperand(value)); |
| + // Untag. |
| + __ SmiUntag(result1); |
| + __ SignFill(result2, result1); |
| } else { |
| Register temp = locs()->temp(0).reg(); |
| Label* deopt = compiler->AddDeoptStub(deopt_id_, |
| @@ -5665,16 +5687,26 @@ void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| __ b(deopt, NE); |
| // It's a Mint. |
| - __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| - Mint::value_offset() - kHeapObjectTag); |
| + // Load low word. |
| + __ LoadFromOffset(kWord, |
| + result1, |
| + value, |
| + Mint::value_offset() - kHeapObjectTag); |
| + // Load high word. |
| + __ LoadFromOffset(kWord, |
| + result2, |
| + value, |
| + Mint::value_offset() - kHeapObjectTag + kWordSize); |
| __ b(&done); |
| // It's a Smi. |
| __ Bind(&is_smi); |
| - __ SmiUntag(value); |
| - // Sign extend into temp. |
| - __ Asr(temp, value, 31); |
| - __ vmovdrr(EvenDRegisterOf(result), value, temp); |
| + // Load Smi into result1. |
| + __ mov(result1, ShifterOperand(value)); |
| + // Untag. |
| + __ SmiUntag(result1); |
| + // Sign extend result1 into result2. |
| + __ SignFill(result2, result1); |
| __ Bind(&done); |
| } |
| } |
| @@ -5682,14 +5714,14 @@ void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 1; |
| - const intptr_t kNumTemps = 2; |
| + const intptr_t kNumTemps = 1; |
| LocationSummary* summary = |
| new LocationSummary(kNumInputs, |
| kNumTemps, |
| LocationSummary::kCallOnSlowPath); |
| - summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| summary->set_temp(0, Location::RequiresRegister()); |
| - summary->set_temp(1, Location::RequiresRegister()); |
| summary->set_out(0, Location::RequiresRegister()); |
| return summary; |
| } |
| @@ -5731,40 +5763,39 @@ class BoxIntegerSlowPath : public SlowPathCode { |
| void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| compiler->AddSlowPathCode(slow_path); |
| - |
| + PairLocation* value_pair = locs()->in(0).AsPairLocation(); |
| + Register value1 = value_pair->At(0).reg(); |
|
zra
2014/05/14 18:27:41
optional: lo/hi instead of 1/2 as above
Cutch
2014/05/15 18:26:08
Done.
|
| + Register value2 = value_pair->At(1).reg(); |
| + Register tmp = locs()->temp(0).reg(); |
| 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); |
| + // Check high word. |
|
zra
2014/05/14 18:27:41
Can you rewrite this to mirror the ia32 implementa
Cutch
2014/05/15 18:26:08
I took a stab at this but kept getting test failur
zra
2014/05/15 18:30:45
sgtm
|
| + __ CompareImmediate(value2, 0); |
| __ b(&maybe_pos_smi, EQ); |
| - __ CompareImmediate(hi, -1); |
| + __ CompareImmediate(value2, -1); |
| __ b(&maybe_neg_smi, EQ); |
| __ b(¬_smi); |
| __ Bind(&maybe_pos_smi); |
| - __ CompareImmediate(lo, kSmiMax); |
| + __ CompareImmediate(value1, kSmiMax); |
| __ b(&is_smi, LS); // unsigned lower or same. |
| __ b(¬_smi); |
| __ Bind(&maybe_neg_smi); |
| - __ CompareImmediate(lo, 0); |
| + __ CompareImmediate(value1, 0); |
| __ b(¬_smi, GE); |
| - __ CompareImmediate(lo, kSmiMin); |
| + __ CompareImmediate(value1, kSmiMin); |
| __ b(¬_smi, LT); |
| // lo is a Smi. Tag it and return. |
| __ Bind(&is_smi); |
| - __ SmiTag(lo); |
| - __ mov(out_reg, ShifterOperand(lo)); |
| + __ mov(out_reg, ShifterOperand(value1)); |
| + __ SmiTag(out_reg); |
| __ b(&done); |
| // Not a smi. Box it. |
| @@ -5773,149 +5804,178 @@ void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
| slow_path->entry_label(), |
| out_reg, |
| - lo); |
| + tmp); |
| __ Bind(slow_path->exit_label()); |
| - __ StoreDToOffset(dvalue0, out_reg, Mint::value_offset() - kHeapObjectTag); |
| + __ StoreToOffset(kWord, |
| + value1, |
| + out_reg, |
| + Mint::value_offset() - kHeapObjectTag); |
| + __ StoreToOffset(kWord, |
| + value2, |
| + out_reg, |
| + Mint::value_offset() - kHeapObjectTag + kWordSize); |
| __ Bind(&done); |
| } |
| LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 2; |
| - const intptr_t kNumTemps = |
| - FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| + const intptr_t kNumTemps = 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()); |
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| + summary->set_in(1, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| return summary; |
| } |
| void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - QRegister left = locs()->in(0).fpu_reg(); |
| - QRegister right = locs()->in(1).fpu_reg(); |
| - QRegister out = locs()->out(0).fpu_reg(); |
| + PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
| + Register left1 = left_pair->At(0).reg(); |
| + Register left2 = left_pair->At(1).reg(); |
| + PairLocation* right_pair = locs()->in(1).AsPairLocation(); |
| + Register right1 = right_pair->At(0).reg(); |
| + Register right2 = right_pair->At(1).reg(); |
| + PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| + Register out1 = out_pair->At(0).reg(); |
| + Register out2 = out_pair->At(1).reg(); |
| Label* deopt = NULL; |
| if (FLAG_throw_on_javascript_int_overflow) { |
| deopt = compiler->AddDeoptStub(deopt_id(), ICData::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::kBIT_AND: { |
| + __ and_(out1, left1, ShifterOperand(right1)); |
| + __ and_(out2, left2, ShifterOperand(right2)); |
| + } |
| + break; |
| + case Token::kBIT_OR: { |
| + __ orr(out1, left1, ShifterOperand(right1)); |
| + __ orr(out2, left2, ShifterOperand(right2)); |
| + } |
| + break; |
| + case Token::kBIT_XOR: { |
| + __ eor(out1, left1, ShifterOperand(right1)); |
| + __ eor(out2, left2, ShifterOperand(right2)); |
| + } |
| + 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(), ICData::kDeoptBinaryMintOp); |
| } |
| if (op_kind() == Token::kADD) { |
| - __ vaddqi(kWordPair, out, left, right); |
| + __ adds(out1, left1, ShifterOperand(right1)); |
| + __ adcs(out2, left2, ShifterOperand(right2)); |
| } else { |
| ASSERT(op_kind() == Token::kSUB); |
| - __ vsubqi(kWordPair, out, left, right); |
| + __ subs(out1, left1, ShifterOperand(right1)); |
| + __ sbcs(out2, left2, ShifterOperand(right2)); |
| } |
| - __ 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); |
| + // Deopt on overflow. |
| + __ b(deopt, VS); |
| break; |
| } |
| - default: UNREACHABLE(); 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); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out1, out2); |
| } |
| } |
| LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 2; |
| - const intptr_t kNumTemps = |
| - FLAG_throw_on_javascript_int_overflow ? 2 : 1; |
| + const intptr_t kNumTemps = 1; |
| LocationSummary* summary = |
| new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| - summary->set_in(0, Location::RequiresFpuRegister()); |
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| 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()); |
| + summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| return summary; |
| } |
| void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - QRegister value = locs()->in(0).fpu_reg(); |
| + PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
| + Register left1 = left_pair->At(0).reg(); |
| + Register left2 = left_pair->At(1).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); |
| + PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| + Register out1 = out_pair->At(0).reg(); |
| + Register out2 = out_pair->At(1).reg(); |
| + Register temp = locs()->temp(0).reg(); |
| Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp); |
| - Label done; |
| + Label done, early_out; |
| + // Early out if shift is 0. |
| __ CompareImmediate(shift, 0); |
| - __ vmovq(out, value); |
| - __ b(&done, EQ); |
| + __ b(&early_out, EQ); |
| + |
| + // Untag shift count. |
| __ SmiUntag(shift); |
| - // vshlq takes the shift value from low byte. Deopt if shift is |
| - // outside of [0, 63]. |
| - __ CompareImmediate(shift, 63); |
| - __ b(deopt, GT); |
| - __ CompareImmediate(shift, 0); |
| + // Deopt if shift is negative. |
| + __ CompareImmediate(shift, 1); |
| __ b(deopt, LT); |
| - __ veorq(temp, temp, temp); // Zero out temp. |
| + // Deopt if shift is larger than 32. |
|
zra
2014/05/14 18:27:41
Are there funky things that happen for >= 32 as pa
Cutch
2014/05/15 18:26:08
Done.
|
| + __ CompareImmediate(shift, 32); |
| + __ b(deopt, GT); |
| + |
| 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); |
| + /* |
| + * Perform right shift, in pseudo C: |
| + * temp = 32 - N; |
| + * temp = left2 <<L temp; |
| + * out1 = temp | (left1 L>> N); |
| + * out2 = left2 A>> N; |
| + */ |
| + __ rsb(temp, shift, ShifterOperand(32)); |
| + __ mov(temp, ShifterOperand(left2, LSL, temp)); |
| + __ orr(out1, temp, ShifterOperand(left1, LSR, shift)); |
| + __ mov(out2, ShifterOperand(left2, ASR, shift)); |
| + // Finished. |
| + __ b(&done); |
| 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); |
| + /* |
| + * Perform left shift, in pseudo C: |
| + * temp = 32 - N; |
| + * out2 = left2 <<L shift; |
| + * out2 = out2 | (left1 L>> temp); |
| + * out1 = left1 <<L shift; |
| + */ |
| + __ rsb(temp, shift, ShifterOperand(32)); |
| + __ mov(out2, ShifterOperand(left2, LSL, shift)); |
| + __ orr(out2, out2, ShifterOperand(left1, LSR, temp)); |
| + __ mov(out1, ShifterOperand(left1, LSL, shift)); |
| + |
| + // Check for overflow. |
| + |
| + // Copy high word from output. |
| + __ mov(temp, ShifterOperand(out2)); |
| + // Shift copy right. |
| + __ Asr(temp, temp, shift); |
| + // Compare with high word from input. |
| + __ cmp(temp, ShifterOperand(left2)); |
| + // Overflow if they aren't equal. |
| __ b(deopt, NE); |
| + // Finished. |
| + __ b(&done); |
| break; |
| } |
| default: |
| @@ -5923,44 +5983,50 @@ void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| break; |
| } |
| + __ Bind(&early_out); |
| + __ mov(out1, ShifterOperand(left1)); |
| + __ mov(out2, ShifterOperand(left2)); |
| + |
| __ 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); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out1, out2); |
| } |
| } |
| LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| const intptr_t kNumInputs = 1; |
| - const intptr_t kNumTemps = |
| - FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| + const intptr_t kNumTemps = 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()); |
| - } |
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| + Location::RequiresRegister())); |
| return summary; |
| } |
| void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| ASSERT(op_kind() == Token::kBIT_NOT); |
| - QRegister value = locs()->in(0).fpu_reg(); |
| - QRegister out = locs()->out(0).fpu_reg(); |
| + |
| + PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
| + Register left1 = left_pair->At(0).reg(); |
| + Register left2 = left_pair->At(1).reg(); |
| + |
| + PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| + Register out1 = out_pair->At(0).reg(); |
| + Register out2 = out_pair->At(1).reg(); |
| + |
| Label* deopt = NULL; |
| + |
| if (FLAG_throw_on_javascript_int_overflow) { |
| deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp); |
| } |
| - __ vmvnq(out, value); |
| + __ mvn(out1, ShifterOperand(left1)); |
| + __ mvn(out2, ShifterOperand(left2)); |
| 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); |
| + EmitJavascriptIntOverflowCheck(compiler, deopt, out1, out2); |
| } |
| } |