Commit a8e5dd51 authored by gergely@homejinni.com's avatar gergely@homejinni.com

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 <kilvadyb@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16461 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9615b8c4
......@@ -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) {
......
......@@ -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;
};
......
......@@ -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,
......
......@@ -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()) {
......
......@@ -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)
......
......@@ -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,
&not_in_int32_range);
jmp(&done);
bind(&not_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,
&not_in_int32_range);
jmp(&done);
bind(&not_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;
......
......@@ -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);
......@@ -787,27 +794,37 @@ class MacroAssembler: public Assembler {
Register input_low,
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment