Commit 978ad03b authored by bmeurer's avatar bmeurer Committed by Commit bot

[crankshaft] Address the deoptimization loops of Math.floor, Math.round and Math.ceil.

Fix and re-enable the flexible representation for Math.floor (which is used to
implement Math.ceil) and Math.round, which allows Math.floor and Math.round to
return double results instead of int32, and therefore allows values outside
the int32 range, especially -0 is now a valid result, which doesn't deopt.

Also port this feature to x64 and ia32 when the CPU supports the SSE4.1
extension.

This addresses all the known deoptimization loops related to Math.round
in the Kraken benchmark suite, and seems to also address most of the
deoptimization loops related to Math.floor in the Oort Online benchmark.

Drive-by-fix: Import the regression tests for the broken HMathFloorOfDiv
optimization that caused the initial revert of the feature (for arm64 only
back then).

BUG=chromium:476477,v8:2890,v8:4059
R=jarin@chromium.org
LOG=n

Review URL: https://codereview.chromium.org/1841513003

Cr-Commit-Position: refs/heads/master@{#35094}
parent 816b4737
......@@ -1484,7 +1484,8 @@ HValue* HUnaryMathOperation::Canonicalize() {
val, representation(), false, false));
}
}
if (op() == kMathFloor && value()->IsDiv() && value()->HasOneUse()) {
if (op() == kMathFloor && representation().IsSmiOrInteger32() &&
value()->IsDiv() && value()->HasOneUse()) {
HDiv* hdiv = HDiv::cast(value());
HValue* left = hdiv->left();
......
......@@ -2499,10 +2499,10 @@ class HUnaryMathOperation final : public HTemplateInstruction<2> {
// Indicates if we support a double (and int32) output for Math.floor and
// Math.round.
bool SupportsFlexibleFloorAndRound() const {
#ifdef V8_TARGET_ARCH_ARM64
// TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
// fixed.
return false;
#if V8_TARGET_ARCH_ARM64
return true;
#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
return CpuFeatures::IsSupported(SSE4_1);
#else
return false;
#endif
......
......@@ -3177,8 +3177,14 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
}
}
void LCodeGen::DoMathFloorD(LMathFloorD* instr) {
XMMRegister output_reg = ToDoubleRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
CpuFeatureScope scope(masm(), SSE4_1);
__ roundsd(output_reg, input_reg, kRoundDown);
}
void LCodeGen::DoMathFloor(LMathFloor* instr) {
void LCodeGen::DoMathFloorI(LMathFloorI* instr) {
XMMRegister xmm_scratch = double_scratch0();
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
......@@ -3242,8 +3248,23 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
}
}
void LCodeGen::DoMathRoundD(LMathRoundD* instr) {
XMMRegister xmm_scratch = double_scratch0();
XMMRegister output_reg = ToDoubleRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
CpuFeatureScope scope(masm(), SSE4_1);
Label done;
__ roundsd(output_reg, input_reg, kRoundUp);
__ Move(xmm_scratch, -0.5);
__ addsd(xmm_scratch, output_reg);
__ ucomisd(xmm_scratch, input_reg);
__ j(below_equal, &done, Label::kNear);
__ Move(xmm_scratch, 1.0);
__ subsd(output_reg, xmm_scratch);
__ bind(&done);
}
void LCodeGen::DoMathRound(LMathRound* instr) {
void LCodeGen::DoMathRoundI(LMathRoundI* instr) {
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
XMMRegister xmm_scratch = double_scratch0();
......
......@@ -1161,22 +1161,33 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
}
}
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegisterAtStart(instr->value());
LMathFloor* result = new(zone()) LMathFloor(input);
return AssignEnvironment(DefineAsRegister(result));
if (instr->representation().IsInteger32()) {
LMathFloorI* result = new (zone()) LMathFloorI(input);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
} else {
DCHECK(instr->representation().IsDouble());
LMathFloorD* result = new (zone()) LMathFloorD(input);
return DefineAsRegister(result);
}
}
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp = FixedTemp(xmm4);
LMathRound* result = new(zone()) LMathRound(input, temp);
return AssignEnvironment(DefineAsRegister(result));
if (instr->representation().IsInteger32()) {
LOperand* temp = FixedTemp(xmm4);
LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
} else {
DCHECK(instr->representation().IsDouble());
LMathRoundD* result = new (zone()) LMathRoundD(input);
return DefineAsRegister(result);
}
}
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
LOperand* input = UseRegister(instr->value());
LMathFround* result = new (zone()) LMathFround(input);
......
......@@ -103,12 +103,14 @@ class LCodeGen;
V(MathAbs) \
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorD) \
V(MathFloorI) \
V(MathFround) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathRoundD) \
V(MathRoundI) \
V(MathSqrt) \
V(MaybeGrowElements) \
V(ModByConstI) \
......@@ -153,7 +155,6 @@ class LCodeGen;
V(UnknownOSRValue) \
V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
Opcode opcode() const final { return LInstruction::k##type; } \
void CompileToNative(LCodeGen* generator) final; \
......@@ -815,23 +816,43 @@ class LCompareNumericAndBranch final : public LControlInstruction<2, 0> {
void PrintDataTo(StringStream* stream) override;
};
// Math.floor with a double result.
class LMathFloorD final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFloorD(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloorD, "math-floor-d")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathFloor final : public LTemplateInstruction<1, 1, 0> {
// Math.floor with an integer result.
class LMathFloorI final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFloor(LOperand* value) {
inputs_[0] = value;
}
explicit LMathFloorI(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
DECLARE_CONCRETE_INSTRUCTION(MathFloorI, "math-floor-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
// Math.round with a double result.
class LMathRoundD final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathRoundD(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathRoundD, "math-round-d")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathRound final : public LTemplateInstruction<1, 1, 1> {
// Math.round with an integer result.
class LMathRoundI final : public LTemplateInstruction<1, 1, 1> {
public:
LMathRound(LOperand* value, LOperand* temp) {
LMathRoundI(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
......@@ -839,7 +860,7 @@ class LMathRound final : public LTemplateInstruction<1, 1, 1> {
LOperand* temp() { return temps_[0]; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
DECLARE_CONCRETE_INSTRUCTION(MathRoundI, "math-round-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
......
......@@ -3384,8 +3384,14 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
}
}
void LCodeGen::DoMathFloorD(LMathFloorD* instr) {
XMMRegister output_reg = ToDoubleRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
CpuFeatureScope scope(masm(), SSE4_1);
__ Roundsd(output_reg, input_reg, kRoundDown);
}
void LCodeGen::DoMathFloor(LMathFloor* instr) {
void LCodeGen::DoMathFloorI(LMathFloorI* instr) {
XMMRegister xmm_scratch = double_scratch0();
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
......@@ -3443,8 +3449,23 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
}
}
void LCodeGen::DoMathRoundD(LMathRoundD* instr) {
XMMRegister xmm_scratch = double_scratch0();
XMMRegister output_reg = ToDoubleRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
CpuFeatureScope scope(masm(), SSE4_1);
Label done;
__ Roundsd(output_reg, input_reg, kRoundUp);
__ Move(xmm_scratch, -0.5);
__ Addsd(xmm_scratch, output_reg);
__ Ucomisd(xmm_scratch, input_reg);
__ j(below_equal, &done, Label::kNear);
__ Move(xmm_scratch, 1.0);
__ Subsd(output_reg, xmm_scratch);
__ bind(&done);
}
void LCodeGen::DoMathRound(LMathRound* instr) {
void LCodeGen::DoMathRoundI(LMathRoundI* instr) {
const XMMRegister xmm_scratch = double_scratch0();
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
......
......@@ -1150,22 +1150,33 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
}
}
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegisterAtStart(instr->value());
LMathFloor* result = new(zone()) LMathFloor(input);
return AssignEnvironment(DefineAsRegister(result));
if (instr->representation().IsInteger32()) {
LMathFloorI* result = new (zone()) LMathFloorI(input);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
} else {
DCHECK(instr->representation().IsDouble());
LMathFloorD* result = new (zone()) LMathFloorD(input);
return DefineAsRegister(result);
}
}
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp = FixedTemp(xmm4);
LMathRound* result = new(zone()) LMathRound(input, temp);
return AssignEnvironment(DefineAsRegister(result));
if (instr->representation().IsInteger32()) {
LOperand* temp = FixedTemp(xmm4);
LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
} else {
DCHECK(instr->representation().IsDouble());
LMathRoundD* result = new (zone()) LMathRoundD(input);
return DefineAsRegister(result);
}
}
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
LOperand* input = UseRegister(instr->value());
LMathFround* result = new (zone()) LMathFround(input);
......
......@@ -99,12 +99,14 @@ class LCodeGen;
V(MathAbs) \
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorD) \
V(MathFloorI) \
V(MathFround) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathRoundD) \
V(MathRoundI) \
V(MathSqrt) \
V(MaybeGrowElements) \
V(ModByConstI) \
......@@ -149,7 +151,6 @@ class LCodeGen;
V(UnknownOSRValue) \
V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
Opcode opcode() const final { return LInstruction::k##type; } \
void CompileToNative(LCodeGen* generator) final; \
......@@ -812,23 +813,43 @@ class LCompareNumericAndBranch final : public LControlInstruction<2, 0> {
void PrintDataTo(StringStream* stream) override;
};
// Math.floor with a double result.
class LMathFloorD final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFloorD(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloorD, "math-floor-d")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathFloor final : public LTemplateInstruction<1, 1, 0> {
// Math.floor with an integer result.
class LMathFloorI final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFloor(LOperand* value) {
inputs_[0] = value;
}
explicit LMathFloorI(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
DECLARE_CONCRETE_INSTRUCTION(MathFloorI, "math-floor-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
// Math.round with a double result.
class LMathRoundD final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathRoundD(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathRoundD, "math-round-d")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathRound final : public LTemplateInstruction<1, 1, 1> {
// Math.round with an integer result.
class LMathRoundI final : public LTemplateInstruction<1, 1, 1> {
public:
LMathRound(LOperand* value, LOperand* temp) {
LMathRoundI(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
......@@ -836,7 +857,7 @@ class LMathRound final : public LTemplateInstruction<1, 1, 1> {
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
DECLARE_CONCRETE_INSTRUCTION(MathRoundI, "math-round-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var obj = {
_leftTime: 12345678,
_divider: function() {
var s = Math.floor(this._leftTime / 3600);
var e = Math.floor(s / 24);
var i = s % 24;
return {
s: s,
e: e,
i: i,
}
}
}
for (var i = 0; i < 1000; i++) {
obj._divider();
}
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function foo(x) {
var s = Math.floor(x / 3600);
Math.floor(s);
return s % 24;
}
foo(12345678);
foo(12345678);
%OptimizeFunctionOnNextCall(foo);
foo(12345678);
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