+2013-10-01 Nadav Rotem <nrotem@apple.com>
+
+ FTL: split overflow checks into non-overflow arithmetic and an additional call to the overflow intrinsic check.
+ https://bugs.webkit.org/show_bug.cgi?id=122170
+
+ Reviewed by Filip Pizlo.
+
+ Overflow intrinsics are preventing SCEV and other LLVM analysis passes from analyzing loops. This patch changes the FTL-IR gen by splitting arithmetic calculations into two parts:
+ 1. Generate the arithmetic calculation (that may overflow)
+ 2. Generate the overflow check (that is only used by the OSR-exit logic).
+
+ We trust LLVM (SelectionDAG) to merge these calculations into a single opcode.
+
+ This JS function:
+
+ function foo() {
+ for (i=0; i < 10000000; i++) { }
+ }
+
+ Is now compiled into this LLVM-IR:
+
+ "OSR exit continuation for @24<Int32>": ; preds = %"Block #0", %"OSR exit continuation for @24<Int32>2"
+ %4 = phi i64 [ %10, %"OSR exit continuation for @24<Int32>2" ], [ -281474976710656, %"Block #0" ]
+ %5 = trunc i64 %4 to i32
+ %6 = add i32 %5, 1
+ %7 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %5, i32 1)
+ %8 = extractvalue { i32, i1 } %7, 1
+ br i1 %8, label %"OSR exit failCase for @24<Int32>1", label %"OSR exit continuation for @24<Int32>2"
+
+ And into this assembly:
+
+ LBB0_1: ## %OSR exit continuation for @24<Int32>
+ ## =>This Inner Loop Header: Depth=1
+ movl %ecx, %esi
+ incl %esi
+ jo LBB0_4
+
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileAddSub):
+ (JSC::FTL::LowerDFGToLLVM::compileArithMul):
+ (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
+
2013-10-01 Nadav Rotem <nrotem@apple.com>
Consolidate multiple OSRExit calls into one.
case Int32Use: {
LValue left = lowInt32(m_node->child1());
LValue right = lowInt32(m_node->child2());
-
+ LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right);
+
if (bytecodeCanTruncateInteger(m_node->arithNodeFlags())) {
- setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
+ setInt32(result);
break;
}
- LValue result = isSub ? m_out.subWithOverflow32(left, right) : m_out.addWithOverflow32(left, right);
+ LValue overflow = isSub ? m_out.subWithOverflow32(left, right) : m_out.addWithOverflow32(left, right);
- speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
- setInt32(m_out.extractValue(result, 0));
+ speculate(Overflow, noValue(), 0, m_out.extractValue(overflow, 1));
+ setInt32(result);
break;
}
LValue left = lowInt52(m_node->child1());
LValue right = lowInt52(m_node->child2());
- LValue result = isSub ? m_out.subWithOverflow64(left, right) : m_out.addWithOverflow64(left, right);
- speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
- setInt52(m_out.extractValue(result, 0));
+ LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right);
+
+ LValue overflow = isSub ? m_out.subWithOverflow64(left, right) : m_out.addWithOverflow64(left, right);
+ speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflow, 1));
+ setInt52(result);
break;
}
case Int32Use: {
LValue left = lowInt32(m_node->child1());
LValue right = lowInt32(m_node->child2());
-
- LValue result;
- if (bytecodeCanTruncateInteger(m_node->arithNodeFlags()))
- result = m_out.mul(left, right);
- else {
+ LValue result = m_out.mul(left, right);
+
+ if (!bytecodeCanTruncateInteger(m_node->arithNodeFlags())) {
LValue overflowResult = m_out.mulWithOverflow32(left, right);
speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
- result = m_out.extractValue(overflowResult, 0);
}
if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), opposite(kind));
-
+ LValue result = m_out.mul(left, right);
+
+
LValue overflowResult = m_out.mulWithOverflow64(left, right);
speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
- LValue result = m_out.extractValue(overflowResult, 0);
-
+
if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
case Int32Use: {
LValue value = lowInt32(m_node->child1());
- LValue result;
- if (bytecodeCanTruncateInteger(m_node->arithNodeFlags()))
- result = m_out.neg(value);
- else if (bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
- // We don't have a negate-with-overflow intrinsic. Hopefully this
- // does the trick, though.
- LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
- speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
- result = m_out.extractValue(overflowResult, 0);
- } else {
- speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
- result = m_out.neg(value);
+ LValue result = m_out.neg(value);
+ if (!bytecodeCanTruncateInteger(m_node->arithNodeFlags())) {
+ if (bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
+ // We don't have a negate-with-overflow intrinsic. Hopefully this
+ // does the trick, though.
+ LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
+ speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+ } else
+ speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
+
}
-
+
setInt32(result);
break;
}
LValue value = lowInt52(m_node->child1());
LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
- LValue result = m_out.extractValue(overflowResult, 0);
+ LValue result = m_out.neg(value);
speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
setInt52(result);
break;