Chromium Code Reviews| Index: src/arm/lithium-codegen-arm.cc |
| diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc |
| index 6ff4cab9ac538951e946b95ebfa111b85d1f6f2d..9a02a07460d28cc3202ea71d6bc2f7b89317f396 100644 |
| --- a/src/arm/lithium-codegen-arm.cc |
| +++ b/src/arm/lithium-codegen-arm.cc |
| @@ -65,8 +65,6 @@ bool LCodeGen::GenerateCode() { |
| HPhase phase("Z_Code generation", chunk()); |
| ASSERT(is_unused()); |
| status_ = GENERATING; |
| - CpuFeatures::Scope scope1(VFP3); |
| - CpuFeatures::Scope scope2(ARMv7); |
| CodeStub::GenerateFPStubs(); |
| @@ -118,44 +116,49 @@ void LCodeGen::Comment(const char* format, ...) { |
| bool LCodeGen::GeneratePrologue() { |
| ASSERT(is_generating()); |
| - ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| + if (info()->IsOptimizing()) { |
| + ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| #ifdef DEBUG |
| - if (strlen(FLAG_stop_at) > 0 && |
| - info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| - __ stop("stop_at"); |
| - } |
| + if (strlen(FLAG_stop_at) > 0 && |
| + info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| + __ stop("stop_at"); |
| + } |
| #endif |
| - // r1: Callee's JS function. |
| - // cp: Callee's context. |
| - // fp: Caller's frame pointer. |
| - // lr: Caller's pc. |
| - |
| - // Strict mode functions and builtins need to replace the receiver |
| - // with undefined when called as functions (without an explicit |
| - // receiver object). r5 is zero for method calls and non-zero for |
| - // function calls. |
| - if (!info_->is_classic_mode() || info_->is_native()) { |
| - Label ok; |
| - Label begin; |
| - __ bind(&begin); |
| - __ cmp(r5, Operand(0)); |
| - __ b(eq, &ok); |
| - int receiver_offset = scope()->num_parameters() * kPointerSize; |
| - __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| - __ str(r2, MemOperand(sp, receiver_offset)); |
| - __ bind(&ok); |
| - ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos()); |
| - } |
| - |
| - // The following three instructions must remain together and unmodified for |
| - // code aging to work properly. |
| - __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| - // Add unused load of ip to ensure prologue sequence is identical for |
| - // full-codegen and lithium-codegen. |
| - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| - __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. |
| + // r1: Callee's JS function. |
| + // cp: Callee's context. |
| + // fp: Caller's frame pointer. |
| + // lr: Caller's pc. |
| + |
| + // Strict mode functions and builtins need to replace the receiver |
| + // with undefined when called as functions (without an explicit |
| + // receiver object). r5 is zero for method calls and non-zero for |
| + // function calls. |
| + if (!info_->is_classic_mode() || info_->is_native()) { |
| + Label ok; |
| + Label begin; |
| + __ bind(&begin); |
| + __ cmp(r5, Operand(0)); |
| + __ b(eq, &ok); |
| + int receiver_offset = scope()->num_parameters() * kPointerSize; |
| + __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| + __ str(r2, MemOperand(sp, receiver_offset)); |
| + __ bind(&ok); |
| + ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos()); |
| + } |
| + } |
| + |
| + if (NeedsEagerFrame()) { |
| + // The following three instructions must remain together and unmodified for |
| + // code aging to work properly. |
| + __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| + // Add unused load of ip to ensure prologue sequence is identical for |
| + // full-codegen and lithium-codegen. |
| + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| + __ add(fp, sp, Operand(2 * kPointerSize)); |
| + frame_is_built_ = true; |
| + } |
| // Reserve space for the stack slots needed by the code. |
| int slots = GetStackSlotCount(); |
| @@ -174,7 +177,7 @@ bool LCodeGen::GeneratePrologue() { |
| } |
| // Possibly allocate a local context. |
| - int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| + int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| if (heap_slots > 0) { |
| Comment(";;; Allocate local context"); |
| // Argument to NewContext is the function, which is in r1. |
| @@ -210,7 +213,7 @@ bool LCodeGen::GeneratePrologue() { |
| } |
| // Trace the call. |
| - if (FLAG_trace) { |
| + if (FLAG_trace && info()->IsOptimizing()) { |
| __ CallRuntime(Runtime::kTraceEnter, 0); |
| } |
| return !is_aborted(); |
| @@ -268,10 +271,31 @@ bool LCodeGen::GenerateDeferredCode() { |
| for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| LDeferredCode* code = deferred_[i]; |
| __ bind(code->entry()); |
| + if (NeedsDeferredFrame()) { |
| + Comment(";;; Deferred build frame", |
| + code->instruction_index(), |
| + code->instr()->Mnemonic()); |
| + ASSERT(!frame_is_built_); |
| + ASSERT(info()->IsStub()); |
| + frame_is_built_ = true; |
| + __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| + __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| + __ push(scratch0()); |
| + __ add(fp, sp, Operand(2 * kPointerSize)); |
| + } |
| Comment(";;; Deferred code @%d: %s.", |
| code->instruction_index(), |
| code->instr()->Mnemonic()); |
| code->Generate(); |
| + if (NeedsDeferredFrame()) { |
| + Comment(";;; Deferred destory frame", |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: "destroy"
danno
2012/11/30 16:23:24
Done. But destroy is so final, so... depressing. "
|
| + code->instruction_index(), |
| + code->instr()->Mnemonic()); |
| + ASSERT(frame_is_built_); |
| + __ pop(ip); |
| + __ ldm(ia_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| + frame_is_built_ = false; |
| + } |
| __ jmp(code->exit()); |
| } |
| } |
| @@ -285,7 +309,7 @@ bool LCodeGen::GenerateDeferredCode() { |
| bool LCodeGen::GenerateDeoptJumpTable() { |
| - // Check that the jump table is accessible from everywhere in the function |
| + // Check that the jump table is acvcessible from everywhere in the function |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: I prefer the old version.
danno
2012/11/30 16:23:24
Done.
|
| // code, i.e. that offsets to the table can be encoded in the 24bit signed |
| // immediate of a branch instruction. |
| // To simplify we consider the code size from the first instruction to the |
| @@ -293,24 +317,70 @@ bool LCodeGen::GenerateDeoptJumpTable() { |
| // Each entry in the jump table generates one instruction and inlines one |
| // 32bit data after it. |
| if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) + |
| - deopt_jump_table_.length() * 2)) { |
| + deopt_jump_table_.length() * 7)) { |
| Abort("Generated code is too large"); |
| } |
| - // Block the constant pool emission during the jump table emission. |
| - __ BlockConstPoolFor(deopt_jump_table_.length()); |
| __ RecordComment("[ Deoptimisation jump table"); |
| Label table_start; |
| __ bind(&table_start); |
| + Label needs_frame_not_call; |
| + bool has_generated_needs_frame_not_call = false; |
|
Jakob Kummerow
2012/11/28 16:28:22
see comments on ia32 version. In short:
1) if you
danno
2012/11/30 16:23:24
Done.
|
| + Label needs_frame_is_call; |
| + bool has_generated_needs_frame_is_call = false; |
| for (int i = 0; i < deopt_jump_table_.length(); i++) { |
| __ bind(&deopt_jump_table_[i].label); |
| - __ ldr(pc, MemOperand(pc, Assembler::kInstrSize - Assembler::kPcLoadDelta)); |
| - __ dd(reinterpret_cast<uint32_t>(deopt_jump_table_[i].address)); |
| + Address entry = deopt_jump_table_[i].address; |
| + if (deopt_jump_table_[i].needs_frame) { |
| + __ mov(ip, Operand(ExternalReference::ForDeoptEntry(entry))); |
| + if (deopt_jump_table_[i].is_lazy_deopt) { |
| + if (!has_generated_needs_frame_is_call) { |
| + has_generated_needs_frame_is_call = true; |
| + __ bind(&needs_frame_is_call); |
| + __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| + // If there is not frame, we don't have access to the JSFunction that |
| + // needs to be put into the frame. |
| + ASSERT(info()->IsStub()); |
| + __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| + __ push(scratch0()); |
| + __ add(fp, sp, Operand(2 * kPointerSize)); |
| + __ mov(lr, Operand(pc), LeaveCC, al); |
| + __ mov(pc, ip); |
| + } else { |
| + __ b(&needs_frame_is_call); |
| + } |
| + } else { |
| + if (!has_generated_needs_frame_not_call) { |
| + has_generated_needs_frame_not_call = true; |
| + __ bind(&needs_frame_not_call); |
| + __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| + // If there is not frame, we don't have access to the JSFunction that |
| + // needs to be put into the frame. |
| + ASSERT(info()->IsStub()); |
| + __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| + __ push(scratch0()); |
| + __ add(fp, sp, Operand(2 * kPointerSize)); |
| + __ mov(pc, ip); |
| + } else { |
| + __ b(&needs_frame_not_call); |
| + } |
| + } |
| + } else { |
| + if (deopt_jump_table_[i].is_lazy_deopt) { |
| + __ mov(lr, Operand(pc), LeaveCC, al); |
| + __ mov(pc, Operand(ExternalReference::ForDeoptEntry(entry))); |
| + } else { |
| + __ mov(pc, Operand(ExternalReference::ForDeoptEntry(entry))); |
| + } |
| + } |
| + masm()->CheckConstPool(false, false); |
| } |
| - ASSERT(masm()->InstructionsGeneratedSince(&table_start) == |
| - deopt_jump_table_.length() * 2); |
| __ RecordComment("]"); |
| + // Force constant pool emission at the end of the deopt jump table to make |
| + // sure that no constant pools are emitted after. |
| + masm()->CheckConstPool(true, false); |
| + |
| // The deoptimization jump table is the last part of the instruction |
| // sequence. Mark the generated code as done unless we bailed out. |
| if (!is_aborted()) status_ = DONE; |
| @@ -330,8 +400,8 @@ Register LCodeGen::ToRegister(int index) const { |
| } |
| -DoubleRegister LCodeGen::ToDoubleRegister(int index) const { |
| - return DoubleRegister::FromAllocationIndex(index); |
| +DwVfpRegister LCodeGen::ToDoubleRegister(int index) const { |
| + return DwVfpRegister::FromAllocationIndex(index); |
| } |
| @@ -372,15 +442,15 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { |
| } |
| -DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const { |
| +DwVfpRegister LCodeGen::ToDoubleRegister(LOperand* op) const { |
| ASSERT(op->IsDoubleRegister()); |
| return ToDoubleRegister(op->index()); |
| } |
| -DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, |
| - SwVfpRegister flt_scratch, |
| - DoubleRegister dbl_scratch) { |
| +DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, |
| + SwVfpRegister flt_scratch, |
| + DwVfpRegister dbl_scratch) { |
| if (op->IsDoubleRegister()) { |
| return ToDoubleRegister(op->index()); |
| } else if (op->IsConstantOperand()) { |
| @@ -516,7 +586,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
| translation, |
| arguments_index, |
| arguments_count); |
| - int closure_id = *info()->closure() != *environment->closure() |
| + bool has_closure_id = !info()->closure().is_null() && |
| + *info()->closure() != *environment->closure(); |
| + int closure_id = has_closure_id |
| ? DefineDeoptimizationLiteral(environment->closure()) |
| : Translation::kSelfLiteralId; |
| @@ -537,6 +609,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
| ASSERT(height == 0); |
| translation->BeginSetterStubFrame(closure_id); |
| break; |
| + case STUB: |
| + translation->BeginCompiledStubFrame(); |
| + break; |
| case ARGUMENTS_ADAPTOR: |
| translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
| break; |
| @@ -732,7 +807,11 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
| RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| ASSERT(environment->HasBeenRegistered()); |
| int id = environment->deoptimization_index(); |
| - Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); |
| + |
| + Deoptimizer::BailoutType bailout_type = info()->IsStub() |
| + ? Deoptimizer::LAZY |
| + : Deoptimizer::EAGER; |
| + Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type); |
| if (entry == NULL) { |
| Abort("bailout was not prepared"); |
| return; |
| @@ -748,14 +827,19 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
| if (FLAG_trap_on_deopt) __ stop("trap_on_deopt", cc); |
| - if (cc == al) { |
| + bool needs_lazy_deopt = info()->IsStub(); |
| + ASSERT(info()->IsStub() || frame_is_built_); |
| + if (cc == al && !needs_lazy_deopt) { |
| __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| } else { |
| // We often have several deopts to the same entry, reuse the last |
| // jump entry if this is the case. |
| if (deopt_jump_table_.is_empty() || |
| - (deopt_jump_table_.last().address != entry)) { |
| - deopt_jump_table_.Add(JumpTableEntry(entry), zone()); |
| + (deopt_jump_table_.last().address != entry) || |
| + (deopt_jump_table_.last().is_lazy_deopt != needs_lazy_deopt) || |
| + (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { |
| + JumpTableEntry table_entry(entry, !frame_is_built_, needs_lazy_deopt); |
| + deopt_jump_table_.Add(table_entry, zone()); |
| } |
| __ b(cc, &deopt_jump_table_.last().label); |
| } |
| @@ -1364,6 +1448,8 @@ void LCodeGen::DoDeferredBinaryOpStub(LPointerMap* pointer_map, |
| LOperand* left_argument, |
| LOperand* right_argument, |
| Token::Value op) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed, as the Scope c'tor right below co
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope vfp_scope(VFP2); |
| Register left = ToRegister(left_argument); |
| Register right = ToRegister(right_argument); |
| @@ -1649,6 +1735,8 @@ void LCodeGen::DoConstantI(LConstantI* instr) { |
| void LCodeGen::DoConstantD(LConstantD* instr) { |
| ASSERT(instr->result()->IsDoubleRegister()); |
| DwVfpRegister result = ToDoubleRegister(instr->result()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| double v = instr->value(); |
| __ Vmov(result, v, scratch0()); |
| } |
| @@ -1817,9 +1905,11 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
| __ mov(result_reg, right_op, LeaveCC, NegateCondition(condition)); |
| } else { |
| ASSERT(instr->hydrogen()->representation().IsDouble()); |
| - DoubleRegister left_reg = ToDoubleRegister(left); |
| - DoubleRegister right_reg = ToDoubleRegister(right); |
| - DoubleRegister result_reg = ToDoubleRegister(instr->result()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister left_reg = ToDoubleRegister(left); |
| + DwVfpRegister right_reg = ToDoubleRegister(right); |
| + DwVfpRegister result_reg = ToDoubleRegister(instr->result()); |
| Label check_nan_left, check_zero, return_left, return_right, done; |
| __ VFPCompareAndSetFlags(left_reg, right_reg); |
| __ b(vs, &check_nan_left); |
| @@ -1862,9 +1952,11 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
| void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| - DoubleRegister left = ToDoubleRegister(instr->left()); |
| - DoubleRegister right = ToDoubleRegister(instr->right()); |
| - DoubleRegister result = ToDoubleRegister(instr->result()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister left = ToDoubleRegister(instr->left()); |
| + DwVfpRegister right = ToDoubleRegister(instr->right()); |
| + DwVfpRegister result = ToDoubleRegister(instr->result()); |
| switch (instr->op()) { |
| case Token::ADD: |
| __ vadd(result, left, right); |
| @@ -1952,7 +2044,9 @@ void LCodeGen::DoBranch(LBranch* instr) { |
| __ cmp(reg, Operand(0)); |
| EmitBranch(true_block, false_block, ne); |
| } else if (r.IsDouble()) { |
| - DoubleRegister reg = ToDoubleRegister(instr->value()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister reg = ToDoubleRegister(instr->value()); |
| Register scratch = scratch0(); |
| // Test the double value. Zero and NaN are false. |
| @@ -2037,8 +2131,9 @@ void LCodeGen::DoBranch(LBranch* instr) { |
| } |
| if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { |
| + CpuFeatures::Scope scope(VFP2); |
| // heap number -> false iff +0, -0, or NaN. |
| - DoubleRegister dbl_scratch = double_scratch0(); |
| + DwVfpRegister dbl_scratch = double_scratch0(); |
| Label not_heap_number; |
| __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| __ b(ne, ¬_heap_number); |
| @@ -2116,6 +2211,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| EmitGoto(next_block); |
| } else { |
| if (instr->is_double()) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| // Compare left and right operands as doubles and load the |
| // resulting flags into the normal status register. |
| __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right)); |
| @@ -2654,16 +2751,21 @@ void LCodeGen::DoCmpT(LCmpT* instr) { |
| void LCodeGen::DoReturn(LReturn* instr) { |
| - if (FLAG_trace) { |
| + if (FLAG_trace && info()->IsOptimizing()) { |
| // Push the return value on the stack as the parameter. |
| // Runtime::TraceExit returns its parameter in r0. |
| __ push(r0); |
| __ CallRuntime(Runtime::kTraceExit, 1); |
| } |
| - int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize; |
| - __ mov(sp, fp); |
| - __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| - __ add(sp, sp, Operand(sp_delta)); |
| + if (NeedsEagerFrame()) { |
| + int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize; |
| + __ mov(sp, fp); |
| + __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| + __ add(sp, sp, Operand(sp_delta)); |
| + } |
| + if (info()->IsStub()) { |
| + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| + } |
| __ Jump(lr); |
| } |
| @@ -3013,17 +3115,63 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
| if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
| elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
| - CpuFeatures::Scope scope(VFP3); |
| DwVfpRegister result = ToDoubleRegister(instr->result()); |
| Operand operand = key_is_constant |
| ? Operand(constant_key << element_size_shift) |
| : Operand(key, LSL, shift_size); |
| __ add(scratch0(), external_pointer, operand); |
| - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
| - __ vldr(result.low(), scratch0(), additional_offset); |
| - __ vcvt_f64_f32(result, result.low()); |
| - } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS |
| - __ vldr(result, scratch0(), additional_offset); |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
| + __ vldr(result.low(), scratch0(), additional_offset); |
| + __ vcvt_f64_f32(result, result.low()); |
| + } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS |
| + __ vldr(result, scratch0(), additional_offset); |
| + } |
| + } else { |
| + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
| + Register value = external_pointer; |
| + __ ldr(value, MemOperand(scratch0(), additional_offset)); |
| + __ and_(sfpd_lo, value, Operand(kBinary32MantissaMask)); |
| + |
| + __ mov(scratch0(), Operand(value, LSR, kBinary32MantissaBits)); |
| + __ and_(scratch0(), scratch0(), |
| + Operand(kBinary32ExponentMask >> kBinary32MantissaBits)); |
| + |
| + Label exponent_rebiased; |
| + __ teq(scratch0(), Operand(0x00)); |
| + __ b(eq, &exponent_rebiased); |
| + |
| + __ teq(scratch0(), Operand(0xff)); |
| + __ mov(scratch0(), Operand(0x7ff), LeaveCC, eq); |
| + __ b(eq, &exponent_rebiased); |
| + |
| + // Rebias exponent. |
| + __ add(scratch0(), |
| + scratch0(), |
| + Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias)); |
| + |
| + __ bind(&exponent_rebiased); |
| + __ and_(sfpd_hi, value, Operand(kBinary32SignMask)); |
| + __ orr(sfpd_hi, sfpd_hi, |
| + Operand(scratch0(), LSL, HeapNumber::kMantissaBitsInTopWord)); |
| + |
| + // Shift mantissa. |
| + static const int kMantissaShiftForHiWord = |
| + kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; |
| + |
| + static const int kMantissaShiftForLoWord = |
| + kBitsPerInt - kMantissaShiftForHiWord; |
| + |
| + __ orr(sfpd_hi, sfpd_hi, |
| + Operand(sfpd_lo, LSR, kMantissaShiftForHiWord)); |
| + __ mov(sfpd_lo, Operand(sfpd_lo, LSL, kMantissaShiftForLoWord)); |
| + |
| + } else { |
| + __ ldr(sfpd_lo, MemOperand(scratch0(), additional_offset)); |
| + __ ldr(sfpd_hi, MemOperand(scratch0(), |
| + additional_offset + kPointerSize)); |
| + } |
| } |
| } else { |
| Register result = ToRegister(instr->result()); |
| @@ -3092,23 +3240,28 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
| key = ToRegister(instr->key()); |
| } |
| - Operand operand = key_is_constant |
| - ? Operand(((constant_key + instr->additional_index()) << |
| - element_size_shift) + |
| - FixedDoubleArray::kHeaderSize - kHeapObjectTag) |
| - : Operand(key, LSL, shift_size); |
| - __ add(elements, elements, operand); |
| + int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) + |
| + ((constant_key + instr->additional_index()) << element_size_shift); |
| if (!key_is_constant) { |
| - __ add(elements, elements, |
| - Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) + |
| - (instr->additional_index() << element_size_shift))); |
| - } |
| - |
| - __ vldr(result, elements, 0); |
| - if (instr->hydrogen()->RequiresHoleCheck()) { |
| - __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); |
| - __ cmp(scratch, Operand(kHoleNanUpper32)); |
| - DeoptimizeIf(eq, instr->environment()); |
| + __ add(elements, elements, Operand(key, LSL, shift_size)); |
| + } |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + __ add(elements, elements, Operand(base_offset)); |
| + __ vldr(result, elements, 0); |
| + if (instr->hydrogen()->RequiresHoleCheck()) { |
| + __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); |
| + __ cmp(scratch, Operand(kHoleNanUpper32)); |
| + DeoptimizeIf(eq, instr->environment()); |
| + } |
| + } else { |
| + __ ldr(sfpd_hi, MemOperand(elements, base_offset + kPointerSize)); |
| + __ ldr(sfpd_lo, MemOperand(elements, base_offset)); |
| + if (instr->hydrogen()->RequiresHoleCheck()) { |
| + ASSERT(kPointerSize == sizeof(kHoleNanLower32)); |
| + __ cmp(sfpd_hi, Operand(kHoleNanUpper32)); |
| + DeoptimizeIf(eq, instr->environment()); |
| + } |
| } |
| } |
| @@ -3544,6 +3697,8 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| // Class for deferred case. |
| class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| public: |
| @@ -3580,7 +3735,9 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| - DoubleRegister input = ToDoubleRegister(instr->value()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister input = ToDoubleRegister(instr->value()); |
| Register result = ToRegister(instr->result()); |
| Register scratch = scratch0(); |
| @@ -3605,7 +3762,9 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
| - DoubleRegister input = ToDoubleRegister(instr->value()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister input = ToDoubleRegister(instr->value()); |
| Register result = ToRegister(instr->result()); |
| DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp()); |
| Register scratch = scratch0(); |
| @@ -3670,16 +3829,20 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
| void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
| - DoubleRegister input = ToDoubleRegister(instr->value()); |
| - DoubleRegister result = ToDoubleRegister(instr->result()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister input = ToDoubleRegister(instr->value()); |
| + DwVfpRegister result = ToDoubleRegister(instr->result()); |
| __ vsqrt(result, input); |
| } |
| void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| - DoubleRegister input = ToDoubleRegister(instr->value()); |
| - DoubleRegister result = ToDoubleRegister(instr->result()); |
| - DoubleRegister temp = ToDoubleRegister(instr->temp()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister input = ToDoubleRegister(instr->value()); |
| + DwVfpRegister result = ToDoubleRegister(instr->result()); |
| + DwVfpRegister temp = ToDoubleRegister(instr->temp()); |
| // Note that according to ECMA-262 15.8.2.13: |
| // Math.pow(-Infinity, 0.5) == Infinity |
| @@ -3698,6 +3861,8 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| void LCodeGen::DoPower(LPower* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Representation exponent_type = instr->hydrogen()->right()->representation(); |
| // Having marked this as a call, we can use any registers. |
| // Just make sure that the input/output registers are the expected ones. |
| @@ -3730,6 +3895,8 @@ void LCodeGen::DoPower(LPower* instr) { |
| void LCodeGen::DoRandom(LRandom* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| class DeferredDoRandom: public LDeferredCode { |
| public: |
| DeferredDoRandom(LCodeGen* codegen, LRandom* instr) |
| @@ -3808,10 +3975,12 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) { |
| void LCodeGen::DoMathExp(LMathExp* instr) { |
| - DoubleRegister input = ToDoubleRegister(instr->value()); |
| - DoubleRegister result = ToDoubleRegister(instr->result()); |
| - DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); |
| - DoubleRegister double_scratch2 = double_scratch0(); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| + DwVfpRegister input = ToDoubleRegister(instr->value()); |
| + DwVfpRegister result = ToDoubleRegister(instr->result()); |
| + DwVfpRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); |
| + DwVfpRegister double_scratch2 = double_scratch0(); |
| Register temp1 = ToRegister(instr->temp1()); |
| Register temp2 = ToRegister(instr->temp2()); |
| @@ -4097,6 +4266,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Register external_pointer = ToRegister(instr->elements()); |
| Register key = no_reg; |
| ElementsKind elements_kind = instr->elements_kind(); |
| @@ -4167,6 +4338,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
| void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| DwVfpRegister value = ToDoubleRegister(instr->value()); |
| Register elements = ToRegister(instr->elements()); |
| Register key = no_reg; |
| @@ -4443,6 +4616,8 @@ void LCodeGen::DoStringLength(LStringLength* instr) { |
| void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| LOperand* input = instr->value(); |
| ASSERT(input->IsRegister() || input->IsStackSlot()); |
| LOperand* output = instr->result(); |
| @@ -4460,6 +4635,8 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| LOperand* input = instr->value(); |
| LOperand* output = instr->result(); |
| @@ -4521,13 +4698,49 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { |
| } |
| +// Convert unsigned integer with specified number of leading zeroes in binary |
| +// representation to IEEE 754 double. |
| +// Integer to convert is passed in register hiword. |
| +// Resulting double is returned in registers hiword:loword. |
| +// This functions does not work correctly for 0. |
| +static void GenerateUInt2Double(MacroAssembler* masm, |
| + Register hiword, |
| + Register loword, |
| + Register scratch, |
| + int leading_zeroes) { |
| + const int meaningful_bits = kBitsPerInt - leading_zeroes - 1; |
| + const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits; |
| + |
| + const int mantissa_shift_for_hi_word = |
| + meaningful_bits - HeapNumber::kMantissaBitsInTopWord; |
| + const int mantissa_shift_for_lo_word = |
| + kBitsPerInt - mantissa_shift_for_hi_word; |
| + masm->mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift)); |
| + if (mantissa_shift_for_hi_word > 0) { |
| + masm->mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word)); |
| + masm->orr(hiword, scratch, |
| + Operand(hiword, LSR, mantissa_shift_for_hi_word)); |
| + } else { |
| + masm->mov(loword, Operand(0, RelocInfo::NONE)); |
| + masm->orr(hiword, scratch, |
| + Operand(hiword, LSL, mantissa_shift_for_hi_word)); |
|
Jakob Kummerow
2012/11/28 16:28:22
I can't convince myself that this is right. I thin
danno
2012/11/30 16:23:24
Done.
|
| + } |
| + |
| + // If least significant bit of biased exponent was not 1 it was corrupted |
| + // by most significant bit of mantissa so we should fix that. |
| + if (!(biased_exponent & 1)) { |
| + masm->bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift)); |
| + } |
| +} |
| + |
| + |
| void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
| LOperand* value, |
| IntegerSignedness signedness) { |
| Label slow; |
| Register src = ToRegister(value); |
| Register dst = ToRegister(instr->result()); |
| - DoubleRegister dbl_scratch = double_scratch0(); |
| + DwVfpRegister dbl_scratch = double_scratch0(); |
| SwVfpRegister flt_scratch = dbl_scratch.low(); |
| // Preserve the value of all registers. |
| @@ -4542,16 +4755,40 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
| __ SmiUntag(src, dst); |
| __ eor(src, src, Operand(0x80000000)); |
| } |
| - __ vmov(flt_scratch, src); |
| - __ vcvt_f64_s32(dbl_scratch, flt_scratch); |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + __ vmov(flt_scratch, src); |
| + __ vcvt_f64_s32(dbl_scratch, flt_scratch); |
| + } else { |
| + FloatingPointHelper::Destination dest = |
| + FloatingPointHelper::kCoreRegisters; |
| + FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, d0, |
| + sfpd_lo, sfpd_hi, |
| + scratch0(), s0); |
| + } |
| } else { |
| - __ vmov(flt_scratch, src); |
| - __ vcvt_f64_u32(dbl_scratch, flt_scratch); |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + __ vmov(flt_scratch, src); |
| + __ vcvt_f64_u32(dbl_scratch, flt_scratch); |
| + } else { |
| + Label no_leading_zero, done; |
| + __ tst(src, Operand(0x80000000)); |
| + __ b(ne, &no_leading_zero); |
| + |
| + // Integer has one leading zeros. |
| + GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 1); |
| + __ b(&done); |
| + |
| + __ bind(&no_leading_zero); |
| + GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 0); |
| + __ b(&done); |
| + } |
| } |
| if (FLAG_inline_new) { |
| - __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); |
| - __ AllocateHeapNumber(r5, r3, r4, r6, &slow, DONT_TAG_RESULT); |
| + __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex); |
| + __ AllocateHeapNumber(r5, r3, r4, scratch0(), &slow, DONT_TAG_RESULT); |
| __ Move(dst, r5); |
| __ b(&done); |
| } |
| @@ -4571,7 +4808,13 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
| // Done. Put the value in dbl_scratch into the value of the allocated heap |
| // number. |
| __ bind(&done); |
| - __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset); |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset); |
| + } else { |
| + __ str(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset)); |
| + __ str(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset)); |
| + } |
| __ add(dst, dst, Operand(kHeapObjectTag)); |
| __ StoreToSafepointRegisterSlot(dst, dst); |
| } |
| @@ -4588,7 +4831,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| LNumberTagD* instr_; |
| }; |
| - DoubleRegister input_reg = ToDoubleRegister(instr->value()); |
| + DwVfpRegister input_reg = ToDoubleRegister(instr->value()); |
| Register scratch = scratch0(); |
| Register reg = ToRegister(instr->result()); |
| Register temp1 = ToRegister(instr->temp()); |
| @@ -4604,7 +4847,13 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| __ jmp(deferred->entry()); |
| } |
| __ bind(deferred->exit()); |
| - __ vstr(input_reg, reg, HeapNumber::kValueOffset); |
| + if (CpuFeatures::IsSupported(VFP2)) { |
| + CpuFeatures::Scope scope(VFP2); |
| + __ vstr(input_reg, reg, HeapNumber::kValueOffset); |
| + } else { |
| + __ str(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset)); |
| + __ str(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize)); |
| + } |
| // Now that we have finished with the object's real address tag it |
| __ add(reg, reg, Operand(kHeapObjectTag)); |
| } |
| @@ -4645,13 +4894,15 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| void LCodeGen::EmitNumberUntagD(Register input_reg, |
| - DoubleRegister result_reg, |
| + DwVfpRegister result_reg, |
| bool deoptimize_on_undefined, |
| bool deoptimize_on_minus_zero, |
| LEnvironment* env) { |
| Register scratch = scratch0(); |
| SwVfpRegister flt_scratch = double_scratch0().low(); |
| ASSERT(!result_reg.is(double_scratch0())); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Label load_smi, heap_number, done; |
| @@ -4726,6 +4977,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
| __ cmp(scratch1, Operand(ip)); |
| if (instr->truncating()) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Register scratch3 = ToRegister(instr->temp2()); |
| SwVfpRegister single_scratch = double_scratch.low(); |
| ASSERT(!scratch3.is(input_reg) && |
| @@ -4817,7 +5070,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| ASSERT(result->IsDoubleRegister()); |
| Register input_reg = ToRegister(input); |
| - DoubleRegister result_reg = ToDoubleRegister(result); |
| + DwVfpRegister result_reg = ToDoubleRegister(result); |
| EmitNumberUntagD(input_reg, result_reg, |
| instr->hydrogen()->deoptimize_on_undefined(), |
| @@ -4966,14 +5219,18 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
| void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { |
| - DoubleRegister value_reg = ToDoubleRegister(instr->unclamped()); |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope vfp_scope(VFP2); |
| + DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped()); |
| Register result_reg = ToRegister(instr->result()); |
| - DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); |
| + DwVfpRegister temp_reg = ToDoubleRegister(instr->temp()); |
| __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); |
| } |
| void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Register unclamped_reg = ToRegister(instr->unclamped()); |
| Register result_reg = ToRegister(instr->result()); |
| __ ClampUint8(result_reg, unclamped_reg); |
| @@ -4981,10 +5238,12 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { |
| void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { |
| + ASSERT(CpuFeatures::IsSupported(VFP2)); |
|
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
| + CpuFeatures::Scope scope(VFP2); |
| Register scratch = scratch0(); |
| Register input_reg = ToRegister(instr->unclamped()); |
| Register result_reg = ToRegister(instr->result()); |
| - DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); |
| + DwVfpRegister temp_reg = ToDoubleRegister(instr->temp()); |
| Label is_smi, done, heap_number; |
| // Both smi and heap number cases are handled. |
| @@ -5561,6 +5820,7 @@ void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { |
| void LCodeGen::EnsureSpaceForLazyDeopt() { |
| + if (info()->IsStub()) return; |
| // Ensure that we have enough space after the previous lazy-bailout |
| // instruction for patching the code here. |
| int current_pc = masm()->pc_offset(); |