[DFG][FTL][B3] Support floor and ceil
https://bugs.webkit.org/show_bug.cgi?id=154683
Reviewed by Filip Pizlo.
Source/JavaScriptCore:
This patch implements and fixes the following things.
1. Implement Ceil and Floor in DFG, FTL and B3
x86 SSE 4.2 and ARM64 have round instructions that can directly perform Ceil or Floor.
This patch leverages this functionality. We introduce ArithFloor and ArithCeil.
During DFG phase, these nodes attempt to convert itself to Identity (in Fixup phase).
As the same to ArithRound, it tracks arith rounding mode.
And if these nodes are required to emit machine codes, we emit rounding machine code
if it is supported in the current machine. For example, in x86, we emit `round`.
This `Floor` functionality is nice for @toInteger in builtin.
That is used for Array.prototype.{forEach, map, every, some, reduce...}
And according to the benchmark results, Kraken audio-oscillator is slightly improved
due to its frequent Math.round and Math.floor calls.
2. Implement Floor in B3 and Air
As the same to Ceil in B3, we add a new B3 IR and Air opcode, Floor.
This Floor is leveraged to implement ArithFloor in DFG.
3. Fix ArithRound operation
Currently, we used cvtsd2si (in x86) to convert double value to int32.
And we also used this to implement Math.round, like, cvtsd2si(value + 0.5).
However, this implementation is not correct. Because cvtsd2si is not floor operation.
It is trucate operation. This is OK for positive numbers. But NG for negative numbers.
For example, the current implementation accidentally rounds `-0.6` to `-0.0`. This should be `-1.0`.
Using Ceil and Floor instructions, we implement correct ArithRound.
* assembler/MacroAssemblerARM.h:
(JSC::MacroAssemblerARM::supportsFloatingPointRounding):
(JSC::MacroAssemblerARM::ceilDouble):
(JSC::MacroAssemblerARM::floorDouble):
(JSC::MacroAssemblerARM::supportsFloatingPointCeil): Deleted.
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::supportsFloatingPointRounding):
(JSC::MacroAssemblerARM64::floorFloat):
(JSC::MacroAssemblerARM64::supportsFloatingPointCeil): Deleted.
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::supportsFloatingPointRounding):
(JSC::MacroAssemblerARMv7::ceilDouble):
(JSC::MacroAssemblerARMv7::floorDouble):
(JSC::MacroAssemblerARMv7::supportsFloatingPointCeil): Deleted.
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::ceilDouble):
(JSC::MacroAssemblerMIPS::floorDouble):
(JSC::MacroAssemblerMIPS::supportsFloatingPointRounding):
(JSC::MacroAssemblerMIPS::supportsFloatingPointCeil): Deleted.
* assembler/MacroAssemblerSH4.h:
(JSC::MacroAssemblerSH4::supportsFloatingPointRounding):
(JSC::MacroAssemblerSH4::ceilDouble):
(JSC::MacroAssemblerSH4::floorDouble):
(JSC::MacroAssemblerSH4::supportsFloatingPointCeil): Deleted.
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::floorDouble):
(JSC::MacroAssemblerX86Common::floorFloat):
(JSC::MacroAssemblerX86Common::supportsFloatingPointRounding):
(JSC::MacroAssemblerX86Common::supportsFloatingPointCeil): Deleted.
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::floorConstant):
* b3/B3ConstDoubleValue.h:
* b3/B3ConstFloatValue.cpp:
(JSC::B3::ConstFloatValue::floorConstant):
* b3/B3ConstFloatValue.h:
* b3/B3LowerMacrosAfterOptimizations.cpp:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3ReduceDoubleToFloat.cpp:
* b3/B3ReduceStrength.cpp:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::floorConstant):
(JSC::B3::Value::isRounded):
(JSC::B3::Value::effects):
(JSC::B3::Value::key):
(JSC::B3::Value::typeFor):
* b3/B3Value.h:
* b3/air/AirFixPartialRegisterStalls.cpp:
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::testFloorCeilArg):
(JSC::B3::testFloorArg):
(JSC::B3::testFloorImm):
(JSC::B3::testFloorMem):
(JSC::B3::testFloorFloorArg):
(JSC::B3::testCeilFloorArg):
(JSC::B3::testFloorIToD64):
(JSC::B3::testFloorIToD32):
(JSC::B3::testFloorArgWithUselessDoubleConversion):
(JSC::B3::testFloorArgWithEffectfulDoubleConversion):
(JSC::B3::run):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArithMode.cpp:
(WTF::printInternal):
* dfg/DFGArithMode.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::roundShouldSpeculateInt32):
* dfg/DFGNode.h:
(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasArithRoundingMode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithRounding):
(JSC::DFG::SpeculativeJIT::compileArithRound): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithRound):
(JSC::FTL::DFG::LowerDFGToB3::compileArithFloor):
(JSC::FTL::DFG::LowerDFGToB3::compileArithCeil):
* ftl/FTLOutput.h:
(JSC::FTL::Output::doubleFloor):
* jit/ThunkGenerators.cpp:
(JSC::ceilThunkGenerator):
* tests/stress/math-ceil-arith-rounding-mode.js: Added.
(firstCareAboutZeroSecondDoesNot):
(firstDoNotCareAboutZeroSecondDoes):
(warmup):
(verifyNegativeZeroIsPreserved):
* tests/stress/math-ceil-basics.js: Added.
(mathCeilOnIntegers):
(mathCeilOnDoubles):
(mathCeilOnBooleans):
(uselessMathCeil):
(mathCeilWithOverflow):
(mathCeilConsumedAsDouble):
(mathCeilDoesNotCareAboutMinusZero):
(mathCeilNoArguments):
(mathCeilTooManyArguments):
(testMathCeilOnConstants):
(mathCeilStructTransition):
(Math.ceil):
* tests/stress/math-floor-arith-rounding-mode.js: Added.
(firstCareAboutZeroSecondDoesNot):
(firstDoNotCareAboutZeroSecondDoes):
(warmup):
(verifyNegativeZeroIsPreserved):
* tests/stress/math-floor-basics.js: Added.
(mathFloorOnIntegers):
(mathFloorOnDoubles):
(mathFloorOnBooleans):
(uselessMathFloor):
(mathFloorWithOverflow):
(mathFloorConsumedAsDouble):
(mathFloorDoesNotCareAboutMinusZero):
(mathFloorNoArguments):
(mathFloorTooManyArguments):
(testMathFloorOnConstants):
(mathFloorStructTransition):
(Math.floor):
* tests/stress/math-round-should-not-use-truncate.js: Added.
(mathRoundDoesNotCareAboutMinusZero):
* tests/stress/math-rounding-infinity.js: Added.
(shouldBe):
(testRound):
(testFloor):
(testCeil):
* tests/stress/math-rounding-nan.js: Added.
(shouldBe):
(testRound):
(testFloor):
(testCeil):
* tests/stress/math-rounding-negative-zero.js: Added.
(shouldBe):
(testRound):
(testFloor):
(testCeil):
(testRoundNonNegativeZero):
(testRoundNonNegativeZero2):
Websites/webkit.org:
* docs/b3/intermediate-representation.html:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@197380 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index d7c1bff..a541ef2 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -833,10 +833,20 @@
break;
}
- case ArithRound: {
+ case ArithRound:
+ case ArithFloor:
+ case ArithCeil: {
JSValue operand = forNode(node->child1()).value();
if (operand && operand.isNumber()) {
- double roundedValue = jsRound(operand.asNumber());
+ double roundedValue = 0;
+ if (node->op() == ArithRound)
+ roundedValue = jsRound(operand.asNumber());
+ else if (node->op() == ArithFloor)
+ roundedValue = floor(operand.asNumber());
+ else {
+ ASSERT(node->op() == ArithCeil);
+ roundedValue = ceil(operand.asNumber());
+ }
if (producesInteger(node->arithRoundingMode())) {
int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
diff --git a/Source/JavaScriptCore/dfg/DFGArithMode.cpp b/Source/JavaScriptCore/dfg/DFGArithMode.cpp
index c1dfe7f..84ddae1 100644
--- a/Source/JavaScriptCore/dfg/DFGArithMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArithMode.cpp
@@ -55,6 +55,22 @@
RELEASE_ASSERT_NOT_REACHED();
}
+void printInternal(PrintStream& out, JSC::DFG::Arith::RoundingMode mode)
+{
+ switch (mode) {
+ case JSC::DFG::Arith::RoundingMode::Int32:
+ out.print("Int32");
+ return;
+ case JSC::DFG::Arith::RoundingMode::Int32WithNegativeZeroCheck:
+ out.print("Int32WithNegativeZeroCheck");
+ return;
+ case JSC::DFG::Arith::RoundingMode::Double:
+ out.print("Double");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
} // namespace WTF
#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGArithMode.h b/Source/JavaScriptCore/dfg/DFGArithMode.h
index 4e09ac3..aecfe3e 100644
--- a/Source/JavaScriptCore/dfg/DFGArithMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArithMode.h
@@ -146,6 +146,7 @@
class PrintStream;
void printInternal(PrintStream&, JSC::DFG::Arith::Mode);
+void printInternal(PrintStream&, JSC::DFG::Arith::RoundingMode);
} // namespace WTF
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index f098b64..bbc0521 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2188,7 +2188,9 @@
return true;
}
- case RoundIntrinsic: {
+ case RoundIntrinsic:
+ case FloorIntrinsic:
+ case CeilIntrinsic: {
if (argumentCountIncludingThis == 1) {
insertChecks();
set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
@@ -2197,7 +2199,16 @@
if (argumentCountIncludingThis == 2) {
insertChecks();
Node* operand = get(virtualRegisterForArgument(1, registerOffset));
- Node* roundNode = addToGraph(ArithRound, OpInfo(0), OpInfo(prediction), operand);
+ NodeType op;
+ if (intrinsic == RoundIntrinsic)
+ op = ArithRound;
+ else if (intrinsic == FloorIntrinsic)
+ op = ArithFloor;
+ else {
+ ASSERT(intrinsic == CeilIntrinsic);
+ op = ArithCeil;
+ }
+ Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand);
set(VirtualRegister(resultOperand), roundNode);
return true;
}
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 343a6de..458086e 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -297,6 +297,8 @@
}
case ArithRound:
+ case ArithFloor:
+ case ArithCeil:
def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
return;
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 702da5b..4521adb 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -87,6 +87,8 @@
case ArithSqrt:
case ArithRandom:
case ArithRound:
+ case ArithFloor:
+ case ArithCeil:
case ArithFRound:
case ArithSin:
case ArithCos:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 2265c10..f01c146 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -363,7 +363,9 @@
break;
}
- case ArithRound: {
+ case ArithRound:
+ case ArithFloor:
+ case ArithCeil: {
if (m_graph.unaryArithShouldSpeculateInt32(node, FixupPass)) {
fixIntOrBooleanEdge(node->child1());
insertCheck<Int32Use>(m_indexInBlock, node->child1().node());
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 4c9a38b..541c84e 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -222,6 +222,8 @@
out.print(comma, node->arrayMode());
if (node->hasArithMode())
out.print(comma, node->arithMode());
+ if (node->hasArithRoundingMode())
+ out.print(comma, "Rounding:", node->arithRoundingMode());
if (node->hasScopeOffset())
out.print(comma, node->scopeOffset());
if (node->hasDirectArgumentsOffset())
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 60d146b..1a4e2f7 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -316,7 +316,7 @@
bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass)
{
- ASSERT(arithRound->op() == ArithRound);
+ ASSERT(arithRound->op() == ArithRound || arithRound->op() == ArithFloor || arithRound->op() == ArithCeil);
return arithRound->canSpeculateInt32(pass) && !hasExitSite(arithRound->origin.semantic, Overflow) && !hasExitSite(arithRound->origin.semantic, NegativeZero);
}
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index eeab257..5499deb 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -928,7 +928,7 @@
NodeFlags arithNodeFlags()
{
NodeFlags result = m_flags & NodeArithFlagsMask;
- if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == DoubleAsInt32)
+ if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == DoubleAsInt32)
return result;
return result & ~NodeBytecodeNeedsNegZero;
}
@@ -1334,6 +1334,8 @@
{
switch (op()) {
case ArithRound:
+ case ArithFloor:
+ case ArithCeil:
case GetDirectPname:
case GetById:
case GetByIdFlush:
@@ -1715,7 +1717,7 @@
bool hasArithRoundingMode()
{
- return op() == ArithRound;
+ return op() == ArithRound || op() == ArithFloor || op() == ArithCeil;
}
Arith::RoundingMode arithRoundingMode()
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index ddd0b97..71c075a 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -154,6 +154,8 @@
macro(ArithPow, NodeResultNumber) \
macro(ArithRandom, NodeResultDouble | NodeMustGenerate) \
macro(ArithRound, NodeResultNumber) \
+ macro(ArithFloor, NodeResultNumber) \
+ macro(ArithCeil, NodeResultNumber) \
macro(ArithSqrt, NodeResultNumber) \
macro(ArithSin, NodeResultNumber) \
macro(ArithCos, NodeResultNumber) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index fa48248..4596053 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -386,7 +386,9 @@
break;
}
- case ArithRound: {
+ case ArithRound:
+ case ArithFloor:
+ case ArithCeil: {
if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass))
changed |= setPrediction(SpecInt32);
else
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 230efed..98592c7 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -181,6 +181,8 @@
case ArithSqrt:
case ArithFRound:
case ArithRound:
+ case ArithFloor:
+ case ArithCeil:
case ArithSin:
case ArithCos:
case ArithLog:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6174603..f03af97 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4412,46 +4412,93 @@
}
}
-void SpeculativeJIT::compileArithRound(Node* node)
+void SpeculativeJIT::compileArithRounding(Node* node)
{
ASSERT(node->child1().useKind() == DoubleRepUse);
SpeculateDoubleOperand value(this, node->child1());
FPRReg valueFPR = value.fpr();
- if (producesInteger(node->arithRoundingMode()) && !shouldCheckNegativeZero(node->arithRoundingMode())) {
- FPRTemporary oneHalf(this);
- GPRTemporary roundedResultAsInt32(this);
- FPRReg oneHalfFPR = oneHalf.fpr();
- GPRReg resultGPR = roundedResultAsInt32.gpr();
+ auto setResult = [&] (FPRReg resultFPR) {
+ if (producesInteger(node->arithRoundingMode())) {
+ GPRTemporary roundedResultAsInt32(this);
+ FPRTemporary scratch(this);
+ FPRReg scratchFPR = scratch.fpr();
+ GPRReg resultGPR = roundedResultAsInt32.gpr();
+ JITCompiler::JumpList failureCases;
+ m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node->arithRoundingMode()));
+ speculationCheck(Overflow, JSValueRegs(), node, failureCases);
- static const double halfConstant = 0.5;
- m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&halfConstant), oneHalfFPR);
- m_jit.addDouble(valueFPR, oneHalfFPR);
+ int32Result(resultGPR, node);
+ } else
+ doubleResult(resultFPR, node);
+ };
- JITCompiler::Jump truncationFailed = m_jit.branchTruncateDoubleToInt32(oneHalfFPR, resultGPR);
- speculationCheck(Overflow, JSValueRegs(), node, truncationFailed);
- int32Result(resultGPR, node);
- return;
+ if (m_jit.supportsFloatingPointRounding()) {
+ switch (node->op()) {
+ case ArithRound: {
+ FPRTemporary result(this);
+ FPRReg resultFPR = result.fpr();
+ if (producesInteger(node->arithRoundingMode()) && !shouldCheckNegativeZero(node->arithRoundingMode())) {
+ static const double halfConstant = 0.5;
+ m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&halfConstant), resultFPR);
+ m_jit.addDouble(valueFPR, resultFPR);
+ m_jit.floorDouble(resultFPR, resultFPR);
+ } else {
+ m_jit.ceilDouble(valueFPR, resultFPR);
+ FPRTemporary realPart(this);
+ FPRReg realPartFPR = realPart.fpr();
+ m_jit.subDouble(resultFPR, valueFPR, realPartFPR);
+
+ FPRTemporary scratch(this);
+ FPRReg scratchFPR = scratch.fpr();
+ static const double halfConstant = 0.5;
+ m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&halfConstant), scratchFPR);
+
+ JITCompiler::Jump shouldUseCeiled = m_jit.branchDouble(JITCompiler::DoubleLessThanOrEqual, realPartFPR, scratchFPR);
+ static const double oneConstant = -1.0;
+ m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), scratchFPR);
+ m_jit.addDouble(scratchFPR, resultFPR);
+ shouldUseCeiled.link(&m_jit);
+ }
+ setResult(resultFPR);
+ return;
+ }
+
+ case ArithFloor: {
+ FPRTemporary rounded(this);
+ FPRReg resultFPR = rounded.fpr();
+ m_jit.floorDouble(valueFPR, resultFPR);
+ setResult(resultFPR);
+ return;
+ }
+
+ case ArithCeil: {
+ FPRTemporary rounded(this);
+ FPRReg resultFPR = rounded.fpr();
+ m_jit.ceilDouble(valueFPR, resultFPR);
+ setResult(resultFPR);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ } else {
+ flushRegisters();
+ FPRResult roundedResultAsDouble(this);
+ FPRReg resultFPR = roundedResultAsDouble.fpr();
+ if (node->op() == ArithRound)
+ callOperation(jsRound, resultFPR, valueFPR);
+ else if (node->op() == ArithFloor)
+ callOperation(floor, resultFPR, valueFPR);
+ else {
+ ASSERT(node->op() == ArithCeil);
+ callOperation(ceil, resultFPR, valueFPR);
+ }
+ m_jit.exceptionCheck();
+ setResult(resultFPR);
}
-
- flushRegisters();
- FPRResult roundedResultAsDouble(this);
- FPRReg resultFPR = roundedResultAsDouble.fpr();
- callOperation(jsRound, resultFPR, valueFPR);
- m_jit.exceptionCheck();
- if (producesInteger(node->arithRoundingMode())) {
- GPRTemporary roundedResultAsInt32(this);
- FPRTemporary scratch(this);
- FPRReg scratchFPR = scratch.fpr();
- GPRReg resultGPR = roundedResultAsInt32.gpr();
- JITCompiler::JumpList failureCases;
- m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR);
- speculationCheck(Overflow, JSValueRegs(), node, failureCases);
-
- int32Result(resultGPR, node);
- } else
- doubleResult(resultFPR, node);
}
void SpeculativeJIT::compileArithSqrt(Node* node)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 9188a83..5d6fba4d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2267,7 +2267,9 @@
void compileArithDiv(Node*);
void compileArithMod(Node*);
void compileArithPow(Node*);
- void compileArithRound(Node*);
+ void compileArithRounding(Node*);
+ void compileArithFloor(Node*);
+ void compileArithCeil(Node*);
void compileArithRandom(Node*);
void compileArithSqrt(Node*);
void compileArithLog(Node*);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 8472b8c..2009a02 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2292,7 +2292,9 @@
break;
case ArithRound:
- compileArithRound(node);
+ case ArithFloor:
+ case ArithCeil:
+ compileArithRounding(node);
break;
case ArithSin: {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 83b6f5b..38cb2cd 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2415,7 +2415,9 @@
break;
case ArithRound:
- compileArithRound(node);
+ case ArithFloor:
+ case ArithCeil:
+ compileArithRounding(node);
break;
case ArithSin: {