FTL: split overflow checks into non-overflow arithmetic and an additional call to...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Oct 2013 23:18:47 +0000 (23:18 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Oct 2013 23:18:47 +0000 (23:18 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@156746 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

index a3f2fda27fe9dff4b7726d6b10249b2282401e6a..41927088fd97ea79fa4a66f7cba993817b52a8a8 100644 (file)
@@ -1,3 +1,45 @@
+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.
index ca28ba679aaa8e480150dd71bbb771a840ada900..8f1877eb653bd5f34f8957c587c28d899055e0aa 100644 (file)
@@ -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;