if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else if (instr->representation().IsInteger32()) {
- // The temporary operand is necessary to ensure that right is not allocated
- // into edx.
- FixedTemp(r1);
+ // TODO(1042) The fixed register allocation
+ // is needed because we call GenericBinaryOpStub from
+ // the generated code, which requires registers r0
+ // and r1 to be used. We should remove that
+ // when we provide a native implementation.
LOperand* value = UseFixed(instr->left(), r0);
- LOperand* divisor = UseRegister(instr->right());
- return AssignEnvironment(DefineFixed(new LDivI(value, divisor), r0));
+ LOperand* divisor = UseFixed(instr->right(), r1);
+ return AssignEnvironment(AssignPointerMap(
+ DefineFixed(new LDivI(value, divisor), r0)));
} else {
return DoArithmeticT(Token::DIV, instr);
}
}
+void LCodeGen::RecordSafepointWithRegistersAndDoubles(
+ LPointerMap* pointers,
+ int arguments,
+ int deoptimization_index) {
+ const ZoneList<LOperand*>* operands = pointers->operands();
+ Safepoint safepoint =
+ safepoints_.DefineSafepointWithRegistersAndDoubles(
+ masm(), arguments, deoptimization_index);
+ for (int i = 0; i < operands->length(); i++) {
+ LOperand* pointer = operands->at(i);
+ if (pointer->IsStackSlot()) {
+ safepoint.DefinePointerSlot(pointer->index());
+ } else if (pointer->IsRegister()) {
+ safepoint.DefinePointerRegister(ToRegister(pointer));
+ }
+ }
+ // Register cp always contains a pointer to the context.
+ safepoint.DefinePointerRegister(cp);
+}
+
+
void LCodeGen::RecordPosition(int position) {
if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
masm()->positions_recorder()->RecordPosition(position);
void LCodeGen::DoDivI(LDivI* instr) {
- Abort("DoDivI unimplemented.");
+ class DeferredDivI: public LDeferredCode {
+ public:
+ DeferredDivI(LCodeGen* codegen, LDivI* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredDivI(instr_); }
+ private:
+ LDivI* instr_;
+ };
+
+ const Register left = ToRegister(instr->left());
+ const Register right = ToRegister(instr->right());
+ const Register scratch = scratch0();
+ const Register result = ToRegister(instr->result());
+
+ // Check for x / 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ tst(right, right);
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ // Check for (0 / -x) that will produce negative zero.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label left_not_zero;
+ __ tst(left, Operand(left));
+ __ b(ne, &left_not_zero);
+ __ tst(right, Operand(right));
+ DeoptimizeIf(mi, instr->environment());
+ __ bind(&left_not_zero);
+ }
+
+ // Check for (-kMinInt / -1).
+ if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ Label left_not_min_int;
+ __ cmp(left, Operand(kMinInt));
+ __ b(ne, &left_not_min_int);
+ __ cmp(right, Operand(-1));
+ DeoptimizeIf(eq, instr->environment());
+ __ bind(&left_not_min_int);
+ }
+
+ Label done, deoptimize;
+ // Test for a few common cases first.
+ __ cmp(right, Operand(1));
+ __ mov(result, left, LeaveCC, eq);
+ __ b(eq, &done);
+
+ __ cmp(right, Operand(2));
+ __ tst(left, Operand(1), eq);
+ __ mov(result, Operand(left, ASR, 1), LeaveCC, eq);
+ __ b(eq, &done);
+
+ __ cmp(right, Operand(4));
+ __ tst(left, Operand(3), eq);
+ __ mov(result, Operand(left, ASR, 2), LeaveCC, eq);
+ __ b(eq, &done);
+
+ // Call the generic stub. The numbers in r0 and r1 have
+ // to be tagged to Smis. If that is not possible, deoptimize.
+ DeferredDivI* deferred = new DeferredDivI(this, instr);
+
+ __ TrySmiTag(left, &deoptimize, scratch);
+ __ TrySmiTag(right, &deoptimize, scratch);
+
+ __ b(al, deferred->entry());
+ __ bind(deferred->exit());
+
+ // If the result in r0 is a Smi, untag it, else deoptimize.
+ __ BranchOnNotSmi(result, &deoptimize);
+ __ SmiUntag(result);
+ __ b(&done);
+
+ __ bind(&deoptimize);
+ DeoptimizeIf(al, instr->environment());
+ __ bind(&done);
+}
+
+
+void LCodeGen::DoDeferredDivI(LDivI* instr) {
+ Register left = ToRegister(instr->left());
+ Register right = ToRegister(instr->right());
+
+ __ PushSafepointRegistersAndDoubles();
+ GenericBinaryOpStub stub(Token::DIV, OVERWRITE_LEFT, left, right);
+ __ CallStub(&stub);
+ RecordSafepointWithRegisters(instr->pointer_map(),
+ 0,
+ Safepoint::kNoDeoptimizationIndex);
+ // Overwrite the stored value of r0 with the result of the stub.
+ __ str(r0, MemOperand(sp, DwVfpRegister::kNumAllocatableRegisters *
+ kDoubleSize));
+ __ PopSafepointRegistersAndDoubles();
}
void FinishCode(Handle<Code> code);
// Deferred code support.
+ void DoDeferredDivI(LDivI* instr);
void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
+ void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
+ int arguments,
+ int deoptimization_index);
void RecordPosition(int position);
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
}
+void MacroAssembler::PushSafepointRegistersAndDoubles() {
+ PushSafepointRegisters();
+ sub(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters *
+ kDoubleSize));
+ for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) {
+ vstr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize);
+ }
+}
+
+
+void MacroAssembler::PopSafepointRegistersAndDoubles() {
+ for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) {
+ vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize);
+ }
+ add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters *
+ kDoubleSize));
+ PopSafepointRegisters();
+}
+
int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
// The registers are pushed starting with the highest encoding,
// which means that lowest encodings are closest to the stack pointer.
// RegList constant kSafepointSavedRegisters.
void PushSafepointRegisters();
void PopSafepointRegisters();
+ void PushSafepointRegistersAndDoubles();
+ void PopSafepointRegistersAndDoubles();
+
static int SafepointRegisterStackIndex(int reg_code);
// Load two consecutive registers with two consecutive memory locations.
add(reg, reg, Operand(reg), s);
}
+ // Try to convert int32 to smi. If the value is to large, preserve
+ // the original value and jump to not_a_smi. Destroys scratch and
+ // sets flags.
+ void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
+ mov(scratch, reg);
+ SmiTag(scratch, SetCC);
+ b(vs, not_a_smi);
+ mov(reg, scratch);
+ }
+
void SmiUntag(Register reg) {
mov(reg, Operand(reg, ASR, kSmiTagSize));
}
pc_and_deoptimization_index.deoptimization_index = deoptimization_index;
pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset();
pc_and_deoptimization_index.arguments = 0;
+ pc_and_deoptimization_index.has_doubles = false;
deoptimization_info_.Add(pc_and_deoptimization_index);
indexes_.Add(new ZoneList<int>(8));
registers_.Add(NULL);
pc_and_deoptimization_index.deoptimization_index = deoptimization_index;
pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset();
pc_and_deoptimization_index.arguments = arguments;
+ pc_and_deoptimization_index.has_doubles = false;
deoptimization_info_.Add(pc_and_deoptimization_index);
indexes_.Add(new ZoneList<int>(8));
registers_.Add(new ZoneList<int>(4));
}
+Safepoint SafepointTableBuilder::DefineSafepointWithRegistersAndDoubles(
+ Assembler* assembler, int arguments, int deoptimization_index) {
+ ASSERT(deoptimization_index != -1);
+ ASSERT(arguments >= 0);
+ DeoptimizationInfo pc_and_deoptimization_index;
+ pc_and_deoptimization_index.pc = assembler->pc_offset();
+ pc_and_deoptimization_index.deoptimization_index = deoptimization_index;
+ pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset();
+ pc_and_deoptimization_index.arguments = arguments;
+ pc_and_deoptimization_index.has_doubles = true;
+ deoptimization_info_.Add(pc_and_deoptimization_index);
+ indexes_.Add(new ZoneList<int>(8));
+ registers_.Add(new ZoneList<int>(4));
+ return Safepoint(indexes_.last(), registers_.last());
+}
+
unsigned SafepointTableBuilder::GetCodeOffset() const {
ASSERT(emitted_);
return offset_;
uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
encoding |= SafepointEntry::GapCodeSizeField::encode(gap_size);
encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
+ encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
return encoding;
}
return ArgumentsField::decode(info_);
}
+ bool has_doubles() const {
+ ASSERT(is_valid());
+ return SaveDoublesField::decode(info_);
+ }
+
uint8_t* bits() {
ASSERT(is_valid());
return bits_;
// instructions before potentially emitting a constant pool.
static const int kGapCodeSizeBits = 13;
static const int kArgumentsFieldBits = 3;
+ static const int kSaveDoublesFieldBits = 1;
static const int kDeoptIndexBits =
- 32 - kGapCodeSizeBits - kArgumentsFieldBits;
+ 32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits;
class GapCodeSizeField: public BitField<unsigned, 0, kGapCodeSizeBits> {};
class DeoptimizationIndexField: public BitField<int,
kGapCodeSizeBits,
class ArgumentsField: public BitField<unsigned,
kGapCodeSizeBits + kDeoptIndexBits,
kArgumentsFieldBits> {}; // NOLINT
+ class SaveDoublesField: public BitField<bool,
+ kGapCodeSizeBits + kDeoptIndexBits +
+ kArgumentsFieldBits,
+ kSaveDoublesFieldBits> { }; // NOLINT
+
private:
unsigned info_;
uint8_t* bits_;
int arguments,
int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
+ // Define a new safepoint with all double registers and the normal
+ // registers on the stack for the current position in the body and
+ // take the number of arguments on top of the registers into account.
+ // TODO(1043) Rewrite the three SafepointTableBuilder::DefineSafepoint
+ // methods to one method that uses template arguments.
+ Safepoint DefineSafepointWithRegistersAndDoubles(
+ Assembler* assembler,
+ int arguments,
+ int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
+
// Update the last safepoint with the size of the code generated for the gap
// following it.
void SetPcAfterGap(int pc) {
unsigned deoptimization_index;
unsigned pc_after_gap;
unsigned arguments;
+ bool has_doubles;
};
uint32_t EncodeExceptPC(const DeoptimizationInfo& info);