From: gergely@homejinni.com Date: Sun, 1 Sep 2013 17:22:08 +0000 (+0000) Subject: MIPS: Support for DoubleToIStub (truncating). X-Git-Tag: upstream/4.7.83~12721 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a8e5dd516959c54cbe071a179ceeb4b390ab8caa;p=platform%2Fupstream%2Fv8.git MIPS: Support for DoubleToIStub (truncating). Port r16322 (8a03070) Original commit message: Added support for truncating DoubleToIStub and reorganize the macro-assembler dToI operations to do the fast-path inline and the slow path by calling the stub. BUG= R=gergely@homejinni.com Review URL: https://codereview.chromium.org/23694014 Patch from Balazs Kilvady . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16461 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 8b0fdb2..93f3fde 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -521,6 +521,64 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { } +void DoubleToIStub::Generate(MacroAssembler* masm) { + Label out_of_range, only_low, negate, done; + Register input_reg = source(); + Register result_reg = destination(); + + int double_offset = offset(); + // Account for saved regs if input is sp. + if (input_reg.is(sp)) double_offset += 3 * kPointerSize; + + Register scratch = + GetRegisterThatIsNotOneOf(input_reg, result_reg); + Register scratch2 = + GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch); + Register scratch3 = + GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch2); + DoubleRegister double_scratch = kLithiumScratchDouble.low(); + DoubleRegister double_input = f12; + + __ Push(scratch, scratch2, scratch3); + + __ ldc1(double_input, MemOperand(input_reg, double_offset)); + + if (!skip_fastpath()) { + // Clear cumulative exception flags and save the FCSR. + __ cfc1(scratch2, FCSR); + __ ctc1(zero_reg, FCSR); + // Try a conversion to a signed integer. + __ trunc_w_d(double_scratch, double_input); + __ mfc1(result_reg, double_scratch); + // Retrieve and restore the FCSR. + __ cfc1(scratch, FCSR); + __ ctc1(scratch2, FCSR); + // Check for overflow and NaNs. + __ And( + scratch, scratch, + kFCSROverflowFlagMask | kFCSRUnderflowFlagMask + | kFCSRInvalidOpFlagMask); + // If we had no exceptions we are done. + __ Branch(&done, eq, scratch, Operand(zero_reg)); + } + + // Load the double value and perform a manual truncation. + Register input_high = scratch2; + Register input_low = scratch3; + __ Move(input_low, input_high, double_input); + + __ EmitOutOfInt32RangeTruncate(result_reg, + input_high, + input_low, + scratch); + + __ bind(&done); + + __ Pop(scratch, scratch2, scratch3); + __ Ret(); +} + + bool WriteInt32ToHeapNumberStub::IsPregenerated() { // These variants are compiled ahead of time. See next method. if (the_int_.is(a1) && @@ -1532,12 +1590,12 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, __ SmiUntag(a2, right); } else { // Convert operands to 32-bit integers. Right in a2 and left in a3. - __ ConvertNumberToInt32( + __ TruncateNumberToI( left, a3, heap_number_map, - scratch1, scratch2, scratch3, f0, not_numbers); - __ ConvertNumberToInt32( + scratch1, scratch2, scratch3, not_numbers); + __ TruncateNumberToI( right, a2, heap_number_map, - scratch1, scratch2, scratch3, f0, not_numbers); + scratch1, scratch2, scratch3, not_numbers); } Label result_not_a_smi; switch (op) { diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h index 221b344..1800178 100644 --- a/src/mips/code-stubs-mips.h +++ b/src/mips/code-stubs-mips.h @@ -391,7 +391,7 @@ class RecordWriteStub: public PlatformCodeStub { address_(address), scratch0_(scratch0) { ASSERT(!AreAliased(scratch0, object, address, no_reg)); - scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_); + scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_); } void Save(MacroAssembler* masm) { @@ -434,19 +434,6 @@ class RecordWriteStub: public PlatformCodeStub { Register scratch0_; Register scratch1_; - Register GetRegThatIsNotOneOf(Register r1, - Register r2, - Register r3) { - for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { - Register candidate = Register::FromAllocationIndex(i); - if (candidate.is(r1)) continue; - if (candidate.is(r2)) continue; - if (candidate.is(r3)) continue; - return candidate; - } - UNREACHABLE(); - return no_reg; - } friend class RecordWriteStub; }; diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 11aac0b..e7f05a6 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -4853,7 +4853,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->temp()); DoubleRegister double_scratch = double_scratch0(); - DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3()); + DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp2()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); @@ -4868,11 +4868,6 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // of the if. if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - FPURegister single_scratch = double_scratch.low(); - ASSERT(!scratch3.is(input_reg) && - !scratch3.is(scratch1) && - !scratch3.is(scratch2)); // Performs a truncating conversion of a floating point number as used by // the JS bitwise operations. Label heap_number; @@ -4886,14 +4881,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ Branch(&done); __ bind(&heap_number); - __ ldc1(double_scratch2, - FieldMemOperand(input_reg, HeapNumber::kValueOffset)); - __ EmitECMATruncate(input_reg, - double_scratch2, - single_scratch, - scratch1, - scratch2, - scratch3); + __ mov(scratch2, input_reg); + __ TruncateHeapNumberToI(input_reg, scratch2); } else { // Deoptimize if we don't have a heap number. DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at)); @@ -4980,20 +4969,12 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->temp()); DoubleRegister double_input = ToDoubleRegister(instr->value()); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - FPURegister single_scratch = double_scratch0().low(); - __ EmitECMATruncate(result_reg, - double_input, - single_scratch, - scratch1, - scratch2, - scratch3); + __ TruncateDoubleToI(result_reg, double_input); } else { - Register except_flag = scratch2; + Register except_flag = LCodeGen::scratch1(); __ EmitFPUTruncate(kRoundToMinusInf, result_reg, @@ -5020,21 +5001,13 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { Register result_reg = ToRegister(instr->result()); - Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->temp()); + Register scratch1 = LCodeGen::scratch0(); DoubleRegister double_input = ToDoubleRegister(instr->value()); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - FPURegister single_scratch = double_scratch0().low(); - __ EmitECMATruncate(result_reg, - double_input, - single_scratch, - scratch1, - scratch2, - scratch3); + __ TruncateDoubleToI(result_reg, double_input); } else { - Register except_flag = scratch2; + Register except_flag = LCodeGen::scratch1(); __ EmitFPUTruncate(kRoundToMinusInf, result_reg, diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index b8775c3..695a058 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1844,13 +1844,10 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { } else { value = UseRegister(val); LOperand* temp1 = TempRegister(); - LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() - : NULL; - LOperand* temp3 = FixedTemp(f22); + LOperand* temp2 = FixedTemp(f22); res = DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, - temp2, - temp3)); + temp2)); res = AssignEnvironment(res); } return res; @@ -1870,14 +1867,12 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { return AssignPointerMap(result); } else if (to.IsSmi()) { LOperand* value = UseRegister(instr->value()); - return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToSmi(value, - TempRegister(), TempRegister()))); + return AssignEnvironment( + DefineAsRegister(new(zone()) LDoubleToSmi(value))); } else { ASSERT(to.IsInteger32()); LOperand* value = UseRegister(instr->value()); - LOperand* temp1 = TempRegister(); - LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; - LDoubleToI* res = new(zone()) LDoubleToI(value, temp1, temp2); + LDoubleToI* res = new(zone()) LDoubleToI(value); return AssignEnvironment(DefineAsRegister(res)); } } else if (from.IsInteger32()) { diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index dfdf63c..584682c 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -2041,17 +2041,13 @@ class LNumberTagD V8_FINAL : public LTemplateInstruction<1, 1, 2> { }; -class LDoubleToSmi V8_FINAL : public LTemplateInstruction<1, 1, 2> { +class LDoubleToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: - LDoubleToSmi(LOperand* value, LOperand* temp, LOperand* temp2) { + explicit LDoubleToSmi(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; } LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -2061,17 +2057,13 @@ class LDoubleToSmi V8_FINAL : public LTemplateInstruction<1, 1, 2> { // Sometimes truncating conversion from a tagged value to an int32. -class LDoubleToI V8_FINAL : public LTemplateInstruction<1, 1, 2> { +class LDoubleToI V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: - LDoubleToI(LOperand* value, LOperand* temp, LOperand* temp2) { + explicit LDoubleToI(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; } LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -2081,22 +2073,19 @@ class LDoubleToI V8_FINAL : public LTemplateInstruction<1, 1, 2> { // Truncating conversion from a tagged value to an int32. -class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 3> { +class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 2> { public: LTaggedToI(LOperand* value, LOperand* temp, - LOperand* temp2, - LOperand* temp3) { + LOperand* temp2) { inputs_[0] = value; temps_[0] = temp; temps_[1] = temp2; - temps_[2] = temp3; } LOperand* value() { return inputs_[0]; } LOperand* temp() { return temps_[0]; } LOperand* temp2() { return temps_[1]; } - LOperand* temp3() { return temps_[2]; } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 2738900..cd1d38e 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -1498,22 +1498,12 @@ void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, } -void MacroAssembler::EmitECMATruncate(Register result, - FPURegister double_input, - FPURegister single_scratch, - Register scratch, - Register scratch2, - Register scratch3) { - ASSERT(!scratch2.is(result)); - ASSERT(!scratch3.is(result)); - ASSERT(!scratch3.is(scratch2)); - ASSERT(!scratch.is(result) && - !scratch.is(scratch2) && - !scratch.is(scratch3)); - ASSERT(!single_scratch.is(double_input)); - - Label done; - Label manual; +void MacroAssembler::TryInlineTruncateDoubleToI(Register result, + DoubleRegister double_input, + Label* done) { + DoubleRegister single_scratch = kLithiumScratchDouble.low(); + Register scratch = at; + Register scratch2 = t9; // Clear cumulative exception flags and save the FCSR. cfc1(scratch2, FCSR); @@ -1529,16 +1519,83 @@ void MacroAssembler::EmitECMATruncate(Register result, scratch, kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); // If we had no exceptions we are done. - Branch(&done, eq, scratch, Operand(zero_reg)); + Branch(done, eq, scratch, Operand(zero_reg)); +} + + +void MacroAssembler::TruncateDoubleToI(Register result, + DoubleRegister double_input) { + Label done; + + TryInlineTruncateDoubleToI(result, double_input, &done); + + // If we fell through then inline version didn't succeed - call stub instead. + push(ra); + Subu(sp, sp, Operand(kDoubleSize)); // Put input on stack. + sdc1(double_input, MemOperand(sp, 0)); + + DoubleToIStub stub(sp, result, 0, true, true); + CallStub(&stub); + + Addu(sp, sp, Operand(kDoubleSize)); + pop(ra); + + bind(&done); +} + - // Load the double value and perform a manual truncation. - Register input_high = scratch2; - Register input_low = scratch3; - Move(input_low, input_high, double_input); +void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) { + Label done; + DoubleRegister double_scratch = f12; + ASSERT(!result.is(object)); + + ldc1(double_scratch, + MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag)); + TryInlineTruncateDoubleToI(result, double_scratch, &done); + + // If we fell through then inline version didn't succeed - call stub instead. + push(ra); + DoubleToIStub stub(object, + result, + HeapNumber::kValueOffset - kHeapObjectTag, + true, + true); + CallStub(&stub); + pop(ra); + + bind(&done); +} + + +void MacroAssembler::TruncateNumberToI(Register object, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Register scratch3, + Label* not_number) { + Label done; + Label not_in_int32_range; + DoubleRegister double_scratch = f12; + + UntagAndJumpIfSmi(result, object, &done); + JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); + ConvertToInt32(object, + result, + scratch1, + scratch2, + double_scratch, + ¬_in_int32_range); + jmp(&done); + + bind(¬_in_int32_range); + lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); + lw(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset)); EmitOutOfInt32RangeTruncate(result, - input_high, - input_low, - scratch); + scratch1, + scratch2, + scratch3); + bind(&done); } @@ -4577,40 +4634,6 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, } -void MacroAssembler::ConvertNumberToInt32(Register object, - Register dst, - Register heap_number_map, - Register scratch1, - Register scratch2, - Register scratch3, - FPURegister double_scratch, - Label* not_number) { - Label done; - Label not_in_int32_range; - - UntagAndJumpIfSmi(dst, object, &done); - JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); - ConvertToInt32(object, - dst, - scratch1, - scratch2, - double_scratch, - ¬_in_int32_range); - jmp(&done); - - bind(¬_in_int32_range); - lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); - lw(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset)); - - EmitOutOfInt32RangeTruncate(dst, - scratch1, - scratch2, - scratch3); - - bind(&done); -} - - void MacroAssembler::LoadNumber(Register object, FPURegister dst, Register heap_number_map, @@ -5642,6 +5665,30 @@ void MacroAssembler::TestJSArrayForAllocationMemento( } +Register GetRegisterThatIsNotOneOf(Register reg1, + Register reg2, + Register reg3, + Register reg4, + Register reg5, + Register reg6) { + RegList regs = 0; + if (reg1.is_valid()) regs |= reg1.bit(); + if (reg2.is_valid()) regs |= reg2.bit(); + if (reg3.is_valid()) regs |= reg3.bit(); + if (reg4.is_valid()) regs |= reg4.bit(); + if (reg5.is_valid()) regs |= reg5.bit(); + if (reg6.is_valid()) regs |= reg6.bit(); + + for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { + Register candidate = Register::FromAllocationIndex(i); + if (regs & candidate.bit()) continue; + return candidate; + } + UNREACHABLE(); + return no_reg; +} + + bool AreAliased(Register r1, Register r2, Register r3, Register r4) { if (r1.is(r2)) return true; if (r1.is(r3)) return true; diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index 26bed68..8f0b3b1 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -90,6 +90,13 @@ enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved }; +Register GetRegisterThatIsNotOneOf(Register reg1, + Register reg2 = no_reg, + Register reg3 = no_reg, + Register reg4 = no_reg, + Register reg5 = no_reg, + Register reg6 = no_reg); + bool AreAliased(Register r1, Register r2, Register r3, Register r4); @@ -788,26 +795,36 @@ class MacroAssembler: public Assembler { Register scratch); // Performs a truncating conversion of a floating point number as used by + // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it + // succeeds, otherwise falls through if result is saturated. On return + // 'result' either holds answer, or is clobbered on fall through. + // + // Only public for the test code in test-code-stubs-arm.cc. + void TryInlineTruncateDoubleToI(Register result, + DoubleRegister input, + Label* done); + + // Performs a truncating conversion of a floating point number as used by // the JS bitwise operations. See ECMA-262 9.5: ToInt32. - // Exits with 'result' holding the answer and all other registers clobbered. - void EmitECMATruncate(Register result, - FPURegister double_input, - FPURegister single_scratch, - Register scratch, - Register scratch2, - Register scratch3); + // Exits with 'result' holding the answer. + void TruncateDoubleToI(Register result, DoubleRegister double_input); + + // Performs a truncating conversion of a heap number as used by + // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' + // must be different registers. Exits with 'result' holding the answer. + void TruncateHeapNumberToI(Register result, Register object); // Converts the smi or heap number in object to an int32 using the rules // for ToInt32 as described in ECMAScript 9.5.: the value is truncated - // and brought into the range -2^31 .. +2^31 - 1. - void ConvertNumberToInt32(Register object, - Register dst, - Register heap_number_map, - Register scratch1, - Register scratch2, - Register scratch3, - FPURegister double_scratch, - Label* not_int32); + // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be + // different registers. + void TruncateNumberToI(Register object, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Register scratch3, + Label* not_int32); // Loads the number from object into dst register. // If |object| is neither smi nor heap number, |not_number| is jumped to