Chromium Code Reviews| Index: src/x64/lithium-codegen-x64.cc |
| diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
| index dc988b1a652fa97bb2c97a2eb72888d0464518ec..9e3659dc48468c6a4a3d651b51e00cf3867f09af 100644 |
| --- a/src/x64/lithium-codegen-x64.cc |
| +++ b/src/x64/lithium-codegen-x64.cc |
| @@ -1146,7 +1146,17 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 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()); |
| + |
| + __ cmpq(left, right); |
| + __ movl(result, Immediate(Heap::kTrueValueRootIndex)); |
| + NearLabel load; |
| + __ j(equal, &load); |
| + __ movl(result, Immediate(Heap::kFalseValueRootIndex)); |
|
William Hesse
2011/01/24 16:25:27
Why not move True and False directly to the result
Lasse Reichstein
2011/01/25 10:13:27
The change to the code relative to ia32 is because
|
| + __ bind(&load); |
| + __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0)); |
| } |
| @@ -1162,7 +1172,45 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { |
| 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); |
| + } |
| } |
| @@ -1232,7 +1280,22 @@ Condition LCodeGen::EmitIsObject(Register input, |
| void LCodeGen::DoIsObject(LIsObject* instr) { |
| - Abort("Unimplemented: %s", "DoIsObject"); |
| + Register reg = ToRegister(instr->InputAt(0)); |
| + Register result = ToRegister(instr->result()); |
| + Register temp = ToRegister(instr->TempAt(0)); |
|
Rico
2011/01/25 07:13:28
No need to the temp register here (and in the lith
Lasse Reichstein
2011/01/25 10:13:27
Removed, and EmitIsObject rewritten to use only kS
|
| + Label is_false, is_true, done; |
| + |
| + Condition true_cond = EmitIsObject(reg, result, temp, &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); |
| } |
| @@ -1253,7 +1316,19 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 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)); |
|
William Hesse
2011/01/24 16:25:27
I think you need to multiply the kTrueValueRootInd
Lasse Reichstein
2011/01/25 10:13:27
Well spotted.
|
| } |
| @@ -1386,7 +1461,25 @@ void LCodeGen::EmitClassOfTest(Label* is_true, |
| 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)); |
|
Rico
2011/01/25 07:13:28
Use r10?
Lasse Reichstein
2011/01/25 10:13:27
This temp is needed in EmitClassOfTest. It uses th
|
| + 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); |
| } |
| @@ -1408,7 +1501,12 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 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); |
| } |
| @@ -1700,27 +1798,63 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 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)); |
|
William Hesse
2011/01/24 16:25:27
Operand cannot represent a register, so you need t
Lasse Reichstein
2011/01/25 10:13:27
We assert just above that input is not a register
|
| } |
| void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
| - Abort("Unimplemented: %s", "DoNumberTagI"); |
| -} |
| - |
| + LOperand* input = instr->InputAt(0); |
| + ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| + Register reg = ToRegister(input); |
| -void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
| - Abort("Unimplemented: %s", "DoDeferredNumberTagI"); |
| + __ 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()); |
| + __ Set(reg, 0); |
|
William Hesse
2011/01/24 16:25:27
How can 0 be a valid pointer? It isn't tagged.
Lasse Reichstein
2011/01/25 10:13:27
By chance, since it's the representation of Smi ze
|
| + |
| + __ 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); |
| } |
| @@ -1737,7 +1871,35 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 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(input_reg, input_reg); // Untag smi first. |
| + __ cvtlsi2sd(result_reg, input_reg); |
| + __ Integer32ToSmi(input_reg, input_reg); // Retag smi. |
|
William Hesse
2011/01/24 16:25:27
Can't we have some way to make this optional, or u
Lasse Reichstein
2011/01/25 10:13:27
Using kScratchRegister seems like the easy way. We
|
| + __ bind(&done); |
| } |