[JSC] Add register reuse for ArithAdd of an Int32 and constant in DFG
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2016 06:04:49 +0000 (06:04 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2016 06:04:49 +0000 (06:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155164

Patch by Benjamin Poulain <bpoulain@apple.com> on 2016-03-10
Reviewed by Geoffrey Garen.

Every "inc" in loop was looking like this:
    move rX, rY
    inc rY
    jo 0x230f4a200580

This patch add register Reuse to that case to remove
the extra "move".

* dfg/DFGOSRExit.h:
(JSC::DFG::SpeculationRecovery::SpeculationRecovery):
(JSC::DFG::SpeculationRecovery::immediate):
* dfg/DFGOSRExitCompiler32_64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithAdd):
* tests/stress/arith-add-with-constant-overflow.js: Added.
(opaqueAdd):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197994 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOSRExit.h
Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/tests/stress/arith-add-with-constant-overflow.js [new file with mode: 0644]

index eb86f01..34d6f50 100644 (file)
@@ -1,3 +1,30 @@
+2016-03-10  Benjamin Poulain  <bpoulain@apple.com>
+
+        [JSC] Add register reuse for ArithAdd of an Int32 and constant in DFG
+        https://bugs.webkit.org/show_bug.cgi?id=155164
+
+        Reviewed by Geoffrey Garen.
+
+        Every "inc" in loop was looking like this:
+            move rX, rY
+            inc rY
+            jo 0x230f4a200580
+
+        This patch add register Reuse to that case to remove
+        the extra "move".
+
+        * dfg/DFGOSRExit.h:
+        (JSC::DFG::SpeculationRecovery::SpeculationRecovery):
+        (JSC::DFG::SpeculationRecovery::immediate):
+        * dfg/DFGOSRExitCompiler32_64.cpp:
+        (JSC::DFG::OSRExitCompiler::compileExit):
+        * dfg/DFGOSRExitCompiler64.cpp:
+        (JSC::DFG::OSRExitCompiler::compileExit):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithAdd):
+        * tests/stress/arith-add-with-constant-overflow.js: Added.
+        (opaqueAdd):
+
 2016-03-10  Keith Miller  <keith_miller@apple.com>
 
         Unreviewed, build fix for r197983, hopefully.
index a14d54f..37dee4b 100644 (file)
@@ -48,8 +48,9 @@ struct Node;
 
 // This enum describes the types of additional recovery that
 // may need be performed should a speculation check fail.
-enum SpeculationRecoveryType {
+enum SpeculationRecoveryType : uint8_t {
     SpeculativeAdd,
+    SpeculativeAddImmediate,
     BooleanSpeculationCheck
 };
 
@@ -60,22 +61,34 @@ enum SpeculationRecoveryType {
 class SpeculationRecovery {
 public:
     SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
-        : m_type(type)
+        : m_src(src)
         , m_dest(dest)
-        , m_src(src)
+        , m_type(type)
+    {
+    }
+
+    SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, int32_t immediate)
+        : m_immediate(immediate)
+        , m_dest(dest)
+        , m_type(type)
     {
     }
 
     SpeculationRecoveryType type() { return m_type; }
     GPRReg dest() { return m_dest; }
     GPRReg src() { return m_src; }
+    int32_t immediate() { return m_immediate; }
 
 private:
-    // Indicates the type of additional recovery to be performed.
-    SpeculationRecoveryType m_type;
     // different recovery types may required different additional information here.
+    union {
+        GPRReg m_src;
+        int32_t m_immediate;
+    };
     GPRReg m_dest;
-    GPRReg m_src;
+
+    // Indicates the type of additional recovery to be performed.
+    SpeculationRecoveryType m_type;
 };
 
 // === OSRExit ===
index e419941..c3746bd 100644 (file)
@@ -56,6 +56,10 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
         case SpeculativeAdd:
             m_jit.sub32(recovery->src(), recovery->dest());
             break;
+
+        case SpeculativeAddImmediate:
+            m_jit.sub32(AssemblyHelpers::Imm32(recovery->immediate()), recovery->dest());
+            break;
             
         case BooleanSpeculationCheck:
             break;
index 6999e5c..f45c833 100644 (file)
@@ -61,6 +61,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
             m_jit.sub32(recovery->src(), recovery->dest());
             m_jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest());
             break;
+
+        case SpeculativeAddImmediate:
+            m_jit.sub32(AssemblyHelpers::Imm32(recovery->immediate()), recovery->dest());
+            m_jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest());
+            break;
             
         case BooleanSpeculationCheck:
             m_jit.xor64(AssemblyHelpers::TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
index 369ca89..c9da093 100644 (file)
@@ -3256,19 +3256,26 @@ void SpeculativeJIT::compileArithAdd(Node* node)
 
         if (node->child2()->isInt32Constant()) {
             SpeculateInt32Operand op1(this, node->child1());
+            GPRTemporary result(this, Reuse, op1);
+
+            GPRReg gpr1 = op1.gpr();
             int32_t imm2 = node->child2()->asInt32();
+            GPRReg gprResult = result.gpr();
 
             if (!shouldCheckOverflow(node->arithMode())) {
-                GPRTemporary result(this, Reuse, op1);
-                m_jit.add32(Imm32(imm2), op1.gpr(), result.gpr());
-                int32Result(result.gpr(), node);
+                m_jit.add32(Imm32(imm2), gpr1, gprResult);
+                int32Result(gprResult, node);
                 return;
             }
 
-            GPRTemporary result(this);
-            speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+            MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, Imm32(imm2), gprResult);
+            if (gpr1 == gprResult) {
+                speculationCheck(Overflow, JSValueRegs(), 0, check,
+                    SpeculationRecovery(SpeculativeAddImmediate, gpr1, imm2));
+            } else
+                speculationCheck(Overflow, JSValueRegs(), 0, check);
 
-            int32Result(result.gpr(), node);
+            int32Result(gprResult, node);
             return;
         }
                 
diff --git a/Source/JavaScriptCore/tests/stress/arith-add-with-constant-overflow.js b/Source/JavaScriptCore/tests/stress/arith-add-with-constant-overflow.js
new file mode 100644 (file)
index 0000000..ce5c381
--- /dev/null
@@ -0,0 +1,21 @@
+function opaqueAdd(a)
+{
+    return a + 42;
+}
+noInline(opaqueAdd);
+
+// Warm up.
+for (let i = 0; i < 1e4; ++i) {
+    let result = opaqueAdd(5);
+    if (result !== 47)
+        throw "Invalid opaqueAdd(5) at i = " + i;
+}
+
+// Overflow.
+for (let i = 0; i < 1e3; ++i) {
+    for (let j = -50; j < 50; ++j) {
+        let result = opaqueAdd(2147483647 + j);
+        if (result !== 2147483689 + j)
+            throw "Invalid opaqueAdd(" + 2147483647 + j + ") at i = " + i + " j = " + j;
+    }
+}