Revision: 6304
Author: [email protected]
Date: Fri Jan 14 00:49:52 2011
Log: ARM: Implement DoDivI in the lithium code generator.

This change provides fast code for a few special cases and calls the GenericBinaryOpStub for the rest.

It also changes the register allocation in the generation of lithium instructions to use fixed registers that are compatible with the generic stub. This allocation can be change once we use a more flexible implementation.

Finally, this change provides infrastructure to save double registers at safepoints, which is need to call the stub in deferred code.

BUG=
TEST=

Review URL: http://codereview.chromium.org/6164005
http://code.google.com/p/v8/source/detail?r=6304

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.h
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/safepoint-table.cc
 /branches/bleeding_edge/src/safepoint-table.h

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Thu Jan 13 04:21:47 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Fri Jan 14 00:49:52 2011
@@ -1238,12 +1238,15 @@
   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);
   }
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Jan 13 04:21:47 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Jan 14 00:49:52 2011
@@ -612,6 +612,27 @@
   // Register cp always contains a pointer to the context.
   safepoint.DefinePointerRegister(cp);
 }
+
+
+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) {
@@ -832,7 +853,97 @@


 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();
 }


=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Thu Jan 13 04:21:47 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Fri Jan 14 00:49:52 2011
@@ -71,6 +71,7 @@
   void FinishCode(Handle<Code> code);

   // Deferred code support.
+  void DoDeferredDivI(LDivI* instr);
   void DoDeferredNumberTagD(LNumberTagD* instr);
   void DoDeferredNumberTagI(LNumberTagI* instr);
   void DoDeferredTaggedToI(LTaggedToI* instr);
@@ -200,6 +201,9 @@
   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);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jan 11 23:47:13 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Jan 14 00:49:52 2011
@@ -466,6 +466,25 @@
 }


+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.
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Jan 11 06:11:03 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Jan 14 00:49:52 2011
@@ -232,6 +232,9 @@
   // 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.
@@ -715,6 +718,16 @@
   void SmiTag(Register reg, SBit s = LeaveCC) {
     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));
=======================================
--- /branches/bleeding_edge/src/safepoint-table.cc      Wed Jan 12 06:14:14 2011
+++ /branches/bleeding_edge/src/safepoint-table.cc      Fri Jan 14 00:49:52 2011
@@ -125,6 +125,7 @@
   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);
@@ -141,12 +142,29 @@
   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));
   return Safepoint(indexes_.last(), registers_.last());
 }

+
+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_);
@@ -227,6 +245,7 @@
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;
 }

=======================================
--- /branches/bleeding_edge/src/safepoint-table.h       Wed Jan 12 06:14:14 2011
+++ /branches/bleeding_edge/src/safepoint-table.h       Fri Jan 14 00:49:52 2011
@@ -72,6 +72,11 @@
     ASSERT(is_valid());
     return ArgumentsField::decode(info_);
   }
+
+  bool has_doubles() const {
+    ASSERT(is_valid());
+    return SaveDoublesField::decode(info_);
+  }

   uint8_t* bits() {
     ASSERT(is_valid());
@@ -87,8 +92,9 @@
   // 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,
@@ -96,6 +102,11 @@
   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_;
@@ -209,6 +220,16 @@
       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) {
@@ -227,6 +248,7 @@
     unsigned deoptimization_index;
     unsigned pc_after_gap;
     unsigned arguments;
+    bool has_doubles;
   };

   uint32_t EncodeExceptPC(const DeoptimizationInfo& info);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to