Diff
Modified: trunk/LayoutTests/ChangeLog (160204 => 160205)
--- trunk/LayoutTests/ChangeLog 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/LayoutTests/ChangeLog 2013-12-06 01:47:19 UTC (rev 160205)
@@ -1,3 +1,31 @@
+2013-12-04 Filip Pizlo <[email protected]>
+
+ FTL should use cvttsd2si directly for double-to-int32 conversions
+ https://bugs.webkit.org/show_bug.cgi?id=125275
+
+ Reviewed by Michael Saboff.
+
+ * js/regress/double-to-int32-typed-array-expected.txt: Added.
+ * js/regress/double-to-int32-typed-array-no-inline-expected.txt: Added.
+ * js/regress/double-to-int32-typed-array-no-inline.html: Added.
+ * js/regress/double-to-int32-typed-array.html: Added.
+ * js/regress/double-to-uint32-typed-array-expected.txt: Added.
+ * js/regress/double-to-uint32-typed-array-no-inline-expected.txt: Added.
+ * js/regress/double-to-uint32-typed-array-no-inline.html: Added.
+ * js/regress/double-to-uint32-typed-array.html: Added.
+ * js/regress/script-tests/double-to-int32-typed-array-no-inline.js: Added.
+ (foo):
+ (test):
+ * js/regress/script-tests/double-to-int32-typed-array.js: Added.
+ (foo):
+ (test):
+ * js/regress/script-tests/double-to-uint32-typed-array-no-inline.js: Added.
+ (foo):
+ (test):
+ * js/regress/script-tests/double-to-uint32-typed-array.js: Added.
+ (foo):
+ (test):
+
2013-12-05 Bear Travis <[email protected]>
[CSS Shapes] Enable CSS Shapes on Windows
Added: trunk/LayoutTests/js/regress/double-to-int32-typed-array-expected.txt (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-int32-typed-array-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-int32-typed-array-expected.txt 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,10 @@
+JSRegress/double-to-int32-typed-array
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline-expected.txt (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline-expected.txt 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,10 @@
+JSRegress/double-to-int32-typed-array-no-inline
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline.html (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline.html (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-int32-typed-array-no-inline.html 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/double-to-int32-typed-array.html (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-int32-typed-array.html (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-int32-typed-array.html 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/double-to-uint32-typed-array-expected.txt (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-uint32-typed-array-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-uint32-typed-array-expected.txt 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,10 @@
+JSRegress/double-to-uint32-typed-array
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline-expected.txt (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline-expected.txt 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,10 @@
+JSRegress/double-to-uint32-typed-array-no-inline
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline.html (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline.html (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-uint32-typed-array-no-inline.html 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/double-to-uint32-typed-array.html (0 => 160205)
--- trunk/LayoutTests/js/regress/double-to-uint32-typed-array.html (rev 0)
+++ trunk/LayoutTests/js/regress/double-to-uint32-typed-array.html 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array-no-inline.js (0 => 160205)
--- trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array-no-inline.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array-no-inline.js 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,24 @@
+var array = new Int32Array(1);
+
+function foo(value) {
+ array[0] = value;
+ return array[0];
+}
+
+noInline(foo);
+
+function test(input, output) {
+ var result = foo(input);
+ if (result != output)
+ throw "Error: " + input + " was supposed to result in " + output + " but instead got " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+ test(i + 0.5, i);
+
+test(0, 0);
+test(100.5, 100);
+test(-100.5, -100);
+test(3000000000, -1294967296);
+test(-3000000000, 1294967296);
+test(-2147483648, -2147483648);
Added: trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array.js (0 => 160205)
--- trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/double-to-int32-typed-array.js 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,22 @@
+var array = new Int32Array(1);
+
+function foo(value) {
+ array[0] = value;
+ return array[0];
+}
+
+function test(input, output) {
+ var result = foo(input);
+ if (result != output)
+ throw "Error: " + input + " was supposed to result in " + output + " but instead got " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+ test(i + 0.5, i);
+
+test(0, 0);
+test(100.5, 100);
+test(-100.5, -100);
+test(3000000000, -1294967296);
+test(-3000000000, 1294967296);
+test(-2147483648, -2147483648);
Added: trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array-no-inline.js (0 => 160205)
--- trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array-no-inline.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array-no-inline.js 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,25 @@
+var array = new Uint32Array(1);
+
+function foo(value) {
+ array[0] = value;
+ return array[0];
+}
+
+noInline(foo);
+
+function test(input, output) {
+ var result = foo(input);
+ if (result != output)
+ throw "Error: " + input + " was supposed to result in " + output + " but instead got " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+ test(i + 0.5, i);
+
+test(0, 0);
+test(100.5, 100);
+test(-100.5, 4294967196);
+test(3000000000, 3000000000);
+test(6000000000, 1705032704);
+test(-3000000000, 1294967296);
+test(-2147483648, 2147483648);
Added: trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array.js (0 => 160205)
--- trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/double-to-uint32-typed-array.js 2013-12-06 01:47:19 UTC (rev 160205)
@@ -0,0 +1,23 @@
+var array = new Uint32Array(1);
+
+function foo(value) {
+ array[0] = value;
+ return array[0];
+}
+
+function test(input, output) {
+ var result = foo(input);
+ if (result != output)
+ throw "Error: " + input + " was supposed to result in " + output + " but instead got " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+ test(i + 0.5, i);
+
+test(0, 0);
+test(100.5, 100);
+test(-100.5, 4294967196);
+test(3000000000, 3000000000);
+test(6000000000, 1705032704);
+test(-3000000000, 1294967296);
+test(-2147483648, 2147483648);
Modified: trunk/Source/_javascript_Core/ChangeLog (160204 => 160205)
--- trunk/Source/_javascript_Core/ChangeLog 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-12-06 01:47:19 UTC (rev 160205)
@@ -1,3 +1,57 @@
+2013-12-04 Filip Pizlo <[email protected]>
+
+ FTL should use cvttsd2si directly for double-to-int32 conversions
+ https://bugs.webkit.org/show_bug.cgi?id=125275
+
+ Reviewed by Michael Saboff.
+
+ Wow. This was an ordeal. Using cvttsd2si was actually easy, but I learned, and
+ sometimes even fixed, some interesting things:
+
+ - The llvm.x86.sse2.cvttsd2si intrinsic can actually result in LLVM emitting a
+ vcvttsd2si. I guess the intrinsic doesn't actually imply the instruction.
+
+ - That whole thing about branchTruncateDoubleToUint32? Yeah we don't need that. It's
+ better to use branchTruncateDoubleToInt32 instead. It has the right semantics for
+ all of its callers (err, its one-and-only caller), and it's more likely to take
+ fast path. This patch kills branchTruncateDoubleToUint32.
+
+ - "a[i] = v; v = a[i]". Does this change v? OK, assume that 'a[i]' is a pure-ish
+ operation - like an array access with 'i' being an integer index and we're not
+ having a bad time. Now does this change v? CSE assumes that it doesn't. That's
+ wrong. If 'a' is a typed array - the most sensible and pure kind of array - then
+ this can be a truncating cast. For example 'v' could be a double and 'a' could be
+ an integer array.
+
+ - "v1 = a[i]; v2 = a[i]". Is v1 === v2 assuming that 'a[i]' is pure-ish? The answer
+ is no. You could have a different arrayMode in each access. I know this sounds
+ weird, but with concurrent JIT that might happen.
+
+ This patch adds tests for all of this stuff, except for the first issue (it's weird
+ but probably doesn't matter) and the last issue (it's too much of a freakshow).
+
+ * assembler/MacroAssemblerARM64.h:
+ * assembler/MacroAssemblerARMv7.h:
+ * assembler/MacroAssemblerX86Common.h:
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::getByValLoadElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
+ * ftl/FTLAbbreviations.h:
+ (JSC::FTL::vectorType):
+ (JSC::FTL::getUndef):
+ (JSC::FTL::buildInsertElement):
+ * ftl/FTLIntrinsicRepository.h:
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::doubleToInt32):
+ (JSC::FTL::LowerDFGToLLVM::doubleToUInt32):
+ (JSC::FTL::LowerDFGToLLVM::sensibleDoubleToInt32):
+ * ftl/FTLOutput.h:
+ (JSC::FTL::Output::insertElement):
+ (JSC::FTL::Output::hasSensibleDoubleToInt):
+ (JSC::FTL::Output::sensibleDoubleToInt):
+
2013-12-05 Commit Queue <[email protected]>
Unreviewed, rolling out r160133.
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (160204 => 160205)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -1196,15 +1196,6 @@
return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
}
- Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
- {
- // Truncate to a 64-bit integer in dataTempRegister, copy the low 32-bit to dest.
- m_assembler.fcvtzs<64, 64>(dest, src);
- // Check thlow 32-bits zero extend to be equal to the full value.
- m_assembler.cmp<64>(dest, dest, ARM64Assembler::UXTW, 0);
- return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
- }
-
void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fcvt<32, 64>(dest, src);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (160204 => 160205)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -1074,23 +1074,6 @@
return failure;
}
- Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
- {
- m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
- m_assembler.vmov(dest, fpTempRegisterAsSingle());
-
- Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
- Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
- overflow.link(this);
-
- if (branchType == BranchIfTruncateSuccessful)
- return success;
-
- Jump failure = jump();
- success.link(this);
- return failure;
- }
-
// Result is undefined if the value is outside of the integer range.
void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
{
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (160204 => 160205)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -885,13 +885,6 @@
return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
}
- Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
- {
- ASSERT(isSSE2Present());
- m_assembler.cvttsd2si_rr(src, dest);
- return branch32(branchType ? GreaterThanOrEqual : LessThan, dest, TrustedImm32(0));
- }
-
void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
{
ASSERT(isSSE2Present());
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (160204 => 160205)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2013-12-06 01:47:19 UTC (rev 160205)
@@ -331,7 +331,7 @@
return 0;
}
- Node* getByValLoadElimination(Node* child1, Node* child2)
+ Node* getByValLoadElimination(Node* child1, Node* child2, ArrayMode arrayMode)
{
for (unsigned i = m_indexInBlock; i--;) {
Node* node = m_currentBlock->at(i);
@@ -342,7 +342,9 @@
case GetByVal:
if (!m_graph.byValIsPure(node))
return 0;
- if (node->child1() == child1 && node->child2() == child2)
+ if (node->child1() == child1
+ && node->child2() == child2
+ && node->arrayMode().type() == arrayMode.type())
return node;
break;
@@ -351,7 +353,12 @@
case PutByValAlias: {
if (!m_graph.byValIsPure(node))
return 0;
- if (m_graph.varArgChild(node, 0) == child1 && m_graph.varArgChild(node, 1) == child2)
+ // Typed arrays
+ if (arrayMode.typedArrayType() != NotTypedArray)
+ return 0;
+ if (m_graph.varArgChild(node, 0) == child1
+ && m_graph.varArgChild(node, 1) == child2
+ && node->arrayMode().type() == arrayMode.type())
return m_graph.varArgChild(node, 2).node();
// We must assume that the PutByVal will clobber the location we're getting from.
// FIXME: We can do better; if we know that the PutByVal is accessing an array of a
@@ -1216,7 +1223,7 @@
if (cseMode == StoreElimination)
break;
if (m_graph.byValIsPure(node))
- setReplacement(getByValLoadElimination(node->child1().node(), node->child2().node()));
+ setReplacement(getByValLoadElimination(node->child1().node(), node->child2().node(), node->arrayMode()));
break;
case PutByValDirect:
@@ -1226,7 +1233,7 @@
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
if (node->arrayMode().canCSEStorage()) {
- Node* replacement = getByValLoadElimination(child1.node(), child2.node());
+ Node* replacement = getByValLoadElimination(child1.node(), child2.node(), node->arrayMode());
if (!replacement)
break;
node->setOp(PutByValAlias);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (160204 => 160205)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-12-06 01:47:19 UTC (rev 160205)
@@ -2506,11 +2506,8 @@
MacroAssembler::Jump fixed = m_jit.jump();
notNaN.link(&m_jit);
- MacroAssembler::Jump failed;
- if (isSigned(type))
- failed = m_jit.branchTruncateDoubleToInt32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
- else
- failed = m_jit.branchTruncateDoubleToUint32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
+ MacroAssembler::Jump failed = m_jit.branchTruncateDoubleToInt32(
+ fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
addSlowPathGenerator(slowPathCall(failed, this, toInt32, gpr, fpr));
Modified: trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h (160204 => 160205)
--- trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -58,6 +58,7 @@
static inline LType doubleType(LContext context) { return llvm->DoubleTypeInContext(context); }
static inline LType pointerType(LType type) { return llvm->PointerType(type, 0); }
+static inline LType vectorType(LType type, unsigned count) { return llvm->VectorType(type, count); }
enum PackingMode { NotPacked, Packed };
static inline LType structType(LContext context, LType* elementTypes, unsigned elementCount, PackingMode packing = NotPacked)
@@ -140,6 +141,7 @@
}
static inline LValue getParam(LValue function, unsigned index) { return llvm->GetParam(function, index); }
+static inline LValue getUndef(LType type) { return llvm->GetUndef(type); }
enum BitExtension { ZeroExtend, SignExtend };
static inline LValue constInt(LType type, unsigned long long value, BitExtension extension = ZeroExtend) { return llvm->ConstInt(type, value, extension == SignExtend); }
@@ -217,6 +219,7 @@
static inline LValue buildBitCast(LBuilder builder, LValue value, LType type) { return llvm->BuildBitCast(builder, value, type, ""); }
static inline LValue buildICmp(LBuilder builder, LIntPredicate cond, LValue left, LValue right) { return llvm->BuildICmp(builder, cond, left, right, ""); }
static inline LValue buildFCmp(LBuilder builder, LRealPredicate cond, LValue left, LValue right) { return llvm->BuildFCmp(builder, cond, left, right, ""); }
+static inline LValue buildInsertElement(LBuilder builder, LValue vector, LValue element, LValue index) { return llvm->BuildInsertElement(builder, vector, element, index, ""); }
enum SynchronizationScope { SingleThread, CrossThread };
static inline LValue buildFence(LBuilder builder, LAtomicOrdering ordering, SynchronizationScope scope = CrossThread)
Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (160204 => 160205)
--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -42,12 +42,13 @@
macro(doubleAbs, "llvm.fabs.f64", functionType(doubleType, doubleType)) \
macro(mulWithOverflow32, "llvm.smul.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
macro(mulWithOverflow64, "llvm.smul.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
- macro(subWithOverflow32, "llvm.ssub.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
- macro(subWithOverflow64, "llvm.ssub.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
macro(patchpointInt64, "llvm.experimental.patchpoint.i64", functionType(int64, int32, int32, ref8, int32, Variadic)) \
macro(patchpointVoid, "llvm.experimental.patchpoint.void", functionType(voidType, int32, int32, ref8, int32, Variadic)) \
macro(stackmap, "llvm.experimental.stackmap", functionType(voidType, int32, int32, Variadic)) \
- macro(trap, "llvm.trap", functionType(voidType))
+ macro(subWithOverflow32, "llvm.ssub.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
+ macro(subWithOverflow64, "llvm.ssub.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
+ macro(trap, "llvm.trap", functionType(voidType)) \
+ macro(x86SSE2CvtTSD2SI, "llvm.x86.sse2.cvttsd2si", functionType(int32, vectorType(doubleType, 2)))
#define FOR_EACH_FUNCTION_TYPE(macro) \
macro(C_JITOperation_ESt, functionType(intPtr, intPtr, intPtr)) \
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (160204 => 160205)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-12-06 01:47:19 UTC (rev 160205)
@@ -3011,15 +3011,41 @@
LValue doubleToInt32(LValue doubleValue)
{
+ if (Output::hasSensibleDoubleToInt())
+ return sensibleDoubleToInt32(doubleValue);
+
double limit = pow(2, 31) - 1;
return doubleToInt32(doubleValue, -limit, limit);
}
LValue doubleToUInt32(LValue doubleValue)
{
+ if (Output::hasSensibleDoubleToInt())
+ return sensibleDoubleToInt32(doubleValue);
+
return doubleToInt32(doubleValue, 0, pow(2, 32) - 1, false);
}
+ LValue sensibleDoubleToInt32(LValue doubleValue)
+ {
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 slow path"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 continuation"));
+
+ ValueFromBlock fastResult = m_out.anchor(
+ m_out.sensibleDoubleToInt(doubleValue));
+ m_out.branch(
+ m_out.equal(fastResult.value(), m_out.constInt32(0x80000000)),
+ slowPath, continuation);
+
+ LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
+ ValueFromBlock slowResult = m_out.anchor(
+ m_out.call(m_out.operation(toInt32), doubleValue));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ return m_out.phi(m_out.int32, fastResult, slowResult);
+ }
+
void speculateBackward(
ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
{
Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (160204 => 160205)
--- trunk/Source/_javascript_Core/ftl/FTLOutput.h 2013-12-06 01:19:42 UTC (rev 160204)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h 2013-12-06 01:47:19 UTC (rev 160205)
@@ -154,6 +154,8 @@
LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); }
LValue bitNot(LValue value) { return buildNot(m_builder, value); }
+ LValue insertElement(LValue vector, LValue element, LValue index) { return buildInsertElement(m_builder, vector, element, index); }
+
LValue addWithOverflow32(LValue left, LValue right)
{
return call(addWithOverflow32Intrinsic(), left, right);
@@ -183,6 +185,17 @@
return call(doubleAbsIntrinsic(), value);
}
+ static bool hasSensibleDoubleToInt() { return isX86(); }
+ LValue sensibleDoubleToInt(LValue value)
+ {
+ RELEASE_ASSERT(isX86());
+ return call(
+ x86SSE2CvtTSD2SIIntrinsic(),
+ insertElement(
+ insertElement(getUndef(vectorType(doubleType, 2)), value, int32Zero),
+ doubleZero, int32One));
+ }
+
LValue signExt(LValue value, LType type) { return buildSExt(m_builder, value, type); }
LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
LValue fpToInt(LValue value, LType type) { return buildFPToSI(m_builder, value, type); }