FTL: split overflow checks into non-overflow arithmetic and an additional call...

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

Patch by Nadav Rotem <nrotem@apple.com> on 2013-10-01
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):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156746 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 86346d7c
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.
......@@ -662,16 +662,17 @@ private:
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;
}
......@@ -687,9 +688,11 @@ private:
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;
}
......@@ -713,14 +716,11 @@ private:
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())) {
......@@ -744,11 +744,12 @@ private:
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"));
......@@ -1050,20 +1051,18 @@ private:
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;
}
......@@ -1082,7 +1081,7 @@ private:
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;
......
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