<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[196799] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/196799">196799</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-02-18 22:42:06 -0800 (Thu, 18 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Improve the instruction selection of Select
https://bugs.webkit.org/show_bug.cgi?id=154432

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-02-18
Reviewed by Filip Pizlo.

Plenty of code but this patch is pretty dumb:
-On ARM64: use the 3 operand form of CSEL instead of forcing a source
 to be alised to the destination. This gives more freedom to the register
 allocator and it is one less Move to process per Select.
-On x86, introduce a fake 3 operands form and use aggressive aliasing
 to try to alias both sources to the destination.

 If aliasing succeed on the &quot;elseCase&quot;, the condition of the Select
 is reverted in the MacroAssembler.

 If no aliasing is possible and we end up with 3 registers, the missing
 move instruction is generated by the MacroAssembler.

 The missing move is generated after testing the values because the destination
 can use the same register as one of the test operand.
 Experimental testing seems to indicate there is no macro-fusion on CMOV,
 there is no measurable cost to having the move there.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::isInvertible):
(JSC::MacroAssembler::invert):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::moveConditionallyDouble):
(JSC::MacroAssemblerARM64::moveConditionallyFloat):
(JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
(JSC::MacroAssemblerARM64::moveConditionally32):
(JSC::MacroAssemblerARM64::moveConditionally64):
(JSC::MacroAssemblerARM64::moveConditionallyTest32):
(JSC::MacroAssemblerARM64::moveConditionallyTest64):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::moveConditionallyDouble):
(JSC::MacroAssemblerX86Common::moveConditionallyFloat):
(JSC::MacroAssemblerX86Common::moveConditionally32):
(JSC::MacroAssemblerX86Common::moveConditionallyTest32):
(JSC::MacroAssemblerX86Common::invert):
(JSC::MacroAssemblerX86Common::isInvertible):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::moveConditionally64):
(JSC::MacroAssemblerX86_64::moveConditionallyTest64):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::createSelect):
(JSC::B3::Air::LowerToAir::lower):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::Inst::shouldTryAliasingDef):
* b3/air/AirOpcode.opcodes:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInstInlinesh">trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -1,3 +1,56 @@
</span><ins>+2016-02-18  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Improve the instruction selection of Select
+        https://bugs.webkit.org/show_bug.cgi?id=154432
+
+        Reviewed by Filip Pizlo.
+
+        Plenty of code but this patch is pretty dumb:
+        -On ARM64: use the 3 operand form of CSEL instead of forcing a source
+         to be alised to the destination. This gives more freedom to the register
+         allocator and it is one less Move to process per Select.
+        -On x86, introduce a fake 3 operands form and use aggressive aliasing
+         to try to alias both sources to the destination.
+
+         If aliasing succeed on the &quot;elseCase&quot;, the condition of the Select
+         is reverted in the MacroAssembler.
+
+         If no aliasing is possible and we end up with 3 registers, the missing
+         move instruction is generated by the MacroAssembler.
+
+         The missing move is generated after testing the values because the destination
+         can use the same register as one of the test operand.
+         Experimental testing seems to indicate there is no macro-fusion on CMOV,
+         there is no measurable cost to having the move there.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::isInvertible):
+        (JSC::MacroAssembler::invert):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::moveConditionallyDouble):
+        (JSC::MacroAssemblerARM64::moveConditionallyFloat):
+        (JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
+        (JSC::MacroAssemblerARM64::moveConditionally32):
+        (JSC::MacroAssemblerARM64::moveConditionally64):
+        (JSC::MacroAssemblerARM64::moveConditionallyTest32):
+        (JSC::MacroAssemblerARM64::moveConditionallyTest64):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::moveConditionallyDouble):
+        (JSC::MacroAssemblerX86Common::moveConditionallyFloat):
+        (JSC::MacroAssemblerX86Common::moveConditionally32):
+        (JSC::MacroAssemblerX86Common::moveConditionallyTest32):
+        (JSC::MacroAssemblerX86Common::invert):
+        (JSC::MacroAssemblerX86Common::isInvertible):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::moveConditionally64):
+        (JSC::MacroAssemblerX86_64::moveConditionallyTest64):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::createSelect):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::Inst::shouldTryAliasingDef):
+        * b3/air/AirOpcode.opcodes:
+
</ins><span class="cx"> 2016-02-18  Gyuyoung Kim  &lt;gyuyoung.kim@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [CMake][GTK] Clean up llvm guard in PlatformGTK.cmake
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -177,6 +177,8 @@
</span><span class="cx">         switch (cond) {
</span><span class="cx">         case Zero:
</span><span class="cx">         case NonZero:
</span><ins>+        case Signed:
+        case PositiveOrZero:
</ins><span class="cx">             return true;
</span><span class="cx">         default:
</span><span class="cx">             return false;
</span><span class="lines">@@ -190,6 +192,10 @@
</span><span class="cx">             return NonZero;
</span><span class="cx">         case NonZero:
</span><span class="cx">             return Zero;
</span><ins>+        case Signed:
+            return PositiveOrZero;
+        case PositiveOrZero:
+            return Signed;
</ins><span class="cx">         default:
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">             return Zero; // Make compiler happy for release builds.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -1601,12 +1601,24 @@
</span><span class="cx">         moveConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.fcmp&lt;64&gt;(left, right);
+        moveConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, thenCase, elseCase, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.fcmp&lt;32&gt;(left, right);
</span><span class="cx">         moveConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.fcmp&lt;32&gt;(left, right);
+        moveConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, thenCase, elseCase, dest);
+    }
+
</ins><span class="cx">     template&lt;int datasize&gt;
</span><span class="cx">     void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="lines">@@ -1628,6 +1640,27 @@
</span><span class="cx">         m_assembler.csel&lt;datasize&gt;(dest, src, dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template&lt;int datasize&gt;
+    void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (cond == DoubleNotEqual) {
+            Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+            m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionNE);
+            unordered.link(this);
+            return;
+        }
+        if (cond == DoubleEqualOrUnordered) {
+            // If the compare is unordered, thenCase is copied to dest and the
+            // next csel has all arguments equal to thenCase.
+            // If the compare is ordered, dest is unchanged and EQ decides
+            // what value to set.
+            m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionVS);
+            m_assembler.csel&lt;datasize&gt;(dest, thenCase, dest, ARM64Assembler::ConditionEQ);
+            return;
+        }
+        m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void mulDouble(FPRegisterID src, FPRegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         mulDouble(dest, src, dest);
</span><span class="lines">@@ -1894,24 +1927,48 @@
</span><span class="cx">         m_assembler.csel&lt;32&gt;(dest, src, dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.cmp&lt;32&gt;(left, right);
+        m_assembler.csel&lt;32&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.cmp&lt;64&gt;(left, right);
</span><span class="cx">         m_assembler.csel&lt;64&gt;(dest, src, dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.cmp&lt;64&gt;(left, right);
+        m_assembler.csel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.tst&lt;32&gt;(testReg, mask);
</span><span class="cx">         m_assembler.csel&lt;32&gt;(dest, src, dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.tst&lt;32&gt;(left, right);
+        m_assembler.csel&lt;32&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.tst&lt;64&gt;(testReg, mask);
</span><span class="cx">         m_assembler.csel&lt;64&gt;(dest, src, dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyTest64(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.tst&lt;64&gt;(left, right);
+        m_assembler.csel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     // Forwards / external control flow operations:
</span><span class="cx">     //
</span><span class="cx">     // This set of jump and conditional branch operations return a Jump
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -1577,6 +1577,30 @@
</span><span class="cx">         moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isSSE2Present());
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        RegisterID src;
+        if (elseCase == dest)
+            src = thenCase;
+        else {
+            cond = invert(cond);
+            src = elseCase;
+        }
+
+        if (cond &amp; DoubleConditionBitInvert)
+            m_assembler.ucomisd_rr(left, right);
+        else
+            m_assembler.ucomisd_rr(right, left);
+        moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(isSSE2Present());
</span><span class="lines">@@ -1587,6 +1611,30 @@
</span><span class="cx">             m_assembler.ucomiss_rr(right, left);
</span><span class="cx">         moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
</span><span class="cx">     }
</span><ins>+
+    void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isSSE2Present());
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        RegisterID src;
+        if (elseCase == dest)
+            src = thenCase;
+        else {
+            cond = invert(cond);
+            src = elseCase;
+        }
+
+        if (cond &amp; DoubleConditionBitInvert)
+            m_assembler.ucomiss_rr(left, right);
+        else
+            m_assembler.ucomiss_rr(right, left);
+        moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
+    }
</ins><span class="cx">     
</span><span class="cx">     void swap(RegisterID reg1, RegisterID reg2)
</span><span class="cx">     {
</span><span class="lines">@@ -1700,19 +1748,69 @@
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.cmpl_rr(right, left);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.testl_rr(testReg, mask);
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    void moveConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isInvertible(cond));
+        ASSERT_WITH_MESSAGE(cond != Overflow, &quot;TEST does not set the Overflow Flag.&quot;);
+
+        m_assembler.testl_rr(right, left);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         test32(cond, testReg, mask);
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><del>-    
</del><span class="cx"> 
</span><ins>+    void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isInvertible(cond));
+        ASSERT_WITH_MESSAGE(cond != Overflow, &quot;TEST does not set the Overflow Flag.&quot;);
+
+        test32(cond, testReg, mask);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
</ins><span class="cx">     // Forwards / external control flow operations:
</span><span class="cx">     //
</span><span class="cx">     // This set of jump and conditional branch operations return a Jump
</span><span class="lines">@@ -2120,6 +2218,68 @@
</span><span class="cx">         return static_cast&lt;RelationalCondition&gt;(cond ^ 1);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static DoubleCondition invert(DoubleCondition cond)
+    {
+        switch (cond) {
+        case DoubleEqual:
+            return DoubleNotEqualOrUnordered;
+        case DoubleNotEqual:
+            return DoubleEqualOrUnordered;
+        case DoubleGreaterThan:
+            return DoubleLessThanOrEqualOrUnordered;
+        case DoubleGreaterThanOrEqual:
+            return DoubleLessThanOrUnordered;
+        case DoubleLessThan:
+            return DoubleGreaterThanOrEqualOrUnordered;
+        case DoubleLessThanOrEqual:
+            return DoubleGreaterThanOrUnordered;
+        case DoubleEqualOrUnordered:
+            return DoubleNotEqual;
+        case DoubleNotEqualOrUnordered:
+            return DoubleEqual;
+        case DoubleGreaterThanOrUnordered:
+            return DoubleLessThanOrEqual;
+        case DoubleGreaterThanOrEqualOrUnordered:
+            return DoubleLessThan;
+        case DoubleLessThanOrUnordered:
+            return DoubleGreaterThanOrEqual;
+        case DoubleLessThanOrEqualOrUnordered:
+            return DoubleGreaterThan;
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return DoubleEqual; // make compiler happy
+    }
+
+    static bool isInvertible(ResultCondition cond)
+    {
+        switch (cond) {
+        case Zero:
+        case NonZero:
+        case Signed:
+        case PositiveOrZero:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    static ResultCondition invert(ResultCondition cond)
+    {
+        switch (cond) {
+        case Zero:
+            return NonZero;
+        case NonZero:
+            return Zero;
+        case Signed:
+            return PositiveOrZero;
+        case PositiveOrZero:
+            return Signed;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return Zero; // Make compiler happy for release builds.
+        }
+    }
+
</ins><span class="cx">     void nop()
</span><span class="cx">     {
</span><span class="cx">         m_assembler.nop();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -979,11 +979,44 @@
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        m_assembler.cmpq_rr(right, left);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.testq_rr(testReg, mask);
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><ins>+
+    void moveConditionallyTest64(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isInvertible(cond));
+        ASSERT_WITH_MESSAGE(cond != Overflow, &quot;TEST does not set the Overflow Flag.&quot;);
+
+        m_assembler.testq_rr(right, left);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
</ins><span class="cx">     
</span><span class="cx">     void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="lines">@@ -996,6 +1029,29 @@
</span><span class="cx">             m_assembler.testq_i32r(mask.m_value, testReg);
</span><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><ins>+
+    void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        ASSERT(isInvertible(cond));
+        ASSERT_WITH_MESSAGE(cond != Overflow, &quot;TEST does not set the Overflow Flag.&quot;);
+
+        if (mask.m_value == -1)
+            m_assembler.testq_rr(testReg, testReg);
+        else if (!(mask.m_value &amp; ~0x7f))
+            m_assembler.testb_i8r(mask.m_value, testReg);
+        else
+            m_assembler.testq_i32r(mask.m_value, testReg);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
</ins><span class="cx">     
</span><span class="cx">     void abortWithReason(AbortReason reason)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -1599,13 +1599,32 @@
</span><span class="cx">         Air::Opcode moveConditionallyTest64;
</span><span class="cx">         Air::Opcode moveConditionallyDouble;
</span><span class="cx">         Air::Opcode moveConditionallyFloat;
</span><del>-        Tmp source;
-        Tmp destination;
</del><span class="cx">     };
</span><del>-    Inst createSelect(Value* value, const MoveConditionallyConfig&amp; config, bool inverted = false)
</del><ins>+    Inst createSelect(const MoveConditionallyConfig&amp; config)
</ins><span class="cx">     {
</span><ins>+        auto createSelectInstruction = [&amp;] (Air::Opcode opcode, const Arg&amp; condition, const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
+            if (isValidForm(opcode, condition.kind(), left.kind(), right.kind(), Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
+                Tmp result = tmp(m_value);
+                Tmp thenCase = tmp(m_value-&gt;child(1));
+                Tmp elseCase = tmp(m_value-&gt;child(2));
+                append(relaxedMoveForType(m_value-&gt;type()), tmp(m_value-&gt;child(2)), result);
+                return Inst(
+                    opcode, m_value, condition,
+                    left.consume(*this), right.consume(*this), thenCase, elseCase, result);
+            }
+            if (isValidForm(opcode, condition.kind(), left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                Tmp result = tmp(m_value);
+                Tmp source = tmp(m_value-&gt;child(1));
+                append(relaxedMoveForType(m_value-&gt;type()), tmp(m_value-&gt;child(2)), result);
+                return Inst(
+                    opcode, m_value, condition,
+                    left.consume(*this), right.consume(*this), source, result);
+            }
+            return Inst();
+        };
+
</ins><span class="cx">         return createGenericCompare(
</span><del>-            value,
</del><ins>+            m_value-&gt;child(0),
</ins><span class="cx">             [&amp;] (
</span><span class="cx">                 Arg::Width width, const Arg&amp; relCond,
</span><span class="cx">                 const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
</span><span class="lines">@@ -1617,19 +1636,9 @@
</span><span class="cx">                 case Arg::Width16:
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width32:
</span><del>-                    if (isValidForm(config.moveConditionally32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                        return Inst(
-                            config.moveConditionally32, m_value, relCond,
-                            left.consume(*this), right.consume(*this), config.source, config.destination);
-                    }
-                    return Inst();
</del><ins>+                    return createSelectInstruction(config.moveConditionally32, relCond, left, right);
</ins><span class="cx">                 case Arg::Width64:
</span><del>-                    if (isValidForm(config.moveConditionally64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                        return Inst(
-                            config.moveConditionally64, m_value, relCond,
-                            left.consume(*this), right.consume(*this), config.source, config.destination);
-                    }
-                    return Inst();
</del><ins>+                    return createSelectInstruction(config.moveConditionally64, relCond, left, right);
</ins><span class="cx">                 }
</span><span class="cx">                 ASSERT_NOT_REACHED();
</span><span class="cx">             },
</span><span class="lines">@@ -1644,39 +1653,19 @@
</span><span class="cx">                 case Arg::Width16:
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width32:
</span><del>-                    if (isValidForm(config.moveConditionallyTest32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                        return Inst(
-                            config.moveConditionallyTest32, m_value, resCond,
-                            left.consume(*this), right.consume(*this), config.source, config.destination);
-                    }
-                    return Inst();
</del><ins>+                    return createSelectInstruction(config.moveConditionallyTest32, resCond, left, right);
</ins><span class="cx">                 case Arg::Width64:
</span><del>-                    if (isValidForm(config.moveConditionallyTest64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                        return Inst(
-                            config.moveConditionallyTest64, m_value, resCond,
-                            left.consume(*this), right.consume(*this), config.source, config.destination);
-                    }
-                    return Inst();
</del><ins>+                    return createSelectInstruction(config.moveConditionallyTest64, resCond, left, right);
</ins><span class="cx">                 }
</span><span class="cx">                 ASSERT_NOT_REACHED();
</span><span class="cx">             },
</span><span class="cx">             [&amp;] (Arg doubleCond, const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
</span><del>-                if (isValidForm(config.moveConditionallyDouble, Arg::DoubleCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                    return Inst(
-                        config.moveConditionallyDouble, m_value, doubleCond,
-                        left.consume(*this), right.consume(*this), config.source, config.destination);
-                }
-                return Inst();
</del><ins>+                return createSelectInstruction(config.moveConditionallyDouble, doubleCond, left, right);
</ins><span class="cx">             },
</span><span class="cx">             [&amp;] (Arg doubleCond, const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
</span><del>-                if (isValidForm(config.moveConditionallyFloat, Arg::DoubleCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
-                    return Inst(
-                        config.moveConditionallyFloat, m_value, doubleCond,
-                        left.consume(*this), right.consume(*this), config.source, config.destination);
-                }
-                return Inst();
</del><ins>+                return createSelectInstruction(config.moveConditionallyFloat, doubleCond, left, right);
</ins><span class="cx">             },
</span><del>-            inverted);
</del><ins>+            false);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void lower()
</span><span class="lines">@@ -2027,13 +2016,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case Select: {
</span><del>-            Tmp result = tmp(m_value);
-            append(relaxedMoveForType(m_value-&gt;type()), tmp(m_value-&gt;child(2)), result);
-
</del><span class="cx">             MoveConditionallyConfig config;
</span><del>-            config.source = tmp(m_value-&gt;child(1));
-            config.destination = result;
-
</del><span class="cx">             if (isInt(m_value-&gt;type())) {
</span><span class="cx">                 config.moveConditionally32 = MoveConditionally32;
</span><span class="cx">                 config.moveConditionally64 = MoveConditionally64;
</span><span class="lines">@@ -2051,7 +2034,7 @@
</span><span class="cx">                 config.moveConditionallyFloat = MoveDoubleConditionallyFloat;
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            m_insts.last().append(createSelect(m_value-&gt;child(0), config));
</del><ins>+            m_insts.last().append(createSelect(config));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInstInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -196,6 +196,16 @@
</span><span class="cx">         if (args.size() == 4)
</span><span class="cx">             return 3;
</span><span class="cx">         break;
</span><ins>+    case MoveConditionally32:
+    case MoveConditionally64:
+    case MoveConditionallyTest32:
+    case MoveConditionallyTest64:
+    case MoveConditionallyDouble:
+    case MoveConditionallyFloat:
+        if (args.size() == 6)
+            return 5;
+        break;
+        break;
</ins><span class="cx">     case Patch:
</span><span class="cx">         return PatchCustom::shouldTryAliasingDef(*this);
</span><span class="cx">     default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (196798 => 196799)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-02-19 05:26:53 UTC (rev 196798)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-02-19 06:42:06 UTC (rev 196799)
</span><span class="lines">@@ -713,20 +713,40 @@
</span><span class="cx"> MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+
</ins><span class="cx"> 64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+
</ins><span class="cx"> MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     x86: ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+
</ins><span class="cx"> 64: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     x86: ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+64: MoveConditionallyTest64 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+
+MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
+
</ins><span class="cx"> MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
+
</ins><span class="cx"> MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>