Revision: 6455
Author: [email protected]
Date: Tue Jan 25 03:30:47 2011
Log: X64 Crankshaft: Added a bunch of operations.

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

Modified:
 /branches/bleeding_edge/src/x64/assembler-x64-inl.h
 /branches/bleeding_edge/src/x64/assembler-x64.cc
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/disasm-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.h
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h
 /branches/bleeding_edge/test/cctest/test-assembler-x64.cc

=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64-inl.h Wed Jan 19 03:42:43 2011 +++ /branches/bleeding_edge/src/x64/assembler-x64-inl.h Tue Jan 25 03:30:47 2011
@@ -425,7 +425,7 @@
   // Use SIB with no index register only for base rsp or r12. Otherwise we
   // would skip the SIB byte entirely.
   ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
-  buf_[1] = scale << 6 | index.low_bits() << 3 | base.low_bits();
+  buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
   rex_ |= index.high_bit() << 1 | base.high_bit();
   len_ = 2;
 }
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Mon Jan 24 23:57:56 2011 +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Tue Jan 25 03:30:47 2011
@@ -299,6 +299,34 @@
     buf_[1] = operand.buf_[1];
   }
 }
+
+
+bool Operand::AddressUsesRegister(Register reg) const {
+  int code = reg.code();
+  ASSERT((buf_[0] & 0xC0) != 0xC0);  // Always a memory operand.
+ // Start with only low three bits of base register. Initial decoding doesn't
+  // distinguish on the REX.B bit.
+  int base_code = buf_[0] & 0x07;
+  if (base_code == rsp.code()) {
+    // SIB byte present in buf_[1].
+    // Check the index register from the SIB byte + REX.X prefix.
+    int index_code = ((buf_[1] >> 3) & 0x07) | ((rex_ & 0x02) << 2);
+    // Index code (including REX.X) of 0x04 (rsp) means no index register.
+    if (index_code != rsp.code() && index_code == code) return true;
+    // Add REX.B to get the full base register code.
+    base_code = (buf_[1] & 0x07) | ((rex_ & 0x01) << 3);
+    // A base register of 0x05 (rbp) with mod = 0 means no base register.
+    if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false;
+    return code == base_code;
+  } else {
+    // A base register with low bits of 0x05 (rbp or r13) and mod = 0 means
+    // no base register.
+    if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false;
+    base_code |= ((rex_ & 0x01) << 3);
+    return code == base_code;
+  }
+}
+

// -----------------------------------------------------------------------------
 // Implementation of Assembler.
@@ -2659,6 +2687,30 @@
   emit(0x7E);
   emit_sse_operand(src, dst);
 }
+
+
+void Assembler::movdqa(const Operand& dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit(0x66);
+  emit_rex_64(src, dst);
+  emit(0x0F);
+  emit(0x7F);
+  emit_sse_operand(src, dst);
+}
+
+
+void Assembler::movdqa(XMMRegister dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit(0x66);
+  emit_rex_64(dst, src);
+  emit(0x0F);
+  emit(0x6F);
+  emit_sse_operand(dst, src);
+}


 void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Mon Jan 24 23:57:56 2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Tue Jan 25 03:30:47 2011
@@ -153,6 +153,7 @@
   // Unfortunately we can't make this private in a struct when initializing
   // by assignment.
   int code_;
+
  private:
   static const int registerCodeByAllocationIndex[kNumAllocatableRegisters];
   static const int allocationIndexByRegisterCode[kNumRegisters];
@@ -390,11 +391,15 @@
   // this must not overflow.
   Operand(const Operand& base, int32_t offset);

+  // Checks whether either base or index register is the given register.
+  // Does not check the "reg" part of the Operand.
+  bool AddressUsesRegister(Register reg) const;
+
  private:
   byte rex_;
   byte buf_[6];
-  // The number of bytes in buf_.
-  unsigned int len_;
+  // The number of bytes of buf_ in use.
+  byte len_;

   // Set the ModR/M byte without an encoded 'reg' register. The
   // register is encoded later as part of the emit_operand operation.
@@ -823,6 +828,10 @@
   void andl(Register dst, Register src) {
     arithmetic_op_32(0x23, dst, src);
   }
+
+  void andl(Register dst, const Operand& src) {
+    arithmetic_op_32(0x23, dst, src);
+  }

   void andb(Register dst, Immediate src) {
     immediate_arithmetic_op_8(0x4, dst, src);
@@ -1209,6 +1218,9 @@
   void movsd(XMMRegister dst, XMMRegister src);
   void movsd(XMMRegister dst, const Operand& src);

+  void movdqa(const Operand& dst, XMMRegister src);
+  void movdqa(XMMRegister dst, const Operand& src);
+
   void movss(XMMRegister dst, const Operand& src);
   void movss(const Operand& dst, XMMRegister src);

@@ -1249,10 +1261,6 @@
   void emit_sse_operand(XMMRegister dst, Register src);
   void emit_sse_operand(Register dst, XMMRegister src);

-  // Use either movsd or movlpd.
-  // void movdbl(XMMRegister dst, const Operand& src);
-  // void movdbl(const Operand& dst, XMMRegister src);
-
   // Debugging
   void Print();

=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Jan 24 23:49:39 2011 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jan 25 03:30:47 2011
@@ -2866,7 +2866,7 @@
   __ j(zero, &failure_returned);

   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame();
+  __ LeaveExitFrame(save_doubles_);
   __ ret(0);

   // Handling of failure.
@@ -2975,7 +2975,7 @@
 #else
   int arg_stack_space = 0;
 #endif
-  __ EnterExitFrame(arg_stack_space);
+  __ EnterExitFrame(arg_stack_space, save_doubles_);

   // rax: Holds the context at this point, but should not be used.
   //      On entry to code generated by GenerateCore, it must hold
=======================================
--- /branches/bleeding_edge/src/x64/disasm-x64.cc       Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/x64/disasm-x64.cc       Tue Jan 25 03:30:47 2011
@@ -1023,6 +1023,10 @@
       if (opcode == 0x6E) {
         AppendToBuffer("mov%c %s,",
                        rex_w() ? 'q' : 'd',
+                       NameOfXMMRegister(regop));
+        current += PrintRightOperand(current);
+      } else if (opcode == 0x6F) {
+        AppendToBuffer("movdqa %s,",
                        NameOfXMMRegister(regop));
         current += PrintRightOperand(current);
       } else if (opcode == 0x7E) {
@@ -1030,6 +1034,10 @@
                        rex_w() ? 'q' : 'd');
         current += PrintRightOperand(current);
         AppendToBuffer(", %s", NameOfXMMRegister(regop));
+      } else if (opcode == 0x7F) {
+        AppendToBuffer("movdqa ");
+        current += PrintRightOperand(current);
+        AppendToBuffer(", %s", NameOfXMMRegister(regop));
       } else {
         const char* mnemonic = "?";
         if (opcode == 0x57) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jan 25 02:35:57 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jan 25 03:30:47 2011
@@ -934,7 +934,18 @@


 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
-  Abort("Unimplemented: %s", "DoCmpJSObjectEq");
+  Register left = ToRegister(instr->InputAt(0));
+  Register right = ToRegister(instr->InputAt(1));
+  Register result = ToRegister(instr->result());
+
+  NearLabel different, done;
+  __ cmpq(left, right);
+  __ j(not_equal, &different);
+  __ LoadRoot(result, Heap::kTrueValueRootIndex);
+  __ jmp(&done);
+  __ bind(&different);
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+  __ bind(&done);
 }


@@ -950,7 +961,45 @@


 void LCodeGen::DoIsNull(LIsNull* instr) {
-  Abort("Unimplemented: %s", "DoIsNull");
+  Register reg = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+
+  // If the expression is known to be a smi, then it's
+  // definitely not null. Materialize false.
+  // Consider adding other type and representation tests too.
+  if (instr->hydrogen()->value()->type().IsSmi()) {
+    __ LoadRoot(result, Heap::kFalseValueRootIndex);
+    return;
+  }
+
+  __ CompareRoot(reg, Heap::kNullValueRootIndex);
+  if (instr->is_strict()) {
+    __ movl(result, Immediate(Heap::kTrueValueRootIndex));
+    NearLabel load;
+    __ j(equal, &load);
+    __ movl(result, Immediate(Heap::kFalseValueRootIndex));
+    __ bind(&load);
+    __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0));
+  } else {
+    NearLabel true_value, false_value, done;
+    __ j(equal, &true_value);
+    __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
+    __ j(equal, &true_value);
+    __ JumpIfSmi(reg, &false_value);
+    // Check for undetectable objects by looking in the bit field in
+    // the map. The object has already been smi checked.
+    Register scratch = result;
+    __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+    __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
+             Immediate(1 << Map::kIsUndetectable));
+    __ j(not_zero, &true_value);
+    __ bind(&false_value);
+    __ LoadRoot(result, Heap::kFalseValueRootIndex);
+    __ jmp(&done);
+    __ bind(&true_value);
+    __ LoadRoot(result, Heap::kTrueValueRootIndex);
+    __ bind(&done);
+  }
 }


@@ -992,56 +1041,77 @@


 Condition LCodeGen::EmitIsObject(Register input,
-                                 Register temp1,
-                                 Register temp2,
                                  Label* is_not_object,
                                  Label* is_object) {
-  ASSERT(!input.is(temp1));
-  ASSERT(!input.is(temp2));
-  ASSERT(!temp1.is(temp2));
+  ASSERT(!input.is(kScratchRegister));

   __ JumpIfSmi(input, is_not_object);

-  __ Cmp(input, Factory::null_value());
+  __ CompareRoot(input, Heap::kNullValueRootIndex);
   __ j(equal, is_object);

-  __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset));
+  __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
   // Undetectable objects behave like undefined.
-  __ testb(FieldOperand(temp1, Map::kBitFieldOffset),
+  __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
            Immediate(1 << Map::kIsUndetectable));
   __ j(not_zero, is_not_object);

-  __ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
-  __ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE));
+  __ movzxbl(kScratchRegister,
+             FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
+  __ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE));
   __ j(below, is_not_object);
-  __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE));
+  __ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE));
   return below_equal;
 }


 void LCodeGen::DoIsObject(LIsObject* instr) {
-  Abort("Unimplemented: %s", "DoIsObject");
+  Register reg = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  Label is_false, is_true, done;
+
+  Condition true_cond = EmitIsObject(reg, &is_false, &is_true);
+  __ j(true_cond, &is_true);
+
+  __ bind(&is_false);
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+  __ jmp(&done);
+
+  __ bind(&is_true);
+  __ LoadRoot(result, Heap::kTrueValueRootIndex);
+
+  __ bind(&done);
 }


 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
   Register reg = ToRegister(instr->InputAt(0));
-  Register temp = ToRegister(instr->TempAt(0));
-  Register temp2 = ToRegister(instr->TempAt(1));

   int true_block = chunk_->LookupDestination(instr->true_block_id());
   int false_block = chunk_->LookupDestination(instr->false_block_id());
   Label* true_label = chunk_->GetAssemblyLabel(true_block);
   Label* false_label = chunk_->GetAssemblyLabel(false_block);

- Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
+  Condition true_cond = EmitIsObject(reg, false_label, true_label);

   EmitBranch(true_block, false_block, true_cond);
 }


 void LCodeGen::DoIsSmi(LIsSmi* instr) {
-  Abort("Unimplemented: %s", "DoIsSmi");
+  LOperand* input_operand = instr->InputAt(0);
+  Register result = ToRegister(instr->result());
+  if (input_operand->IsRegister()) {
+    Register input = ToRegister(input_operand);
+    __ CheckSmiToIndicator(result, input);
+  } else {
+    Operand input = ToOperand(instr->InputAt(0));
+    __ CheckSmiToIndicator(result, input);
+  }
+  // result is zero if input is a smi, and one otherwise.
+  ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1);
+  __ movq(result, Operand(kRootRegister, result, times_pointer_size,
+                          Heap::kTrueValueRootIndex * kPointerSize));
 }


@@ -1174,7 +1244,25 @@


 void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
-  Abort("Unimplemented: %s", "DoClassOfTest");
+  Register input = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  ASSERT(input.is(result));
+  Register temp = ToRegister(instr->TempAt(0));
+  Handle<String> class_name = instr->hydrogen()->class_name();
+  NearLabel done;
+  Label is_true, is_false;
+
+  EmitClassOfTest(&is_true, &is_false, class_name, input, temp);
+
+  __ j(not_equal, &is_false);
+
+  __ bind(&is_true);
+  __ LoadRoot(result, Heap::kTrueValueRootIndex);
+  __ jmp(&done);
+
+  __ bind(&is_false);
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+  __ bind(&done);
 }


@@ -1196,7 +1284,12 @@


 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoCmpMapAndBranch");
+  Register reg = ToRegister(instr->InputAt(0));
+  int true_block = instr->true_block_id();
+  int false_block = instr->false_block_id();
+
+  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
+  EmitBranch(true_block, false_block, equal);
 }


@@ -1488,27 +1581,63 @@


 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
-  Abort("Unimplemented: %s", "DoInteger32ToDouble");
+  LOperand* input = instr->InputAt(0);
+  ASSERT(input->IsRegister() || input->IsStackSlot());
+  LOperand* output = instr->result();
+  ASSERT(output->IsDoubleRegister());
+  __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
 }


 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
-  Abort("Unimplemented: %s", "DoNumberTagI");
-}
-
-
-void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
-  Abort("Unimplemented: %s", "DoDeferredNumberTagI");
+  LOperand* input = instr->InputAt(0);
+  ASSERT(input->IsRegister() && input->Equals(instr->result()));
+  Register reg = ToRegister(input);
+
+  __ Integer32ToSmi(reg, reg);
 }


 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
-  Abort("Unimplemented: %s", "DoNumberTagD");
+  class DeferredNumberTagD: public LDeferredCode {
+   public:
+    DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
+   private:
+    LNumberTagD* instr_;
+  };
+
+  XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
+  Register reg = ToRegister(instr->result());
+  Register tmp = ToRegister(instr->TempAt(0));
+
+  DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
+  if (FLAG_inline_new) {
+    __ AllocateHeapNumber(reg, tmp, deferred->entry());
+  } else {
+    __ jmp(deferred->entry());
+  }
+  __ bind(deferred->exit());
+  __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
 }


 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
-  Abort("Unimplemented: %s", "DoDeferredNumberTagD");
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  Register reg = ToRegister(instr->result());
+  __ Move(reg, Smi::FromInt(0));
+
+  __ PushSafepointRegisters();
+  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
+  // Ensure that value in rax survives popping registers.
+  __ movq(kScratchRegister, rax);
+  __ PopSafepointRegisters();
+  __ movq(reg, kScratchRegister);
 }


@@ -1525,7 +1654,34 @@
 void LCodeGen::EmitNumberUntagD(Register input_reg,
                                 XMMRegister result_reg,
                                 LEnvironment* env) {
-  Abort("Unimplemented: %s", "EmitNumberUntagD");
+  NearLabel load_smi, heap_number, done;
+
+  // Smi check.
+  __ JumpIfSmi(input_reg, &load_smi);
+
+  // Heap number map check.
+  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
+                 Heap::kHeapNumberMapRootIndex);
+  __ j(equal, &heap_number);
+
+  __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
+  DeoptimizeIf(not_equal, env);
+
+  // Convert undefined to NaN. Compute NaN as 0/0.
+  __ xorpd(result_reg, result_reg);
+  __ divsd(result_reg, result_reg);
+  __ jmp(&done);
+
+  // Heap number to XMM conversion.
+  __ bind(&heap_number);
+  __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
+  __ jmp(&done);
+
+  // Smi to XMM conversion
+  __ bind(&load_smi);
+  __ SmiToInteger32(kScratchRegister, input_reg);  // Untag smi first.
+  __ cvtlsi2sd(result_reg, kScratchRegister);
+  __ bind(&done);
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Jan 25 02:10:36 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Jan 25 03:30:47 2011
@@ -87,7 +87,6 @@

   // Deferred code support.
   void DoDeferredNumberTagD(LNumberTagD* instr);
-  void DoDeferredNumberTagI(LNumberTagI* instr);
   void DoDeferredTaggedToI(LTaggedToI* instr);
   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
   void DoDeferredStackCheck(LGoto* instr);
@@ -215,8 +214,6 @@
   // Returns the condition on which a final split to
   // true and false label should be made, to optimize fallthrough.
   Condition EmitIsObject(Register input,
-                         Register temp1,
-                         Register temp2,
                          Label* is_not_object,
                          Label* is_object);

=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Tue Jan 25 02:35:57 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Tue Jan 25 03:30:47 2011
@@ -958,12 +958,7 @@
     } else if (v->IsIsObject()) {
       HIsObject* compare = HIsObject::cast(v);
       ASSERT(compare->value()->representation().IsTagged());
-
-      LOperand* temp1 = TempRegister();
-      LOperand* temp2 = TempRegister();
-      return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
-                                    temp1,
-                                    temp2);
+      return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
     } else if (v->IsCompareJSObjectEq()) {
       HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
@@ -1227,26 +1222,34 @@

 LInstruction* LChunkBuilder::DoCompareJSObjectEq(
     HCompareJSObjectEq* instr) {
-  Abort("Unimplemented: %s", "DoCompareJSObjectEq");
-  return NULL;
+  LOperand* left = UseRegisterAtStart(instr->left());
+  LOperand* right = UseRegisterAtStart(instr->right());
+  LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
+  return DefineAsRegister(result);
 }


 LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
-  Abort("Unimplemented: %s", "DoIsNull");
-  return NULL;
+  ASSERT(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+
+  return DefineAsRegister(new LIsNull(value));
 }


 LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
-  Abort("Unimplemented: %s", "DoIsObject");
-  return NULL;
+  ASSERT(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegister(instr->value());
+
+  return DefineAsRegister(new LIsObject(value));
 }


 LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
-  Abort("Unimplemented: %s", "DoIsSmi");
-  return NULL;
+  ASSERT(instr->value()->representation().IsTagged());
+  LOperand* value = UseAtStart(instr->value());
+
+  return DefineAsRegister(new LIsSmi(value));
 }


@@ -1300,7 +1303,62 @@


 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
-  Abort("Unimplemented: %s", "DoChange");
+  Representation from = instr->from();
+  Representation to = instr->to();
+  if (from.IsTagged()) {
+    if (to.IsDouble()) {
+      LOperand* value = UseRegister(instr->value());
+      LNumberUntagD* res = new LNumberUntagD(value);
+      return AssignEnvironment(DefineAsRegister(res));
+    } else {
+      ASSERT(to.IsInteger32());
+      LOperand* value = UseRegister(instr->value());
+      bool needs_check = !instr->value()->type().IsSmi();
+      if (needs_check) {
+        LOperand* xmm_temp =
+            (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
+            ? NULL
+            : FixedTemp(xmm1);
+        LTaggedToI* res = new LTaggedToI(value, xmm_temp);
+        return AssignEnvironment(DefineSameAsFirst(res));
+      } else {
+        return DefineSameAsFirst(new LSmiUntag(value, needs_check));
+      }
+    }
+  } else if (from.IsDouble()) {
+    if (to.IsTagged()) {
+      LOperand* value = UseRegister(instr->value());
+      LOperand* temp = TempRegister();
+
+      // Make sure that temp and result_temp are different registers.
+      LUnallocated* result_temp = TempRegister();
+      LNumberTagD* result = new LNumberTagD(value, temp);
+      return AssignPointerMap(Define(result, result_temp));
+    } else {
+      ASSERT(to.IsInteger32());
+      bool needs_temp = instr->CanTruncateToInt32() &&
+          !CpuFeatures::IsSupported(SSE3);
+      LOperand* value = needs_temp ?
+          UseTempRegister(instr->value()) : UseRegister(instr->value());
+      LOperand* temp = needs_temp ? TempRegister() : NULL;
+ return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp)));
+    }
+  } else if (from.IsInteger32()) {
+    if (to.IsTagged()) {
+      HValue* val = instr->value();
+      LOperand* value = UseRegister(val);
+      if (val->HasRange() && val->range()->IsInSmiRange()) {
+        return DefineSameAsFirst(new LSmiTag(value));
+      } else {
+        LNumberTagI* result = new LNumberTagI(value);
+ return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+      }
+    } else {
+      ASSERT(to.IsDouble());
+      return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
+    }
+  }
+  UNREACHABLE();
   return NULL;
 }

=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Tue Jan 25 02:35:57 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Tue Jan 25 03:30:47 2011
@@ -721,23 +721,20 @@
 };


-class LIsObject: public LTemplateInstruction<1, 1, 1> {
+class LIsObject: public LTemplateInstruction<1, 1, 0> {
  public:
-  LIsObject(LOperand* value, LOperand* temp) {
+  explicit LIsObject(LOperand* value) {
     inputs_[0] = value;
-    temps_[0] = temp;
   }

   DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
 };


-class LIsObjectAndBranch: public LControlInstruction<1, 2> {
+class LIsObjectAndBranch: public LControlInstruction<1, 0> {
  public:
-  LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) {
+  explicit LIsObjectAndBranch(LOperand* value) {
     inputs_[0] = value;
-    temps_[0] = temp;
-    temps_[1] = temp2;
   }

   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Jan 19 02:17:18 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jan 25 03:30:47 2011
@@ -373,6 +373,16 @@
void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
   CallRuntime(Runtime::FunctionForId(id), num_arguments);
 }
+
+
+void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
+  Runtime::Function* function = Runtime::FunctionForId(id);
+  Set(rax, function->nargs);
+  movq(rbx, ExternalReference(function));
+  CEntryStub ces(1);
+  ces.SaveDoubles();
+  CallStub(&ces);
+}


 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
@@ -965,6 +975,27 @@
   testl(src, src);
   return positive;
 }
+
+
+void MacroAssembler::CheckSmiToIndicator(Register dst, Register src) {
+  if (dst.is(src)) {
+    andl(dst, Immediate(kSmiTagMask));
+  } else {
+    movl(dst, Immediate(kSmiTagMask));
+    andl(dst, src);
+  }
+}
+
+
+void MacroAssembler::CheckSmiToIndicator(Register dst, const Operand& src) {
+  if (!(src.AddressUsesRegister(dst))) {
+    movl(dst, Immediate(kSmiTagMask));
+    andl(dst, src);
+  } else {
+    movl(dst, src);
+    andl(dst, Immediate(kSmiTagMask));
+  }
+}


void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) {
@@ -1427,6 +1458,34 @@
 }


+void MacroAssembler::Dropad() {
+  const int kRegistersPushedByPushad = 11;
+  addq(rsp, Immediate(kRegistersPushedByPushad * kPointerSize));
+}
+
+
+// Order general registers are pushed by Pushad:
+// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
+int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
+    0,
+    1,
+    2,
+    3,
+    -1,
+    -1,
+    4,
+    5,
+    6,
+    7,
+    -1,
+    8,
+    9,
+    -1,
+    10,
+    -1
+};
+
+
 void MacroAssembler::PushTryHandler(CodeLocation try_location,
                                     HandlerType type) {
   // Adjust this code if not the case.
@@ -1775,12 +1834,24 @@
 }


-void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) {
+void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
+                                            bool save_doubles) {
 #ifdef _WIN64
-  const int kShaddowSpace = 4;
-  arg_stack_space += kShaddowSpace;
+  const int kShadowSpace = 4;
+  arg_stack_space += kShadowSpace;
 #endif
-  if (arg_stack_space > 0) {
+  // Optionally save all XMM registers.
+  if (save_doubles) {
+    CpuFeatures::Scope scope(SSE2);
+    int space = XMMRegister::kNumRegisters * kDoubleSize +
+        arg_stack_space * kPointerSize;
+    subq(rsp, Immediate(space));
+    int offset = -2 * kPointerSize;
+    for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
+      XMMRegister reg = XMMRegister::FromAllocationIndex(i);
+      movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg);
+    }
+  } else if (arg_stack_space > 0) {
     subq(rsp, Immediate(arg_stack_space * kPointerSize));
   }

@@ -1797,7 +1868,7 @@
 }


-void MacroAssembler::EnterExitFrame(int arg_stack_space) {
+void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) {
   EnterExitFramePrologue(true);

// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
@@ -1805,25 +1876,31 @@
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   lea(r12, Operand(rbp, r14, times_pointer_size, offset));

-  EnterExitFrameEpilogue(arg_stack_space);
+  EnterExitFrameEpilogue(arg_stack_space, save_doubles);
 }


 void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
   EnterExitFramePrologue(false);
-  EnterExitFrameEpilogue(arg_stack_space);
+  EnterExitFrameEpilogue(arg_stack_space, false);
 }


-void MacroAssembler::LeaveExitFrame() {
+void MacroAssembler::LeaveExitFrame(bool save_doubles) {
   // Registers:
   // r12 : argv
-
+  if (save_doubles) {
+    int offset = -2 * kPointerSize;
+    for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
+      XMMRegister reg = XMMRegister::FromAllocationIndex(i);
+      movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize)));
+    }
+  }
   // Get the return address from the stack and restore the frame pointer.
   movq(rcx, Operand(rbp, 1 * kPointerSize));
   movq(rbp, Operand(rbp, 0 * kPointerSize));

-  // Pop everything up to and including the arguments and the receiver
+  // Drop everything up to and including the arguments and the receiver
   // from the caller stack.
   lea(rsp, Operand(r12, 1 * kPointerSize));

=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Jan 19 02:17:18 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Jan 25 03:30:47 2011
@@ -152,7 +152,7 @@
   //
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
   // accessible via StackSpaceOperand.
-  void EnterExitFrame(int arg_stack_space = 0);
+  void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false);

// Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
   // memory (not GCed) on the stack accessible via StackSpaceOperand.
@@ -161,19 +161,19 @@
   // Leave the current exit frame. Expects/provides the return value in
   // register rax:rdx (untouched) and the pointer to the first
   // argument in register rsi.
-  void LeaveExitFrame();
+  void LeaveExitFrame(bool save_doubles = false);

   // Leave the current exit frame. Expects/provides the return value in
   // register rax (untouched).
   void LeaveApiExitFrame();

   // Push and pop the registers that can hold pointers.
-  void PushSafepointRegisters() { UNIMPLEMENTED(); }
-  void PopSafepointRegisters() { UNIMPLEMENTED(); }
+  void PushSafepointRegisters() { Pushad(); }
+  void PopSafepointRegisters() { Popad(); }
   static int SafepointRegisterStackIndex(int reg_code) {
-    UNIMPLEMENTED();
-    return 0;
-  }
+    return kSafepointPushRegisterIndices[reg_code];
+  }
+

// ---------------------------------------------------------------------------
   // JavaScript invokes
@@ -301,6 +301,11 @@
   // conversion to a smi.
   Condition CheckUInteger32ValidSmiValue(Register src);

+  // Check whether src is a Smi, and set dst to zero if it is a smi,
+  // and to one if it isn't.
+  void CheckSmiToIndicator(Register dst, Register src);
+  void CheckSmiToIndicator(Register dst, const Operand& src);
+
   // Test-and-jump functions. Typically combines a check function
   // above with a conditional jump.

@@ -597,6 +602,9 @@
   // (kScratchRegister, kSmiConstantRegister, kRootRegister).
   void Pushad();
   void Popad();
+  // Sets the stack as after performing Popad, without actually loading the
+  // registers.
+  void Dropad();

   // Compare object type for heap object.
// Always use unsigned comparisons: above and below, not less and greater.
@@ -812,6 +820,9 @@
   // Call a runtime routine.
   void CallRuntime(Runtime::Function* f, int num_arguments);

+  // Call a runtime function and save the value of XMM registers.
+  void CallRuntimeSaveDoubles(Runtime::FunctionId id);
+
   // Call a runtime function, returning the CodeStub object called.
   // Try to generate the stub code if necessary.  Do not perform a GC
   // but instead return a retry after GC failure.
@@ -931,6 +942,9 @@
   bool allow_stub_calls() { return allow_stub_calls_; }

  private:
+  // Order general registers are pushed by Pushad.
+  // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
+  static int kSafepointPushRegisterIndices[Register::kNumRegisters];
   bool generating_stub_;
   bool allow_stub_calls_;

@@ -961,7 +975,7 @@

// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
   // accessible via StackSpaceOperand.
-  void EnterExitFrameEpilogue(int arg_stack_space);
+  void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);

   void LeaveExitFrameEpilogue();

=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-x64.cc Tue Dec 7 03:01:02 2010 +++ /branches/bleeding_edge/test/cctest/test-assembler-x64.cc Tue Jan 25 03:30:47 2011
@@ -48,6 +48,12 @@
 using v8::internal::rdx;
 using v8::internal::rbp;
 using v8::internal::rsp;
+using v8::internal::r8;
+using v8::internal::r9;
+using v8::internal::r12;
+using v8::internal::r13;
+using v8::internal::times_1;
+
 using v8::internal::FUNCTION_CAST;
 using v8::internal::CodeDesc;
 using v8::internal::less_equal;
@@ -288,5 +294,48 @@
   int result =  FUNCTION_CAST<F0>(buffer)();
   CHECK_EQ(1, result);
 }
+
+
+TEST(OperandRegisterDependency) {
+  int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
+  for (int i = 0; i < 4; i++) {
+    int offset = offsets[i];
+    CHECK(Operand(rax, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
+    CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
+
+    CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
+    CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
+
+    CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
+    CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
+    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
+    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
+    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
+    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
+
+    CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
+    CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rsp, offset).AddressUsesRegister(r12));
+
+    CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
+    CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
+
+    CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
+    CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
+    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
+    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
+    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
+
+    CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
+    CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
+    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
+    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r12));
+    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
+  }
+}

 #undef __

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

Reply via email to