Use GPRs for mints.
Changes:
* Register allocator now allocates GPRs for kUnboxedMint.
* Register allocator supports for SameAsFirstInput for register pairs.
* Register allocator properly handles register pairs in environment uses and materialization uses.
* BoxInteger updated on IA32/ARM.
* UnboxInteger updated on IA32/ARM.
* BinaryMintOp updated on IA32/ARM.
* ShiftMintOp updated on IA32/ARM.
* UnaryMintOp updated on IA32/ARM.
* RelationalOp updated on IA32/ARM.
* EqualityCompare updated on IA32/ARM.
* LoadIndexed and StoreIndexed updated on IA32/ARM.
* New Deopt instructions added.
* Update live_registers when an instruction has a fixed register input and a call on the slow path.
* Improve printing of register pairs in flow graph.
* Do not assume live registers in slow paths contain tagged values.
* LiveRange pairs for kUnboxedMint definitions marked as kUntagged representation (reduces stack usage).
* Live register spilling on ARM uses same register order as stack map encoding.
* Spill slots containing tagged and untagged are segregated.
* Print stack maps when printing live ranges with safe points.
* Print allocated spill slot when printing live ranges.
Status:
* IA32 completed. All tests are passing.
* ARM completed. All tests passing.
R=fschneider@google.com, srdjan@google.com, zra@google.com
Review URL: https://codereview.chromium.org//252333002
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@36468 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index d712f98..a7c442d 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -273,12 +273,24 @@
}
+void Assembler::adcs(Register rd, Register rn, ShifterOperand so,
+ Condition cond) {
+ EmitType01(cond, so.type(), ADC, 1, rn, rd, so);
+}
+
+
void Assembler::sbc(Register rd, Register rn, ShifterOperand so,
Condition cond) {
EmitType01(cond, so.type(), SBC, 0, rn, rd, so);
}
+void Assembler::sbcs(Register rd, Register rn, ShifterOperand so,
+ Condition cond) {
+ EmitType01(cond, so.type(), SBC, 1, rn, rd, so);
+}
+
+
void Assembler::rsc(Register rd, Register rn, ShifterOperand so,
Condition cond) {
EmitType01(cond, so.type(), RSC, 0, rn, rd, so);
@@ -2161,6 +2173,11 @@
}
+void Assembler::SignFill(Register rd, Register rm) {
+ Asr(rd, rm, 31);
+}
+
+
void Assembler::Vreciprocalqs(QRegister qd, QRegister qm) {
ASSERT(qm != QTMP);
ASSERT(qd != QTMP);
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 607754b..19033fa 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -351,8 +351,12 @@
void adc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
+ void adcs(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
+
void sbc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
+ void sbcs(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
+
void rsc(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
void tst(Register rn, ShifterOperand so, Condition cond = AL);
@@ -694,6 +698,9 @@
void Ror(Register rd, Register rm, Register rs, Condition cond = AL);
void Rrx(Register rd, Register rm, Condition cond = AL);
+ // Fill rd with the sign of rm.
+ void SignFill(Register rd, Register rm);
+
void Vreciprocalqs(QRegister qd, QRegister qm);
void VreciprocalSqrtqs(QRegister qd, QRegister qm);
// If qm must be preserved, then provide a (non-QTMP) temporary.
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 6973e27..8029184 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -683,6 +683,40 @@
}
+ASSEMBLER_TEST_GENERATE(AddCarry, assembler) {
+ __ LoadImmediate(R2, 0xFFFFFFFF);
+ __ mov(R1, ShifterOperand(1));
+ __ mov(R0, ShifterOperand(0));
+ __ adds(R2, R2, ShifterOperand(R1));
+ __ adcs(R0, R0, ShifterOperand(R0));
+ __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(AddCarry, test) {
+ EXPECT(test != NULL);
+ typedef int (*AddCarry)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(AddCarry, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(SubCarry, assembler) {
+ __ LoadImmediate(R2, 0x0);
+ __ mov(R1, ShifterOperand(1));
+ __ mov(R0, ShifterOperand(0));
+ __ subs(R2, R2, ShifterOperand(R1));
+ __ sbcs(R0, R0, ShifterOperand(R0));
+ __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(SubCarry, test) {
+ EXPECT(test != NULL);
+ typedef int (*SubCarry)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SubCarry, test->entry()));
+}
+
+
ASSEMBLER_TEST_GENERATE(AndOrr, assembler) {
__ mov(R1, ShifterOperand(40));
__ mov(R2, ShifterOperand(0));
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index c0f19ab..8a2ebde 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -72,6 +72,17 @@
}
+void BitmapBuilder::Print() const {
+ for (intptr_t i = 0; i < Length(); i++) {
+ if (Get(i)) {
+ OS::Print("1");
+ } else {
+ OS::Print("0");
+ }
+ }
+}
+
+
bool BitmapBuilder::GetBit(intptr_t bit_offset) const {
if (!InRange(bit_offset)) {
return false;
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index fc2c685..6d3376a3 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -47,6 +47,8 @@
// Sets min..max (inclusive) to value.
void SetRange(intptr_t min, intptr_t max, bool value);
+ void Print() const;
+
private:
static const intptr_t kInitialSizeInBytes = 16;
static const intptr_t kIncrementSizeInBytes = 16;
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index c461d93..0c9a7ec 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -189,6 +189,7 @@
case DeoptInstr::kStackSlot:
case DeoptInstr::kDoubleStackSlot:
case DeoptInstr::kInt64StackSlot:
+ case DeoptInstr::kInt64StackSlotPair:
case DeoptInstr::kFloat32x4StackSlot:
case DeoptInstr::kInt32x4StackSlot:
case DeoptInstr::kFloat64x2StackSlot:
@@ -199,7 +200,8 @@
case DeoptInstr::kRegister:
case DeoptInstr::kFpuRegister:
- case DeoptInstr::kInt64FpuRegister:
+ case DeoptInstr::kInt64RegisterPair:
+ case DeoptInstr::kInt64StackSlotRegister:
case DeoptInstr::kFloat32x4FpuRegister:
case DeoptInstr::kInt32x4FpuRegister:
case DeoptInstr::kFloat64x2FpuRegister:
@@ -451,7 +453,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "ms%" Pd "", stack_slot_index_);
+ "int64 stack slot:%" Pd "", stack_slot_index_);
}
void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
@@ -719,21 +721,28 @@
};
-class DeoptInt64FpuRegisterInstr: public DeoptInstr {
+class DeoptInt64RegisterPairInstr: public DeoptInstr {
public:
- explicit DeoptInt64FpuRegisterInstr(intptr_t reg_as_int)
- : reg_(static_cast<FpuRegister>(reg_as_int)) {}
+ DeoptInt64RegisterPairInstr(intptr_t lo_reg_as_int, intptr_t hi_reg_as_int)
+ : lo_reg_(static_cast<Register>(lo_reg_as_int)),
+ hi_reg_(static_cast<Register>(hi_reg_as_int)) {}
- virtual intptr_t source_index() const { return static_cast<intptr_t>(reg_); }
- virtual DeoptInstr::Kind kind() const { return kInt64FpuRegister; }
+ virtual intptr_t source_index() const {
+ return EncodeRegisters(static_cast<intptr_t>(lo_reg_),
+ static_cast<intptr_t>(hi_reg_));
+ }
+ virtual DeoptInstr::Kind kind() const { return kInt64RegisterPair; }
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "%s(m)", Assembler::FpuRegisterName(reg_));
+ "int64 register pair: %s,%s", Assembler::RegisterName(hi_reg_),
+ Assembler::RegisterName(lo_reg_));
}
void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
- int64_t value = deopt_context->FpuRegisterValueAsInt64(reg_);
+ uint32_t lo_value = deopt_context->RegisterValue(lo_reg_);
+ int32_t hi_value = deopt_context->RegisterValue(hi_reg_);
+ int64_t value = Utils::LowHighTo64Bits(lo_value, hi_value);
*reinterpret_cast<RawSmi**>(dest_addr) = Smi::New(0);
if (Smi::IsValid64(value)) {
*dest_addr = reinterpret_cast<intptr_t>(
@@ -744,10 +753,178 @@
}
}
- private:
- const FpuRegister reg_;
+ static const intptr_t kFieldWidth = kBitsPerWord / 2;
+ class LoRegister : public BitField<intptr_t, 0, kFieldWidth> { };
+ class HiRegister : public BitField<intptr_t, kFieldWidth, kFieldWidth> { };
+ static intptr_t EncodeRegisters(intptr_t lo_reg_as_int,
+ intptr_t hi_reg_as_int) {
+ return LoRegister::encode(lo_reg_as_int) |
+ HiRegister::encode(hi_reg_as_int);
+ }
- DISALLOW_COPY_AND_ASSIGN(DeoptInt64FpuRegisterInstr);
+ static intptr_t DecodeLoRegister(intptr_t v) {
+ return LoRegister::decode(v);
+ }
+
+ static intptr_t DecodeHiRegister(intptr_t v) {
+ return HiRegister::decode(v);
+ }
+
+ private:
+ const Register lo_reg_;
+ const Register hi_reg_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptInt64RegisterPairInstr);
+};
+
+
+class DeoptInt64StackSlotPairInstr: public DeoptInstr {
+ public:
+ DeoptInt64StackSlotPairInstr(intptr_t lo_slot, intptr_t hi_slot)
+ : lo_slot_(static_cast<Register>(lo_slot)),
+ hi_slot_(static_cast<Register>(hi_slot)) {}
+
+ virtual intptr_t source_index() const {
+ return EncodeSlots(static_cast<intptr_t>(lo_slot_),
+ static_cast<intptr_t>(hi_slot_));
+ }
+ virtual DeoptInstr::Kind kind() const { return kInt64StackSlotPair; }
+
+ virtual const char* ToCString() const {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "int64 stack slots: %" Pd", %" Pd "", lo_slot_, hi_slot_);
+ }
+
+ void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
+ intptr_t lo_source_index =
+ deopt_context->source_frame_size() - lo_slot_ - 1;
+ int32_t* lo_source_addr = reinterpret_cast<int32_t*>(
+ deopt_context->GetSourceFrameAddressAt(lo_source_index));
+ intptr_t hi_source_index =
+ deopt_context->source_frame_size() - hi_slot_ - 1;
+ int32_t* hi_source_addr = reinterpret_cast<int32_t*>(
+ deopt_context->GetSourceFrameAddressAt(hi_source_index));
+ int64_t value = Utils::LowHighTo64Bits(*lo_source_addr, *hi_source_addr);
+ *reinterpret_cast<RawSmi**>(dest_addr) = Smi::New(0);
+ if (Smi::IsValid64(value)) {
+ *dest_addr = reinterpret_cast<intptr_t>(
+ Smi::New(static_cast<intptr_t>(value)));
+ } else {
+ deopt_context->DeferMintMaterialization(
+ value, reinterpret_cast<RawMint**>(dest_addr));
+ }
+ }
+
+ static const intptr_t kFieldWidth = kBitsPerWord / 2;
+ class LoSlot : public BitField<intptr_t, 0, kFieldWidth> { };
+ class HiSlot : public BitField<intptr_t, kFieldWidth, kFieldWidth> { };
+ static intptr_t EncodeSlots(intptr_t lo_slot,
+ intptr_t hi_slot) {
+ return LoSlot::encode(lo_slot) |
+ HiSlot::encode(hi_slot);
+ }
+
+ static intptr_t DecodeLoSlot(intptr_t v) {
+ return LoSlot::decode(v);
+ }
+
+ static intptr_t DecodeHiSlot(intptr_t v) {
+ return HiSlot::decode(v);
+ }
+
+ private:
+ const intptr_t lo_slot_;
+ const intptr_t hi_slot_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotPairInstr);
+};
+
+
+class DeoptInt64StackSlotRegisterInstr : public DeoptInstr {
+ public:
+ DeoptInt64StackSlotRegisterInstr(intptr_t source_index,
+ intptr_t reg_as_int,
+ bool flip)
+ : slot_(source_index),
+ reg_(static_cast<Register>(reg_as_int)),
+ flip_(flip) {
+ // when flip_ is false, stack slot is low bits and reg is high bits.
+ // when flip_ is true, stack slot is high bits and reg is low bits.
+ }
+
+ virtual intptr_t source_index() const {
+ return Encode(static_cast<intptr_t>(slot_),
+ static_cast<intptr_t>(reg_),
+ flip_ ? 1 : 0);
+ }
+ virtual DeoptInstr::Kind kind() const { return kInt64StackSlotRegister; }
+
+ virtual const char* ToCString() const {
+ if (flip_) {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "int64 reg: %s, stack slot: %" Pd "", Assembler::RegisterName(reg_),
+ slot_);
+ } else {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "int64 stack slot: %" Pd", reg: %s", slot_,
+ Assembler::RegisterName(reg_));
+ }
+ }
+
+ void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
+ intptr_t slot_source_index =
+ deopt_context->source_frame_size() - slot_ - 1;
+ int32_t* slot_source_addr = reinterpret_cast<int32_t*>(
+ deopt_context->GetSourceFrameAddressAt(slot_source_index));
+ int32_t slot_value = *slot_source_addr;
+ int32_t reg_value = deopt_context->RegisterValue(reg_);
+ int64_t value;
+ if (flip_) {
+ value = Utils::LowHighTo64Bits(reg_value, slot_value);
+ } else {
+ value = Utils::LowHighTo64Bits(slot_value, reg_value);
+ }
+ *reinterpret_cast<RawSmi**>(dest_addr) = Smi::New(0);
+ if (Smi::IsValid64(value)) {
+ *dest_addr = reinterpret_cast<intptr_t>(
+ Smi::New(static_cast<intptr_t>(value)));
+ } else {
+ deopt_context->DeferMintMaterialization(
+ value, reinterpret_cast<RawMint**>(dest_addr));
+ }
+ }
+
+ static const intptr_t kFieldWidth = kBitsPerWord / 2;
+ class Slot : public BitField<intptr_t, 0, kFieldWidth> { };
+ class Reg : public BitField<intptr_t, kFieldWidth, kFieldWidth - 1> { };
+ // 1 bit for the flip.
+ class Flip : public BitField<intptr_t, kFieldWidth * 2 - 1, 1> { };
+
+ static intptr_t Encode(intptr_t slot,
+ intptr_t reg_as_int,
+ bool flip) {
+ return Slot::encode(slot) |
+ Reg::encode(reg_as_int) |
+ Flip::encode(flip ? 1 : 0);
+ }
+
+ static intptr_t DecodeSlot(intptr_t v) {
+ return Slot::decode(v);
+ }
+
+ static intptr_t DecodeReg(intptr_t v) {
+ return Reg::decode(v);
+ }
+
+ static bool DecodeFlip(intptr_t v) {
+ return Flip::decode(v);
+ }
+
+ private:
+ const intptr_t slot_;
+ const Register reg_;
+ const bool flip_;
+ DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotRegisterInstr);
};
@@ -1139,7 +1316,28 @@
case kConstant: return new DeoptConstantInstr(source_index);
case kRegister: return new DeoptRegisterInstr(source_index);
case kFpuRegister: return new DeoptFpuRegisterInstr(source_index);
- case kInt64FpuRegister: return new DeoptInt64FpuRegisterInstr(source_index);
+ case kInt64RegisterPair: {
+ intptr_t lo_reg_as_int =
+ DeoptInt64RegisterPairInstr::LoRegister::decode(source_index);
+ intptr_t hi_reg_as_int =
+ DeoptInt64RegisterPairInstr::HiRegister::decode(source_index);
+ return new DeoptInt64RegisterPairInstr(lo_reg_as_int, hi_reg_as_int);
+ }
+ case kInt64StackSlotPair: {
+ intptr_t lo_slot =
+ DeoptInt64StackSlotPairInstr::LoSlot::decode(source_index);
+ intptr_t hi_slot =
+ DeoptInt64StackSlotPairInstr::HiSlot::decode(source_index);
+ return new DeoptInt64StackSlotPairInstr(lo_slot, hi_slot);
+ }
+ case kInt64StackSlotRegister: {
+ intptr_t slot =
+ DeoptInt64StackSlotRegisterInstr::Slot::decode(source_index);
+ intptr_t reg_as_int =
+ DeoptInt64StackSlotRegisterInstr::Reg::decode(source_index);
+ bool flip = DeoptInt64StackSlotRegisterInstr::Flip::decode(source_index);
+ return new DeoptInt64StackSlotRegisterInstr(slot, reg_as_int, flip);
+ }
case kFloat32x4FpuRegister:
return new DeoptFloat32x4FpuRegisterInstr(source_index);
case kFloat64x2FpuRegister:
@@ -1271,8 +1469,6 @@
} else if (source_loc.IsFpuRegister()) {
if (value->definition()->representation() == kUnboxedDouble) {
deopt_instr = new DeoptFpuRegisterInstr(source_loc.fpu_reg());
- } else if (value->definition()->representation() == kUnboxedMint) {
- deopt_instr = new DeoptInt64FpuRegisterInstr(source_loc.fpu_reg());
} else if (value->definition()->representation() == kUnboxedFloat32x4) {
deopt_instr = new DeoptFloat32x4FpuRegisterInstr(source_loc.fpu_reg());
} else if (value->definition()->representation() == kUnboxedInt32x4) {
@@ -1303,6 +1499,34 @@
ASSERT(value->definition()->representation() == kUnboxedFloat64x2);
deopt_instr = new DeoptFloat64x2StackSlotInstr(source_index);
}
+ } else if (source_loc.IsPairLocation()) {
+ ASSERT(value->definition()->representation() == kUnboxedMint);
+ // There are four cases to consider here:
+ // (R = Register, S = Stack slot).
+ // 1) R, R.
+ // 2) S, S.
+ // 3) R, S.
+ // 4) S, R.
+ PairLocation* pair = source_loc.AsPairLocation();
+ if (pair->At(0).IsRegister() && pair->At(1).IsRegister()) {
+ deopt_instr = new DeoptInt64RegisterPairInstr(pair->At(0).reg(),
+ pair->At(1).reg());
+ } else if (pair->At(0).IsStackSlot() && pair->At(1).IsStackSlot()) {
+ deopt_instr = new DeoptInt64StackSlotPairInstr(
+ CalculateStackIndex(pair->At(0)),
+ CalculateStackIndex(pair->At(1)));
+ } else if (pair->At(0).IsRegister() && pair->At(1).IsStackSlot()) {
+ deopt_instr = new DeoptInt64StackSlotRegisterInstr(
+ CalculateStackIndex(pair->At(1)),
+ pair->At(0).reg(),
+ true);
+ } else {
+ ASSERT(pair->At(0).IsStackSlot() && pair->At(1).IsRegister());
+ deopt_instr = new DeoptInt64StackSlotRegisterInstr(
+ CalculateStackIndex(pair->At(0)),
+ pair->At(1).reg(),
+ false);
+ }
} else if (source_loc.IsInvalid() &&
value->definition()->IsMaterializeObject()) {
const intptr_t index = FindMaterialization(
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 551d043..23a5e97 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -58,21 +58,29 @@
intptr_t RegisterValue(Register reg) const {
ASSERT(cpu_registers_ != NULL);
+ ASSERT(reg >= 0);
+ ASSERT(reg < kNumberOfCpuRegisters);
return cpu_registers_[reg];
}
double FpuRegisterValue(FpuRegister reg) const {
ASSERT(fpu_registers_ != NULL);
+ ASSERT(reg >= 0);
+ ASSERT(reg < kNumberOfFpuRegisters);
return *reinterpret_cast<double*>(&fpu_registers_[reg]);
}
int64_t FpuRegisterValueAsInt64(FpuRegister reg) const {
ASSERT(fpu_registers_ != NULL);
+ ASSERT(reg >= 0);
+ ASSERT(reg < kNumberOfFpuRegisters);
return *reinterpret_cast<int64_t*>(&fpu_registers_[reg]);
}
simd128_value_t FpuRegisterValueAsSimd128(FpuRegister reg) const {
ASSERT(fpu_registers_ != NULL);
+ ASSERT(reg >= 0);
+ ASSERT(reg < kNumberOfFpuRegisters);
const float* address = reinterpret_cast<float*>(&fpu_registers_[reg]);
return simd128_value_t().readFrom(address);
}
@@ -216,16 +224,18 @@
kConstant,
kRegister,
kFpuRegister,
- kInt64FpuRegister,
+ kInt64RegisterPair,
kFloat32x4FpuRegister,
kFloat64x2FpuRegister,
kInt32x4FpuRegister,
kStackSlot,
kDoubleStackSlot,
kInt64StackSlot,
+ kInt64StackSlotPair,
kFloat32x4StackSlot,
kFloat64x2StackSlot,
kInt32x4StackSlot,
+ kInt64StackSlotRegister,
kPcMarker,
kPp,
kCallerFp,
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 4a3d66d..bfc098f 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -398,11 +398,24 @@
return;
}
- OS::Print(" live range v%" Pd " [%" Pd ", %" Pd ") in ",
- vreg(), Start(), End());
+ OS::Print(" live range v%" Pd " [%" Pd ", %" Pd ") in ", vreg(),
+ Start(),
+ End());
assigned_location().Print();
+ if (spill_slot_.HasStackIndex()) {
+ intptr_t stack_slot = spill_slot_.stack_index();
+ OS::Print(" allocated spill slot: %" Pd "", stack_slot);
+ }
OS::Print("\n");
+ SafepointPosition* safepoint = first_safepoint();
+ while (safepoint != NULL) {
+ OS::Print(" Safepoint [%" Pd "]: ", safepoint->pos());
+ safepoint->locs()->stack_bitmap()->Print();
+ OS::Print("\n");
+ safepoint = safepoint->next();
+ }
+
UsePosition* use_pos = uses_;
for (UseInterval* interval = first_use_interval_;
interval != NULL;
@@ -564,6 +577,7 @@
GraphEntryInstr* graph_entry = flow_graph_.graph_entry();
for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
Definition* defn = (*graph_entry->initial_definitions())[i];
+ ASSERT(!defn->HasPairRepresentation());
LiveRange* range = GetLiveRange(defn->ssa_temp_index());
range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos());
range->DefineAt(graph_entry->start_pos());
@@ -612,11 +626,14 @@
// in stack maps.
spill_slots_.Add(range_end);
quad_spill_slots_.Add(false);
+ untagged_spill_slots_.Add(false);
+ // Note, all incoming parameters are assumed to be tagged.
MarkAsObjectAtSafepoints(range);
} else if (defn->IsConstant() && block->IsCatchBlockEntry()) {
// Constants at catch block entries consume spill slots.
spill_slots_.Add(range_end);
quad_spill_slots_.Add(false);
+ untagged_spill_slots_.Add(false);
}
}
@@ -632,7 +649,6 @@
static Location::Kind RegisterKindForResult(Instruction* instr) {
if ((instr->representation() == kUnboxedDouble) ||
- (instr->representation() == kUnboxedMint) ||
(instr->representation() == kUnboxedFloat32x4) ||
(instr->representation() == kUnboxedInt32x4) ||
(instr->representation() == kUnboxedFloat64x2) ||
@@ -802,8 +818,12 @@
for (intptr_t i = 0; i < env->Length(); ++i) {
Value* value = env->ValueAt(i);
- locations[i] = Location::Any();
Definition* def = value->definition();
+ if (def->HasPairRepresentation()) {
+ locations[i] = Location::Pair(Location::Any(), Location::Any());
+ } else {
+ locations[i] = Location::Any();
+ }
if (def->IsPushArgument()) {
// Frame size is unknown until after allocation.
@@ -827,13 +847,23 @@
continue;
}
- LiveRange* range = GetLiveRange(def->ssa_temp_index());
- range->AddUseInterval(block_start_pos, use_pos);
- range->AddUse(use_pos, &locations[i]);
-
if (def->HasPairRepresentation()) {
- LiveRange* range =
+ PairLocation* location_pair = locations[i].AsPairLocation();
+ {
+ // First live range.
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, location_pair->SlotAt(0));
+ }
+ {
+ // Second live range.
+ LiveRange* range =
GetLiveRange(ToSecondPairVreg(def->ssa_temp_index()));
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, location_pair->SlotAt(1));
+ }
+ } else {
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
range->AddUseInterval(block_start_pos, use_pos);
range->AddUse(use_pos, &locations[i]);
}
@@ -869,13 +899,25 @@
continue;
}
- locations[i] = Location::Any();
-
- LiveRange* range = GetLiveRange(def->ssa_temp_index());
- range->AddUseInterval(block_start_pos, use_pos);
- range->AddUse(use_pos, &locations[i]);
if (def->HasPairRepresentation()) {
- LiveRange* range = GetLiveRange(ToSecondPairVreg(def->ssa_temp_index()));
+ locations[i] = Location::Pair(Location::Any(), Location::Any());
+ PairLocation* location_pair = locations[i].AsPairLocation();
+ {
+ // First live range.
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, location_pair->SlotAt(0));
+ }
+ {
+ // Second live range.
+ LiveRange* range =
+ GetLiveRange(ToSecondPairVreg(def->ssa_temp_index()));
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, location_pair->SlotAt(1));
+ }
+ } else {
+ locations[i] = Location::Any();
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
range->AddUseInterval(block_start_pos, use_pos);
range->AddUse(use_pos, &locations[i]);
}
@@ -889,7 +931,8 @@
intptr_t pos,
Location* in_ref,
Value* input,
- intptr_t vreg) {
+ intptr_t vreg,
+ RegisterSet* live_registers) {
ASSERT(in_ref != NULL);
ASSERT(!in_ref->IsPairLocation());
ASSERT(input != NULL);
@@ -903,6 +946,9 @@
// value --*
// register [-----)
//
+ if (live_registers != NULL) {
+ live_registers->Add(*in_ref, range->representation());
+ }
MoveOperands* move =
AddMoveAt(pos - 1, *in_ref, Location::Any());
BlockLocation(*in_ref, pos - 1, pos + 1);
@@ -1114,6 +1160,12 @@
locs->out(0).IsUnallocated() &&
(locs->out(0).policy() == Location::kSameAsFirstInput);
+ // Output is same as first input which is a pair.
+ if (output_same_as_first_input && locs->in(0).IsPairLocation()) {
+ // Make out into a PairLocation.
+ locs->set_out(0, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
+ }
// Add uses from the deoptimization environment.
if (current->env() != NULL) ProcessEnvironmentUses(block, current);
@@ -1128,6 +1180,10 @@
// the location is the first register or second register.
Value* input = current->InputAt(j);
Location* in_ref = locs->in_slot(j);
+ RegisterSet* live_registers = NULL;
+ if (locs->HasCallOnSlowPath()) {
+ live_registers = locs->live_registers();
+ }
if (in_ref->IsPairLocation()) {
ASSERT(input->definition()->HasPairRepresentation());
PairLocation* pair = in_ref->AsPairLocation();
@@ -1135,12 +1191,12 @@
// Each element of the pair is assigned it's own virtual register number
// and is allocated its own LiveRange.
ProcessOneInput(block, pos, pair->SlotAt(0),
- input, vreg);
+ input, vreg, live_registers);
ProcessOneInput(block, pos, pair->SlotAt(1), input,
- ToSecondPairVreg(vreg));
+ ToSecondPairVreg(vreg), live_registers);
} else {
ProcessOneInput(block, pos, in_ref, input,
- input->definition()->ssa_temp_index());
+ input->definition()->ssa_temp_index(), live_registers);
}
}
}
@@ -1522,6 +1578,16 @@
}
+UsePosition* AllocationFinger::FirstInterferingUse(intptr_t after) {
+ if (IsInstructionEndPosition(after)) {
+ // If after is a position at the end of the instruction disregard
+ // any use occuring at it.
+ after += 1;
+ }
+ return FirstRegisterUse(after);
+}
+
+
void AllocationFinger::UpdateAfterSplit(intptr_t first_use_after_split_pos) {
if ((first_register_use_ != NULL) &&
(first_register_use_->pos() >= first_use_after_split_pos)) {
@@ -1695,7 +1761,8 @@
split_pos = ToInstructionStart(to) - 1;
}
- ASSERT((split_pos != kIllegalPosition) && (from < split_pos));
+ ASSERT(split_pos != kIllegalPosition);
+ ASSERT(from < split_pos);
return range->SplitAt(split_pos);
}
@@ -1769,6 +1836,8 @@
((range->representation() == kUnboxedFloat32x4) ||
(range->representation() == kUnboxedInt32x4) ||
(range->representation() == kUnboxedFloat64x2));
+ const bool need_untagged = (register_kind_ == Location::kRegister) &&
+ ((range->representation() == kUntagged));
// Search for a free spill slot among allocated: the value in it should be
// dead and its type should match (e.g. it should not be a part of the quad if
@@ -1780,6 +1849,7 @@
: 0;
for (; idx < spill_slots_.length(); idx++) {
if ((need_quad == quad_spill_slots_[idx]) &&
+ (need_untagged == untagged_spill_slots_[idx]) &&
(spill_slots_[idx] <= start)) {
break;
}
@@ -1789,9 +1859,11 @@
// No free spill slot found. Allocate a new one.
spill_slots_.Add(0);
quad_spill_slots_.Add(need_quad);
+ untagged_spill_slots_.Add(need_untagged);
if (need_quad) { // Allocate two double stack slots if we need quad slot.
spill_slots_.Add(0);
quad_spill_slots_.Add(need_quad);
+ untagged_spill_slots_.Add(need_untagged);
}
}
@@ -1822,8 +1894,7 @@
ASSERT(need_quad);
location = Location::QuadStackSlot(slot_idx);
} else {
- ASSERT((range->representation() == kUnboxedDouble) ||
- (range->representation() == kUnboxedMint));
+ ASSERT((range->representation() == kUnboxedDouble));
location = Location::DoubleStackSlot(slot_idx);
}
range->set_spill_slot(location);
@@ -1841,6 +1912,7 @@
for (SafepointPosition* safepoint = range->first_safepoint();
safepoint != NULL;
safepoint = safepoint->next()) {
+ // Mark the stack slot as having an object.
safepoint->locs()->stack_bitmap()->Set(stack_index, true);
}
range = range->next_sibling();
@@ -2199,9 +2271,8 @@
return false;
}
- const UsePosition* use =
- allocated->finger()->FirstRegisterBeneficialUse(unallocated->Start());
-
+ UsePosition* use =
+ allocated->finger()->FirstInterferingUse(start);
if ((use != NULL) && ((ToInstructionStart(use->pos()) - start) <= 1)) {
// This register is blocked by interval that is used
// as register in the current instruction and can't
@@ -2281,7 +2352,7 @@
if (intersection == kMaxPosition) return false;
const intptr_t spill_position = first_unallocated->start();
- UsePosition* use = allocated->finger()->FirstRegisterUse(spill_position);
+ UsePosition* use = allocated->finger()->FirstInterferingUse(spill_position);
if (use == NULL) {
// No register uses after this point.
SpillAfter(allocated, spill_position);
@@ -2316,6 +2387,7 @@
void FlowGraphAllocator::ConvertUseTo(UsePosition* use, Location loc) {
+ ASSERT(!loc.IsPairLocation());
ASSERT(use->location_slot() != NULL);
Location* slot = use->location_slot();
ASSERT(slot->IsUnallocated());
@@ -2350,7 +2422,7 @@
safepoint = safepoint->next()) {
if (!safepoint->locs()->always_calls()) {
ASSERT(safepoint->locs()->can_call());
- safepoint->locs()->live_registers()->Add(loc);
+ safepoint->locs()->live_registers()->Add(loc, range->representation());
}
}
}
@@ -2669,12 +2741,22 @@
}
+static Representation RepresentationForRange(Representation definition_rep) {
+ if (definition_rep == kUnboxedMint) {
+ // kUnboxedMint is split into two ranges, each of which are kUntagged.
+ return kUntagged;
+ }
+ return definition_rep;
+}
+
+
void FlowGraphAllocator::CollectRepresentations() {
// Parameters.
GraphEntryInstr* graph_entry = flow_graph_.graph_entry();
for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) {
Definition* def = (*graph_entry->initial_definitions())[i];
- value_representations_[def->ssa_temp_index()] = def->representation();
+ value_representations_[def->ssa_temp_index()] =
+ RepresentationForRange(def->representation());
ASSERT(!def->HasPairRepresentation());
}
@@ -2690,7 +2772,9 @@
i < catch_entry->initial_definitions()->length();
++i) {
Definition* def = (*catch_entry->initial_definitions())[i];
- value_representations_[def->ssa_temp_index()] = def->representation();
+ ASSERT(!def->HasPairRepresentation());
+ value_representations_[def->ssa_temp_index()] =
+ RepresentationForRange(def->representation());
}
}
// Phis.
@@ -2700,7 +2784,9 @@
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) {
- value_representations_[phi->ssa_temp_index()] = phi->representation();
+ ASSERT(!phi->HasPairRepresentation());
+ value_representations_[phi->ssa_temp_index()] =
+ RepresentationForRange(phi->representation());
}
}
}
@@ -2711,9 +2797,11 @@
Definition* def = instr_it.Current()->AsDefinition();
if ((def != NULL) && (def->ssa_temp_index() >= 0)) {
const intptr_t vreg = def->ssa_temp_index();
- value_representations_[vreg] = def->representation();
+ value_representations_[vreg] =
+ RepresentationForRange(def->representation());
if (def->HasPairRepresentation()) {
- value_representations_[ToSecondPairVreg(vreg)] = def->representation();
+ value_representations_[ToSecondPairVreg(vreg)] =
+ RepresentationForRange(def->representation());
}
}
}
@@ -2761,6 +2849,7 @@
cpu_spill_slot_count_ = spill_slots_.length();
spill_slots_.Clear();
quad_spill_slots_.Clear();
+ untagged_spill_slots_.Clear();
PrepareForAllocation(Location::kFpuRegister,
kNumberOfFpuRegisters,
diff --git a/runtime/vm/flow_graph_allocator.h b/runtime/vm/flow_graph_allocator.h
index ab05f25..e795552b 100644
--- a/runtime/vm/flow_graph_allocator.h
+++ b/runtime/vm/flow_graph_allocator.h
@@ -113,7 +113,8 @@
intptr_t pos,
Location* in_ref,
Value* input,
- intptr_t vreg);
+ intptr_t vreg,
+ RegisterSet* live_registers);
void ProcessOneOutput(BlockEntryInstr* block,
Instruction* current,
intptr_t pos,
@@ -317,6 +318,11 @@
// are disjoint.
GrowableArray<bool> quad_spill_slots_;
+ // Track whether a spill slot is expected to hold a tagged or untagged value.
+ // This is used to keep tagged and untagged spill slots disjoint. See bug
+ // #18955 for details.
+ GrowableArray<bool> untagged_spill_slots_;
+
intptr_t cpu_spill_slot_count_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator);
@@ -498,6 +504,7 @@
Location FirstHint();
UsePosition* FirstRegisterUse(intptr_t after_pos);
UsePosition* FirstRegisterBeneficialUse(intptr_t after_pos);
+ UsePosition* FirstInterferingUse(intptr_t after_pos);
private:
UseInterval* first_pending_use_interval_;
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 648bc6e..7da1818 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -567,7 +567,7 @@
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
Register reg = static_cast<Register>(i);
if (locs->live_registers()->ContainsRegister(reg)) {
- bitmap->Set(bitmap->Length(), true);
+ bitmap->Set(bitmap->Length(), locs->live_registers()->IsTagged(reg));
}
}
}
@@ -638,7 +638,6 @@
Value* value = it.CurrentValue();
switch (value->definition()->representation()) {
case kUnboxedDouble:
- case kUnboxedMint:
it.SetCurrentLocation(Location::DoubleStackSlot(index));
break;
case kUnboxedFloat32x4:
@@ -649,6 +648,27 @@
default:
UNREACHABLE();
}
+ } else if (loc.IsPairLocation()) {
+ intptr_t representation =
+ it.CurrentValue()->definition()->representation();
+ ASSERT(representation == kUnboxedMint);
+ PairLocation* value_pair = loc.AsPairLocation();
+ intptr_t index_lo;
+ intptr_t index_hi;
+ if (value_pair->At(0).IsRegister()) {
+ index_lo = cpu_reg_slots[value_pair->At(0).reg()];
+ } else {
+ ASSERT(value_pair->At(0).IsStackSlot());
+ index_lo = value_pair->At(0).stack_index();
+ }
+ if (value_pair->At(1).IsRegister()) {
+ index_hi = cpu_reg_slots[value_pair->At(1).reg()];
+ } else {
+ ASSERT(value_pair->At(1).IsStackSlot());
+ index_hi = value_pair->At(1).stack_index();
+ }
+ it.SetCurrentLocation(Location::Pair(Location::StackSlot(index_lo),
+ Location::StackSlot(index_hi)));
} else if (loc.IsInvalid()) {
Definition* def =
it.CurrentValue()->definition();
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 3ea3503..17253e2 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1446,23 +1446,25 @@
ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
}
- // Store general purpose registers with the lowest register number at the
+ // Store general purpose registers with the highest register number at the
// lowest address.
- const intptr_t cpu_registers = locs->live_registers()->cpu_registers();
- ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0);
- if (cpu_registers != 0) {
- __ PushList(cpu_registers);
+ for (intptr_t reg_idx = 0; reg_idx < kNumberOfCpuRegisters; ++reg_idx) {
+ Register reg = static_cast<Register>(reg_idx);
+ if (locs->live_registers()->ContainsRegister(reg)) {
+ __ Push(reg);
+ }
}
}
void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
- // General purpose registers have the lowest register number at the
+ // General purpose registers have the highest register number at the
// lowest address.
- const intptr_t cpu_registers = locs->live_registers()->cpu_registers();
- ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0);
- if (cpu_registers != 0) {
- __ PopList(cpu_registers);
+ for (intptr_t reg_idx = kNumberOfCpuRegisters - 1; reg_idx >= 0; --reg_idx) {
+ Register reg = static_cast<Register>(reg_idx);
+ if (locs->live_registers()->ContainsRegister(reg)) {
+ __ Pop(reg);
+ }
}
const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index b6338bd..6ef9ef6 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -602,7 +602,7 @@
Definition* converted = NULL;
if ((from == kTagged) && (to == kUnboxedMint)) {
ASSERT((deopt_target != NULL) ||
- (use->Type()->ToCid() == kDoubleCid));
+ (use->Type()->ToCid() == kUnboxedMint));
const intptr_t deopt_id = (deopt_target != NULL) ?
deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
converted = new UnboxIntegerInstr(use->CopyWithType(), deopt_id);
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index a21400c..c1bcf36 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2131,7 +2131,6 @@
Value* value = InputAt(i);
switch (value->definition()->representation()) {
case kUnboxedDouble:
- case kUnboxedMint:
locations_[i] = Location::DoubleStackSlot(index);
break;
case kUnboxedFloat32x4:
@@ -2142,6 +2141,8 @@
default:
UNREACHABLE();
}
+ } else if (loc.IsPairLocation()) {
+ UNREACHABLE();
} else if (loc.IsInvalid()) {
// We currently only perform one iteration of allocation
// sinking, so we do not expect to find materialized objects
@@ -2348,7 +2349,7 @@
for (intptr_t i = 0; i < length; ++i) {
copy->values_.Add(values_[i]->Copy());
if (locations_ != NULL) {
- copy->locations_[i] = locations_[i];
+ copy->locations_[i] = locations_[i].Copy();
}
}
return copy;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index a266402..b1b982c 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -1779,7 +1779,8 @@
void ClearSSATempIndex() { ssa_temp_index_ = -1; }
bool HasPairRepresentation() const {
return (representation() == kPairOfTagged) ||
- (representation() == kPairOfUnboxedDouble);
+ (representation() == kPairOfUnboxedDouble) ||
+ (representation() == kUnboxedMint);
}
// Compile time type of the definition, which may be requested before type
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index a54102b..fd12d67 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -380,14 +380,13 @@
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;
}
@@ -515,37 +514,32 @@
LocationSummary* locs,
Token::Kind kind) {
ASSERT(Token::IsEqualityOperator(kind));
- const QRegister left = locs->in(0).fpu_reg();
- const QRegister right = locs->in(1).fpu_reg();
- const QRegister tmpq = locs->temp(0).fpu_reg();
- const Register tmp_lo = locs->temp(1).reg();
- const Register tmp_hi = locs->temp(2).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();
- __ 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;
+ // Compare lower.
+ __ cmp(left1, ShifterOperand(right1));
+ // Compare upper if lower is equal.
+ __ cmp(left2, ShifterOperand(right2), EQ);
+ return TokenKindToMintCondition(kind);
}
static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler,
LocationSummary* locs,
Token::Kind kind) {
- const QRegister left = locs->in(0).fpu_reg();
- const QRegister right = locs->in(1).fpu_reg();
- const DRegister dleft0 = EvenDRegisterOf(left);
- const DRegister dright0 = EvenDRegisterOf(right);
- const SRegister sleft0 = EvenSRegisterOf(dleft0);
- const SRegister sleft1 = OddSRegisterOf(dleft0);
- const SRegister sright0 = EvenSRegisterOf(dright0);
- const SRegister sright1 = OddSRegisterOf(dright0);
+ 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();
- const Register tmp_left = locs->temp(0).reg();
- const 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;
@@ -568,25 +562,18 @@
}
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);
+ // Compare upper halves first.
+ __ cmp(left2, ShifterOperand(right2));
+ __ LoadImmediate(out, 0, hi_false_cond);
+ __ LoadImmediate(out, 1, hi_true_cond);
+ // If higher words aren't equal, skip comparing lower words.
+ __ b(&done, NE);
- __ 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);
+ __ cmp(left1, ShifterOperand(right1));
+ __ LoadImmediate(out, 1);
+ __ LoadImmediate(out, 0, lo_false_cond);
__ Bind(&done);
+
return NegateCondition(lo_false_cond);
}
@@ -793,13 +780,14 @@
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;
}
@@ -1153,7 +1141,11 @@
} 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;
@@ -1162,7 +1154,6 @@
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if ((representation() == kUnboxedDouble) ||
- (representation() == kUnboxedMint) ||
(representation() == kUnboxedFloat32x4) ||
(representation() == kUnboxedInt32x4) ||
(representation() == kUnboxedFloat64x2)) {
@@ -1194,23 +1185,6 @@
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.
@@ -1225,6 +1199,8 @@
case kTypedDataFloat32x4ArrayCid:
__ vldmd(IA, idx, dresult0, 2);
break;
+ default:
+ UNREACHABLE();
}
return;
}
@@ -1267,7 +1243,34 @@
UNREACHABLE();
}
- const Register result = locs()->out(0).reg();
+ 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:
ASSERT(index_scale() == 1);
@@ -1384,11 +1387,16 @@
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).
@@ -1573,10 +1581,9 @@
__ str(value, element_address);
} else {
ASSERT(RequiredInputRepresentation(2) == kUnboxedMint);
- const 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;
}
@@ -5726,20 +5733,19 @@
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.
@@ -5748,19 +5754,13 @@
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;
}
@@ -5768,19 +5768,30 @@
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 result_lo = result_pair->At(0).reg();
+ Register result_hi = result_pair->At(1).reg();
+ ASSERT(value != result_lo);
+ ASSERT(value != result_hi);
__ Comment("UnboxIntegerInstr");
- __ veorq(result, result, result);
if (value_cid == kMintCid) {
- __ LoadDFromOffset(EvenDRegisterOf(result), value,
- Mint::value_offset() - kHeapObjectTag);
+ // Load low word.
+ __ LoadFromOffset(kWord,
+ result_lo,
+ value,
+ Mint::value_offset() - kHeapObjectTag);
+ // Load high word.
+ __ LoadFromOffset(kWord,
+ result_hi,
+ value,
+ Mint::value_offset() - kHeapObjectTag + kWordSize);
} else if (value_cid == kSmiCid) {
- const 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 result_lo.
+ __ mov(result_lo, ShifterOperand(value));
+ // Untag.
+ __ SmiUntag(result_lo);
+ __ SignFill(result_hi, result_lo);
} else {
const Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id_,
@@ -5792,16 +5803,26 @@
__ b(deopt, NE);
// It's a Mint.
- __ LoadDFromOffset(EvenDRegisterOf(result), value,
- Mint::value_offset() - kHeapObjectTag);
+ // Load low word.
+ __ LoadFromOffset(kWord,
+ result_lo,
+ value,
+ Mint::value_offset() - kHeapObjectTag);
+ // Load high word.
+ __ LoadFromOffset(kWord,
+ result_hi,
+ 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 result_lo.
+ __ mov(result_lo, ShifterOperand(value));
+ // Untag.
+ __ SmiUntag(result_lo);
+ // Sign extend result_lo into result_hi.
+ __ SignFill(result_hi, result_lo);
__ Bind(&done);
}
}
@@ -5809,14 +5830,14 @@
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;
}
@@ -5858,40 +5879,39 @@
void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this);
compiler->AddSlowPathCode(slow_path);
-
- const Register out_reg = locs()->out(0).reg();
- const QRegister value = locs()->in(0).fpu_reg();
- const DRegister dvalue0 = EvenDRegisterOf(value);
- const Register lo = locs()->temp(0).reg();
- const Register hi = locs()->temp(1).reg();
+ PairLocation* value_pair = locs()->in(0).AsPairLocation();
+ Register value_lo = value_pair->At(0).reg();
+ Register value_hi = value_pair->At(1).reg();
+ Register tmp = locs()->temp(0).reg();
+ Register out_reg = locs()->out(0).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.
+ __ CompareImmediate(value_hi, 0);
__ b(&maybe_pos_smi, EQ);
- __ CompareImmediate(hi, -1);
+ __ CompareImmediate(value_hi, -1);
__ b(&maybe_neg_smi, EQ);
__ b(¬_smi);
__ Bind(&maybe_pos_smi);
- __ CompareImmediate(lo, kSmiMax);
+ __ CompareImmediate(value_lo, kSmiMax);
__ b(&is_smi, LS); // unsigned lower or same.
__ b(¬_smi);
__ Bind(&maybe_neg_smi);
- __ CompareImmediate(lo, 0);
+ __ CompareImmediate(value_lo, 0);
__ b(¬_smi, GE);
- __ CompareImmediate(lo, kSmiMin);
+ __ CompareImmediate(value_lo, 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(value_lo));
+ __ SmiTag(out_reg);
__ b(&done);
// Not a smi. Box it.
@@ -5900,148 +5920,169 @@
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,
+ value_lo,
+ out_reg,
+ Mint::value_offset() - kHeapObjectTag);
+ __ StoreToOffset(kWord,
+ value_hi,
+ 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) {
- const QRegister left = locs()->in(0).fpu_reg();
- const QRegister right = locs()->in(1).fpu_reg();
- const QRegister out = locs()->out(0).fpu_reg();
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+ PairLocation* right_pair = locs()->in(1).AsPairLocation();
+ Register right_lo = right_pair->At(0).reg();
+ Register right_hi = right_pair->At(1).reg();
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = 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_(out_lo, left_lo, ShifterOperand(right_lo));
+ __ and_(out_hi, left_hi, ShifterOperand(right_hi));
+ }
+ break;
+ case Token::kBIT_OR: {
+ __ orr(out_lo, left_lo, ShifterOperand(right_lo));
+ __ orr(out_hi, left_hi, ShifterOperand(right_hi));
+ }
+ break;
+ case Token::kBIT_XOR: {
+ __ eor(out_lo, left_lo, ShifterOperand(right_lo));
+ __ eor(out_hi, left_hi, ShifterOperand(right_hi));
+ }
+ break;
case Token::kADD:
case Token::kSUB: {
- const intptr_t tmpidx = FLAG_throw_on_javascript_int_overflow ? 2 : 0;
- const QRegister tmp = locs()->temp(tmpidx).fpu_reg();
- const 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(out_lo, left_lo, ShifterOperand(right_lo));
+ __ adcs(out_hi, left_hi, ShifterOperand(right_hi));
} else {
ASSERT(op_kind() == Token::kSUB);
- __ vsubqi(kWordPair, out, left, right);
+ __ subs(out_lo, left_lo, ShifterOperand(right_lo));
+ __ sbcs(out_hi, left_hi, ShifterOperand(right_hi));
}
- __ 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) {
- const Register tmp1 = locs()->temp(0).reg();
- const Register tmp2 = locs()->temp(1).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
}
}
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) {
- const QRegister value = locs()->in(0).fpu_reg();
- const Register shift = locs()->in(1).reg();
- const QRegister temp = locs()->temp(0).fpu_reg();
- ASSERT(temp == Q7);
- const QRegister out = locs()->out(0).fpu_reg();
- const DRegister dtemp0 = EvenDRegisterOf(temp);
- const SRegister stemp0 = EvenSRegisterOf(dtemp0);
- const SRegister stemp1 = OddSRegisterOf(dtemp0);
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+ Register shift = locs()->in(1).reg();
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = out_pair->At(1).reg();
+ Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp);
Label done;
+ // Early out if shift is 0.
__ CompareImmediate(shift, 0);
- __ vmovq(out, value);
+ __ mov(out_lo, ShifterOperand(left_lo));
+ __ mov(out_hi, ShifterOperand(left_hi));
__ b(&done, 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 63.
+ __ CompareImmediate(shift, 63);
+ __ 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);
+ __ cmp(shift, ShifterOperand(32));
+
+ __ mov(out_lo, ShifterOperand(out_hi), HI);
+ __ Asr(out_hi, out_hi, 31, HI);
+ __ sub(shift, shift, ShifterOperand(32), HI);
+
+ __ rsb(temp, shift, ShifterOperand(32));
+ __ mov(temp, ShifterOperand(out_hi, LSL, temp));
+ __ orr(out_lo, temp, ShifterOperand(out_lo, LSR, shift));
+ __ Asr(out_hi, out_hi, shift);
break;
}
case Token::kSHL: {
- __ vmovsr(stemp0, shift); // Move the shift into the low S register.
- __ vshlqu(kWordPair, out, value, temp);
+ __ rsbs(temp, shift, ShifterOperand(32));
+ __ sub(temp, shift, ShifterOperand(32), MI);
+ __ mov(out_hi, ShifterOperand(out_lo, LSL, temp), MI);
+ __ mov(out_hi, ShifterOperand(out_hi, LSL, shift), PL);
+ __ orr(out_hi, out_hi, ShifterOperand(out_lo, LSR, temp), PL);
+ __ mov(out_lo, ShifterOperand(out_lo, LSL, shift));
- // 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);
+ // Check for overflow.
+
+ // Copy high word from output.
+ __ mov(temp, ShifterOperand(out_hi));
+ // Shift copy right.
+ __ Asr(temp, temp, shift);
+ // Compare with high word from input.
+ __ cmp(temp, ShifterOperand(left_hi));
+ // Overflow if they aren't equal.
__ b(deopt, NE);
break;
}
@@ -6052,42 +6093,43 @@
__ Bind(&done);
if (FLAG_throw_on_javascript_int_overflow) {
- const Register tmp1 = locs()->in(1).reg();
- const Register tmp2 = locs()->temp(1).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
}
}
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);
- const QRegister value = locs()->in(0).fpu_reg();
- const QRegister out = locs()->out(0).fpu_reg();
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = 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(out_lo, ShifterOperand(left_lo));
+ __ mvn(out_hi, ShifterOperand(left_hi));
if (FLAG_throw_on_javascript_int_overflow) {
- const Register tmp1 = locs()->temp(0).reg();
- const Register tmp2 = locs()->temp(1).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
}
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index a8f9823..7e082dd 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -253,12 +253,13 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (operation_cid() == kMintCid) {
- const intptr_t kNumTemps = 1;
+ 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::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;
}
@@ -392,22 +393,19 @@
static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler,
Label* overflow,
- XmmRegister result,
- Register tmp) {
+ Register result_lo,
+ Register result_hi) {
// Compare upper half.
Label check_lower;
- __ pextrd(tmp, result, Immediate(1));
- __ cmpl(tmp, Immediate(0x00200000));
+ __ cmpl(result_hi, Immediate(0x00200000));
__ j(GREATER, overflow);
__ j(NOT_EQUAL, &check_lower);
- __ pextrd(tmp, result, Immediate(0));
- __ cmpl(tmp, Immediate(0));
+ __ cmpl(result_lo, Immediate(0));
__ j(ABOVE, overflow);
__ Bind(&check_lower);
- __ pextrd(tmp, result, Immediate(1));
- __ cmpl(tmp, Immediate(-0x00200000));
+ __ cmpl(result_hi, Immediate(-0x00200000));
__ j(LESS, overflow);
// Anything in the lower part would make the number bigger than the lower
// bound, so we are done.
@@ -434,15 +432,20 @@
Token::Kind kind,
BranchLabels labels) {
ASSERT(Token::IsEqualityOperator(kind));
- XmmRegister left = locs.in(0).fpu_reg();
- XmmRegister right = locs.in(1).fpu_reg();
- Register temp = locs.temp(0).reg();
- __ movaps(XMM0, left);
- __ pcmpeqq(XMM0, right);
- __ movd(temp, XMM0);
-
+ 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();
+ Label done;
+ // Compare lower.
+ __ cmpl(left1, right1);
+ __ j(NOT_EQUAL, &done);
+ // Lower is equal, compare upper.
+ __ cmpl(left2, right2);
+ __ Bind(&done);
Condition true_condition = TokenKindToMintCondition(kind);
- __ cmpl(temp, Immediate(-1));
return true_condition;
}
@@ -451,10 +454,12 @@
const LocationSummary& locs,
Token::Kind kind,
BranchLabels labels) {
- XmmRegister left = locs.in(0).fpu_reg();
- XmmRegister right = locs.in(1).fpu_reg();
- Register left_tmp = locs.temp(0).reg();
- Register right_tmp = locs.temp(1).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();
Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW;
switch (kind) {
@@ -480,16 +485,12 @@
ASSERT(hi_cond != OVERFLOW && lo_cond != OVERFLOW);
Label is_true, is_false;
// Compare upper halves first.
- __ pextrd(left_tmp, left, Immediate(1));
- __ pextrd(right_tmp, right, Immediate(1));
- __ cmpl(left_tmp, right_tmp);
+ __ cmpl(left2, right2);
__ j(hi_cond, labels.true_label);
__ j(FlipCondition(hi_cond), labels.false_label);
// If upper is equal, compare lower half.
- __ pextrd(left_tmp, left, Immediate(0));
- __ pextrd(right_tmp, right, Immediate(0));
- __ cmpl(left_tmp, right_tmp);
+ __ cmpl(left1, right1);
return lo_cond;
}
@@ -688,13 +689,13 @@
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (operation_cid() == kMintCid) {
- const intptr_t kNumTemps = 2;
+ 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::RequiresRegister());
- locs->set_temp(1, 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;
}
@@ -1020,7 +1021,17 @@
(representation() == kUnboxedInt32x4) ||
(representation() == kUnboxedFloat64x2)) {
locs->set_out(0, Location::RequiresFpuRegister());
+ } else if (representation() == kUnboxedMint) {
+ if (class_id() == kTypedDataInt32ArrayCid) {
+ locs->set_out(0, Location::Pair(Location::RegisterLocation(EAX),
+ Location::RegisterLocation(EDX)));
+ } else {
+ ASSERT(class_id() == kTypedDataUint32ArrayCid);
+ locs->set_out(0, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
+ }
} else {
+ ASSERT(representation() == kTagged);
locs->set_out(0, Location::RequiresRegister());
}
return locs;
@@ -1049,7 +1060,6 @@
}
if ((representation() == kUnboxedDouble) ||
- (representation() == kUnboxedMint) ||
(representation() == kUnboxedFloat32x4) ||
(representation() == kUnboxedInt32x4) ||
(representation() == kUnboxedFloat64x2)) {
@@ -1058,14 +1068,6 @@
__ SmiUntag(index.reg());
}
switch (class_id()) {
- case kTypedDataInt32ArrayCid:
- __ movss(result, element_address);
- __ pmovsxdq(result, result);
- break;
- case kTypedDataUint32ArrayCid:
- __ xorpd(result, result);
- __ movss(result, element_address);
- break;
case kTypedDataFloat32ArrayCid:
__ movss(result, element_address);
break;
@@ -1077,10 +1079,39 @@
case kTypedDataFloat64x2ArrayCid:
__ movups(result, element_address);
break;
+ default:
+ UNREACHABLE();
}
return;
}
+ 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();
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
+ switch (class_id()) {
+ case kTypedDataInt32ArrayCid:
+ ASSERT(result1 == EAX);
+ ASSERT(result2 == EDX);
+ __ movl(result1, element_address);
+ __ cdq();
+ break;
+ case kTypedDataUint32ArrayCid:
+ __ movl(result1, element_address);
+ __ xorl(result2, result2);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return;
+ }
+
+ ASSERT(representation() == kTagged);
+
Register result = locs()->out(0).reg();
if ((index_scale() == 1) && index.IsRegister()) {
__ SmiUntag(index.reg());
@@ -1212,11 +1243,16 @@
break;
case kTypedDataInt32ArrayCid:
case kTypedDataUint32ArrayCid:
- // Mints are stored in XMM registers. For smis, use a writable register
- // because the value must be untagged before storing.
- locs->set_in(2, value()->IsSmiValue()
- ? Location::WritableRegister()
- : Location::RequiresFpuRegister());
+ // For smis, use a writable register because the value must be untagged
+ // before storing. Mints are stored in registers 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:
case kTypedDataFloat64ArrayCid:
@@ -1333,7 +1369,9 @@
__ movl(element_address, value);
} else {
ASSERT(RequiredInputRepresentation(2) == kUnboxedMint);
- __ movss(element_address, locs()->in(2).fpu_reg());
+ PairLocation* value_pair = locs()->in(2).AsPairLocation();
+ Register value1 = value_pair->At(0).reg();
+ __ movl(element_address, value1);
}
break;
case kTypedDataFloat32ArrayCid:
@@ -5536,19 +5574,12 @@
LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t value_cid = value()->Type()->ToCid();
- const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kMintCid));
- const bool needs_writable_input = (value_cid == kSmiCid);
- const intptr_t kNumTemps = needs_temp ? 1 : 0;
+ const intptr_t kNumTemps = 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());
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_out(0, Location::Pair(Location::RegisterLocation(EAX),
+ Location::RegisterLocation(EDX)));
return summary;
}
@@ -5556,30 +5587,39 @@
void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const intptr_t value_cid = value()->Type()->ToCid();
const Register value = locs()->in(0).reg();
- const XmmRegister result = locs()->out(0).fpu_reg();
+ PairLocation* result_pair = locs()->out(0).AsPairLocation();
+ Register result_lo = result_pair->At(0).reg();
+ Register result_hi = result_pair->At(1).reg();
+
+ ASSERT(value != result_lo);
+ ASSERT(value != result_hi);
+ ASSERT(result_lo == EAX);
+ ASSERT(result_hi == EDX);
if (value_cid == kMintCid) {
- __ movsd(result, FieldAddress(value, Mint::value_offset()));
+ __ movl(result_lo, FieldAddress(value, Mint::value_offset()));
+ __ movl(result_hi, FieldAddress(value, Mint::value_offset() + kWordSize));
} else if (value_cid == kSmiCid) {
- __ SmiUntag(value); // Untag input before conversion.
- __ movd(result, value);
- __ pmovsxdq(result, result);
+ __ movl(result_lo, value);
+ __ SmiUntag(result_lo);
+ // Sign extend into result_hi.
+ __ cdq();
} else {
- Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id_,
ICData::kDeoptUnboxInteger);
Label is_smi, done;
__ testl(value, Immediate(kSmiTagMask));
__ j(ZERO, &is_smi);
- __ CompareClassId(value, kMintCid, temp);
+ __ CompareClassId(value, kMintCid, result_lo);
__ j(NOT_EQUAL, deopt);
- __ movsd(result, FieldAddress(value, Mint::value_offset()));
+ __ movl(result_lo, FieldAddress(value, Mint::value_offset()));
+ __ movl(result_hi, FieldAddress(value, Mint::value_offset() + kWordSize));
__ jmp(&done);
__ Bind(&is_smi);
- __ movl(temp, value);
- __ SmiUntag(temp);
- __ movd(result, temp);
- __ pmovsxdq(result, result);
+ __ movl(result_lo, value);
+ __ SmiUntag(result_lo);
+ // Sign extend into result_hi.
+ __ cdq();
__ Bind(&done);
}
}
@@ -5587,15 +5627,14 @@
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_temp(0, Location::RegisterLocation(EAX));
- summary->set_temp(1, Location::RegisterLocation(EDX));
- // TODO(fschneider): Save one temp by using result register as a temp.
+ summary->set_in(0, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
+ summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
@@ -5637,30 +5676,32 @@
void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this);
compiler->AddSlowPathCode(slow_path);
-
+ PairLocation* value_pair = locs()->in(0).AsPairLocation();
+ Register value_lo = value_pair->At(0).reg();
+ Register value_hi = value_pair->At(1).reg();
Register out_reg = locs()->out(0).reg();
- XmmRegister value = locs()->in(0).fpu_reg();
+
+ // Copy value_hi into out_reg as a temporary.
+ // We modify value_lo but restore it before using it.
+ __ movl(out_reg, value_hi);
// Unboxed operations produce smis or mint-sized values.
// Check if value fits into a smi.
Label not_smi, done;
- __ pextrd(EDX, value, Immediate(1)); // Upper half.
- __ pextrd(EAX, value, Immediate(0)); // Lower half.
+
// 1. Compute (x + -kMinSmi) which has to be in the range
// 0 .. -kMinSmi+kMaxSmi for x to fit into a smi.
- __ addl(EAX, Immediate(0x40000000));
- __ adcl(EDX, Immediate(0));
+ __ addl(value_lo, Immediate(0x40000000));
+ __ adcl(out_reg, Immediate(0));
// 2. Unsigned compare to -kMinSmi+kMaxSmi.
- __ cmpl(EAX, Immediate(0x80000000));
- __ sbbl(EDX, Immediate(0));
+ __ cmpl(value_lo, Immediate(0x80000000));
+ __ sbbl(out_reg, Immediate(0));
__ j(ABOVE_EQUAL, ¬_smi);
// 3. Restore lower half if result is a smi.
- __ subl(EAX, Immediate(0x40000000));
-
- __ SmiTag(EAX);
- __ movl(out_reg, EAX);
+ __ subl(value_lo, Immediate(0x40000000));
+ __ movl(out_reg, value_lo);
+ __ SmiTag(out_reg);
__ jmp(&done);
-
__ Bind(¬_smi);
__ TryAllocate(
Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()),
@@ -5669,7 +5710,10 @@
out_reg,
kNoRegister);
__ Bind(slow_path->exit_label());
- __ movsd(FieldAddress(out_reg, Mint::value_offset()), value);
+ // 3. Restore lower half of input before using it.
+ __ subl(value_lo, Immediate(0x40000000));
+ __ movl(FieldAddress(out_reg, Mint::value_offset()), value_lo);
+ __ movl(FieldAddress(out_reg, Mint::value_offset() + kWordSize), value_hi);
__ Bind(&done);
}
@@ -5680,27 +5724,25 @@
case Token::kBIT_AND:
case Token::kBIT_OR:
case Token::kBIT_XOR: {
- const intptr_t kNumTemps =
- FLAG_throw_on_javascript_int_overflow ? 1 : 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_in(0, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
+ summary->set_in(1, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
summary->set_out(0, Location::SameAsFirstInput());
return summary;
}
case Token::kADD:
case Token::kSUB: {
- const intptr_t kNumTemps = 2;
+ 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());
- summary->set_temp(0, Location::RequiresRegister());
- summary->set_temp(1, Location::RequiresRegister());
+ 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::SameAsFirstInput());
return summary;
}
@@ -5712,67 +5754,68 @@
void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- XmmRegister left = locs()->in(0).fpu_reg();
- XmmRegister right = locs()->in(1).fpu_reg();
-
- ASSERT(locs()->out(0).fpu_reg() == left);
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+ PairLocation* right_pair = locs()->in(1).AsPairLocation();
+ Register right_lo = right_pair->At(0).reg();
+ Register right_hi = right_pair->At(1).reg();
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = out_pair->At(1).reg();
+ ASSERT(out_lo == left_lo);
+ ASSERT(out_hi == left_hi);
Label* deopt = NULL;
if (FLAG_throw_on_javascript_int_overflow) {
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp);
}
switch (op_kind()) {
- case Token::kBIT_AND: __ andpd(left, right); break;
- case Token::kBIT_OR: __ orpd(left, right); break;
- case Token::kBIT_XOR: __ xorpd(left, right); break;
+ case Token::kBIT_AND:
+ __ andl(left_lo, right_lo);
+ __ andl(left_hi, right_hi);
+ break;
+ case Token::kBIT_OR:
+ __ orl(left_lo, right_lo);
+ __ orl(left_hi, right_hi);
+ break;
+ case Token::kBIT_XOR:
+ __ xorl(left_lo, right_lo);
+ __ xorl(left_hi, right_hi);
+ break;
case Token::kADD:
case Token::kSUB: {
- Register lo = locs()->temp(0).reg();
- Register hi = locs()->temp(1).reg();
if (!FLAG_throw_on_javascript_int_overflow) {
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp);
}
-
- Label done, overflow;
- __ pextrd(lo, right, Immediate(0)); // Lower half
- __ pextrd(hi, right, Immediate(1)); // Upper half
- __ subl(ESP, Immediate(2 * kWordSize));
- __ movq(Address(ESP, 0), left);
if (op_kind() == Token::kADD) {
- __ addl(Address(ESP, 0), lo);
- __ adcl(Address(ESP, 1 * kWordSize), hi);
+ __ addl(left_lo, right_lo);
+ __ adcl(left_hi, right_hi);
} else {
- __ subl(Address(ESP, 0), lo);
- __ sbbl(Address(ESP, 1 * kWordSize), hi);
+ __ subl(left_lo, right_lo);
+ __ sbbl(left_hi, right_hi);
}
- __ j(OVERFLOW, &overflow);
- __ movq(left, Address(ESP, 0));
- __ addl(ESP, Immediate(2 * kWordSize));
- __ jmp(&done);
- __ Bind(&overflow);
- __ addl(ESP, Immediate(2 * kWordSize));
- __ jmp(deopt);
- __ Bind(&done);
+ __ j(OVERFLOW, deopt);
break;
}
default: UNREACHABLE();
}
if (FLAG_throw_on_javascript_int_overflow) {
- Register tmp = locs()->temp(0).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, left, tmp);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
}
}
LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 1;
+ const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 0;
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::RegisterLocation(ECX));
- summary->set_temp(0, Location::RequiresRegister());
if (op_kind() == Token::kSHL) {
+ summary->set_temp(0, Location::RequiresRegister());
summary->set_temp(1, Location::RequiresRegister());
}
summary->set_out(0, Location::SameAsFirstInput());
@@ -5781,16 +5824,19 @@
void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- XmmRegister left = locs()->in(0).fpu_reg();
- ASSERT(locs()->in(1).reg() == ECX);
- ASSERT(locs()->out(0).fpu_reg() == left);
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = out_pair->At(1).reg();
+ ASSERT(out_lo == left_lo);
+ ASSERT(out_hi == left_hi);
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp);
Label done;
__ testl(ECX, ECX);
__ j(ZERO, &done); // Shift by 0 is a nop.
- __ subl(ESP, Immediate(2 * kWordSize));
- __ movq(Address(ESP, 0), left);
// Deoptimize if shift count is > 31.
// sarl operation masks the count to 5 bits and
// shrd is undefined with count > operand size (32)
@@ -5801,23 +5847,21 @@
__ j(ABOVE, deopt);
switch (op_kind()) {
case Token::kSHR: {
- Register temp = locs()->temp(0).reg();
- __ movl(temp, Address(ESP, 1 * kWordSize)); // High half.
- __ shrd(Address(ESP, 0), temp); // Shift count in CL.
- __ sarl(Address(ESP, 1 * kWordSize), ECX); // Shift count in CL.
+ __ shrd(left_lo, left_hi); // Shift count in CL.
+ __ sarl(left_hi, ECX); // Shift count in CL.
break;
}
case Token::kSHL: {
Register temp1 = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
- __ movl(temp1, Address(ESP, 0 * kWordSize)); // Low 32 bits.
- __ movl(temp2, Address(ESP, 1 * kWordSize)); // High 32 bits.
- __ shll(Address(ESP, 0 * kWordSize), ECX); // Shift count in CL.
- __ shld(Address(ESP, 1 * kWordSize), temp1); // Shift count in CL.
+ __ movl(temp1, left_lo); // Low 32 bits.
+ __ movl(temp2, left_hi); // High 32 bits.
+ __ shll(left_lo, ECX); // Shift count in CL.
+ __ shld(left_hi, temp1); // Shift count in CL.
// Check for overflow by shifting back the high 32 bits
// and comparing with the input.
__ movl(temp1, temp2);
- __ movl(temp2, Address(ESP, 1 * kWordSize));
+ __ movl(temp2, left_hi);
__ sarl(temp2, ECX);
__ cmpl(temp1, temp2);
__ j(NOT_EQUAL, deopt);
@@ -5827,23 +5871,20 @@
UNREACHABLE();
break;
}
- __ movq(left, Address(ESP, 0));
- __ addl(ESP, Immediate(2 * kWordSize));
__ Bind(&done);
if (FLAG_throw_on_javascript_int_overflow) {
- Register tmp = locs()->temp(0).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, left, tmp);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
}
}
LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps =
- FLAG_throw_on_javascript_int_overflow ? 1 : 0;
+ const intptr_t kNumTemps = 0;
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_out(0, Location::SameAsFirstInput());
if (FLAG_throw_on_javascript_int_overflow) {
summary->set_temp(0, Location::RequiresRegister());
@@ -5854,17 +5895,25 @@
void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(op_kind() == Token::kBIT_NOT);
- XmmRegister value = locs()->in(0).fpu_reg();
- ASSERT(value == locs()->out(0).fpu_reg());
+ PairLocation* left_pair = locs()->in(0).AsPairLocation();
+ Register left_lo = left_pair->At(0).reg();
+ Register left_hi = left_pair->At(1).reg();
+ PairLocation* out_pair = locs()->out(0).AsPairLocation();
+ Register out_lo = out_pair->At(0).reg();
+ Register out_hi = out_pair->At(1).reg();
+ ASSERT(out_lo == left_lo);
+ ASSERT(out_hi == left_hi);
+
Label* deopt = NULL;
if (FLAG_throw_on_javascript_int_overflow) {
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp);
}
- __ pcmpeqq(XMM0, XMM0); // Generate all 1's.
- __ pxor(value, XMM0);
+
+ __ notl(left_lo);
+ __ notl(left_hi);
+
if (FLAG_throw_on_javascript_int_overflow) {
- Register tmp = locs()->temp(0).reg();
- EmitJavascriptIntOverflowCheck(compiler, deopt, value, tmp);
+ EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
}
}
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index d9d044a..9809707 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -210,6 +210,12 @@
f->Print("DS%+" Pd "", stack_index());
} else if (kind() == kQuadStackSlot) {
f->Print("QS%+" Pd "", stack_index());
+ } else if (IsPairLocation()) {
+ f->Print("(");
+ AsPairLocation()->At(0).PrintTo(f);
+ f->Print(", ");
+ AsPairLocation()->At(1).PrintTo(f);
+ f->Print(")");
} else {
f->Print("%s", Name());
}
@@ -233,6 +239,19 @@
}
+Location Location::Copy() const {
+ if (IsPairLocation()) {
+ PairLocation* pair = AsPairLocation();
+ ASSERT(!pair->At(0).IsPairLocation());
+ ASSERT(!pair->At(1).IsPairLocation());
+ return Location::Pair(pair->At(0).Copy(), pair->At(1).Copy());
+ } else {
+ // Copy by value.
+ return *this;
+ }
+}
+
+
void LocationSummary::PrintTo(BufferFormatter* f) const {
if (input_count() > 0) {
f->Print(" (");
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index cabb8db..cf6a60b 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -331,11 +331,15 @@
}
intptr_t stack_index() const {
- ASSERT(IsStackSlot() || IsDoubleStackSlot() || IsQuadStackSlot());
+ ASSERT(HasStackIndex());
// Decode stack index manually to preserve sign.
return payload() - kStackIndexBias;
}
+ bool HasStackIndex() const {
+ return IsStackSlot() || IsDoubleStackSlot() || IsQuadStackSlot();
+ }
+
// Return a memory operand for stack slot locations.
Address ToStackSlotAddress() const;
@@ -365,6 +369,8 @@
return KindField::decode(value_);
}
+ Location Copy() const;
+
private:
explicit Location(uword value) : value_(value) { }
@@ -428,15 +434,20 @@
class RegisterSet : public ValueObject {
public:
- RegisterSet() : cpu_registers_(0), fpu_registers_(0) {
+ RegisterSet() : cpu_registers_(0), untagged_cpu_registers_(0),
+ fpu_registers_(0) {
ASSERT(kNumberOfCpuRegisters <= (kWordSize * kBitsPerByte));
ASSERT(kNumberOfFpuRegisters <= (kWordSize * kBitsPerByte));
}
- void Add(Location loc) {
+ void Add(Location loc, Representation rep = kTagged) {
if (loc.IsRegister()) {
cpu_registers_ |= (1 << loc.reg());
+ if (rep != kTagged) {
+ // CPU register contains an untagged value.
+ MarkUntagged(loc);
+ }
} else if (loc.IsFpuRegister()) {
fpu_registers_ |= (1 << loc.fpu_reg());
}
@@ -450,6 +461,32 @@
}
}
+ void DebugPrint() {
+ for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
+ Register r = static_cast<Register>(i);
+ if (ContainsRegister(r)) {
+ OS::Print("%s %s\n", Assembler::RegisterName(r),
+ IsTagged(r) ? "tagged" : "untagged");
+ }
+ }
+
+ for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
+ FpuRegister r = static_cast<FpuRegister>(i);
+ if (ContainsFpuRegister(r)) {
+ OS::Print("%s\n", Assembler::FpuRegisterName(r));
+ }
+ }
+ }
+
+ void MarkUntagged(Location loc) {
+ ASSERT(loc.IsRegister());
+ untagged_cpu_registers_ |= (1 << loc.reg());
+ }
+
+ bool IsTagged(Register reg) const {
+ return (untagged_cpu_registers_ & (1 << reg)) == 0;
+ }
+
bool ContainsRegister(Register reg) const {
return (cpu_registers_ & (1 << reg)) != 0;
}
@@ -468,6 +505,7 @@
private:
intptr_t cpu_registers_;
+ intptr_t untagged_cpu_registers_;
intptr_t fpu_registers_;
DISALLOW_COPY_AND_ASSIGN(RegisterSet);
@@ -561,6 +599,10 @@
return contains_call_ != kNoCall;
}
+ bool HasCallOnSlowPath() {
+ return can_call() && !always_calls();
+ }
+
void PrintTo(BufferFormatter* f) const;
static LocationSummary* Make(intptr_t input_count,