<!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>[197652] trunk/Source</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/197652">197652</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-06 18:40:16 -0800 (Sun, 06 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Improve codegen of Compare and Test
https://bugs.webkit.org/show_bug.cgi?id=155055

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

Source/JavaScriptCore:

This patch introduces a few improvements on how we lower
Compare and Test with immediates:
    -Add certain Immediate forms of ARM64.
    -Use CBZ/CBNZ when possible on ARM64.
    -When possible, convert a CMP into a TST
     On some hardware, we can issue more TST simultaneously.

     On x86, any TST+Jump is candidate for macro-fusion.
     They are also smaller.
     (sections 3.4.2.2 and 3.5.1.9)
    -Do not load the mask immediate of a TST
     if it only contains ones (mostly useful for ARM64
     since that would not have been a valid immediate).

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::compare32):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
This is somewhat unrelated but I found that out while working
on moveDoubleConditionallyTest32:
    If &quot;thenCase&quot; and &quot;dest&quot; are assigned the same register
    by the allocator, then the first (f)fcsel would override
    the &quot;thenCase&quot; and the second fcsel would always be &quot;elseCase&quot;.

This is covered by testb3 but was only uncovered
after recent &quot;Move&quot; removals in lowering.

(JSC::MacroAssemblerARM64::moveConditionally32):
(JSC::MacroAssemblerARM64::moveConditionally64):
(JSC::MacroAssemblerARM64::moveConditionallyTest32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally64):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
(JSC::MacroAssemblerARM64::branch32):
(JSC::MacroAssemblerARM64::branch64):
(JSC::MacroAssemblerARM64::branchTest32):
(JSC::MacroAssemblerARM64::test32):
The version taking an immediate was guarded by
(cond == Zero) || (cond == NonZero). That is overzealous,
and only needed for CBZ/CBNZ.

(JSC::MacroAssemblerARM64::branchTest64):
(JSC::MacroAssemblerARM64::compare32):
(JSC::MacroAssemblerARM64::compare64):
(JSC::MacroAssemblerARM64::commuteCompareToZeroIntoTest):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::moveConditionally32):
(JSC::MacroAssemblerX86Common::moveConditionallyTest32):
(JSC::MacroAssemblerX86Common::branch32):
(JSC::MacroAssemblerX86Common::test32):
(JSC::MacroAssemblerX86Common::branchTest32):
(JSC::MacroAssemblerX86Common::compare32):
(JSC::MacroAssemblerX86Common::commuteCompareToZeroIntoTest):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::compare64):
(JSC::MacroAssemblerX86_64::branch64):
(JSC::MacroAssemblerX86_64::moveConditionally64):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::createGenericCompare):
Unfortunately this cannot be abstracted by the MacroAssembler.
Those immediates are not valid, we have to pick the better
for right away.

* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::int64Operands):
(JSC::B3::modelCompare):
(JSC::B3::testCompareImpl):
(JSC::B3::testCompare):
(JSC::B3::b3Pow):
(JSC::B3::testPowDoubleByIntegerLoop):
Some versions of pow(double, int) do not return
the exact same bits as our integer loop.
Added a new version to have the same behavior
as the B3 loop.

(JSC::B3::run):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleBooleanBranch):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileInt32Compare):
Comparing to an immediate is super common. Do not waste
a register for that!

Source/WebCore:

* cssjit/FunctionCall.h:
(WebCore::FunctionCall::callAndBranchOnCondition):</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="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.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="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssjitFunctionCallh">trunk/Source/WebCore/cssjit/FunctionCall.h</a></li>
<li><a href="#trunkSourceWebCorecssjitSelectorCompilercpp">trunk/Source/WebCore/cssjit/SelectorCompiler.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1,3 +1,95 @@
</span><ins>+2016-03-06  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Improve codegen of Compare and Test
+        https://bugs.webkit.org/show_bug.cgi?id=155055
+
+        Reviewed by Filip Pizlo.
+
+        This patch introduces a few improvements on how we lower
+        Compare and Test with immediates:
+            -Add certain Immediate forms of ARM64.
+            -Use CBZ/CBNZ when possible on ARM64.
+            -When possible, convert a CMP into a TST
+             On some hardware, we can issue more TST simultaneously.
+
+             On x86, any TST+Jump is candidate for macro-fusion.
+             They are also smaller.
+             (sections 3.4.2.2 and 3.5.1.9)
+            -Do not load the mask immediate of a TST
+             if it only contains ones (mostly useful for ARM64
+             since that would not have been a valid immediate).
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::compare32):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
+        This is somewhat unrelated but I found that out while working
+        on moveDoubleConditionallyTest32:
+            If &quot;thenCase&quot; and &quot;dest&quot; are assigned the same register
+            by the allocator, then the first (f)fcsel would override
+            the &quot;thenCase&quot; and the second fcsel would always be &quot;elseCase&quot;.
+
+        This is covered by testb3 but was only uncovered
+        after recent &quot;Move&quot; removals in lowering.
+
+        (JSC::MacroAssemblerARM64::moveConditionally32):
+        (JSC::MacroAssemblerARM64::moveConditionally64):
+        (JSC::MacroAssemblerARM64::moveConditionallyTest32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally64):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
+        (JSC::MacroAssemblerARM64::branch32):
+        (JSC::MacroAssemblerARM64::branch64):
+        (JSC::MacroAssemblerARM64::branchTest32):
+        (JSC::MacroAssemblerARM64::test32):
+        The version taking an immediate was guarded by
+        (cond == Zero) || (cond == NonZero). That is overzealous,
+        and only needed for CBZ/CBNZ.
+
+        (JSC::MacroAssemblerARM64::branchTest64):
+        (JSC::MacroAssemblerARM64::compare32):
+        (JSC::MacroAssemblerARM64::compare64):
+        (JSC::MacroAssemblerARM64::commuteCompareToZeroIntoTest):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::moveConditionally32):
+        (JSC::MacroAssemblerX86Common::moveConditionallyTest32):
+        (JSC::MacroAssemblerX86Common::branch32):
+        (JSC::MacroAssemblerX86Common::test32):
+        (JSC::MacroAssemblerX86Common::branchTest32):
+        (JSC::MacroAssemblerX86Common::compare32):
+        (JSC::MacroAssemblerX86Common::commuteCompareToZeroIntoTest):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::compare64):
+        (JSC::MacroAssemblerX86_64::branch64):
+        (JSC::MacroAssemblerX86_64::moveConditionally64):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::createGenericCompare):
+        Unfortunately this cannot be abstracted by the MacroAssembler.
+        Those immediates are not valid, we have to pick the better
+        for right away.
+
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::int64Operands):
+        (JSC::B3::modelCompare):
+        (JSC::B3::testCompareImpl):
+        (JSC::B3::testCompare):
+        (JSC::B3::b3Pow):
+        (JSC::B3::testPowDoubleByIntegerLoop):
+        Some versions of pow(double, int) do not return
+        the exact same bits as our integer loop.
+        Added a new version to have the same behavior
+        as the B3 loop.
+
+        (JSC::B3::run):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBooleanBranch):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileInt32Compare):
+        Comparing to an immediate is super common. Do not waste
+        a register for that!
+
</ins><span class="cx"> 2016-03-06  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, fix build. This was a messed up merge.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -112,6 +112,7 @@
</span><span class="cx">     using MacroAssemblerBase::pop;
</span><span class="cx">     using MacroAssemblerBase::jump;
</span><span class="cx">     using MacroAssemblerBase::branch32;
</span><ins>+    using MacroAssemblerBase::compare32;
</ins><span class="cx">     using MacroAssemblerBase::move;
</span><span class="cx">     using MacroAssemblerBase::add32;
</span><span class="cx">     using MacroAssemblerBase::and32;
</span><span class="lines">@@ -400,6 +401,11 @@
</span><span class="cx">         return branch32(commute(cond), right, left);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void compare32(RelationalCondition cond, Imm32 left, RegisterID right, RegisterID dest)
+    {
+        compare32(commute(cond), right, left, dest);
+    }
+
</ins><span class="cx">     void branchTestPtr(ResultCondition cond, RegisterID reg, Label target)
</span><span class="cx">     {
</span><span class="cx">         branchTestPtr(cond, reg).linkTo(target, this);
</span><span class="lines">@@ -1621,6 +1627,29 @@
</span><span class="cx">         return branch32(cond, left, right.asTrustedImm32());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void compare32(RelationalCondition cond, RegisterID left, Imm32 right, RegisterID dest)
+    {
+        if (shouldBlind(right)) {
+            if (left != dest || haveScratchRegisterForBlinding()) {
+                RegisterID blindedConstantReg = dest;
+                if (left == dest)
+                    blindedConstantReg = scratchRegisterForBlinding();
+                loadXorBlindedConstant(xorBlindConstant(right), blindedConstantReg);
+                compare32(cond, left, blindedConstantReg, dest);
+                return;
+            }
+            // If we don't have a scratch register available for use, we'll just
+            // place a random number of nops.
+            uint32_t nopCount = random() &amp; 3;
+            while (nopCount--)
+                nop();
+            compare32(cond, left, right.asTrustedImm32(), dest);
+            return;
+        }
+
+        compare32(cond, left, right.asTrustedImm32(), dest);
+    }
+
</ins><span class="cx">     Jump branchAdd32(ResultCondition cond, RegisterID src, Imm32 imm, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         if (src == dest)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;ARM64Assembler.h&quot;
</span><span class="cx"> #include &quot;AbstractMacroAssembler.h&quot;
</span><span class="cx"> #include &lt;wtf/MathExtras.h&gt;
</span><ins>+#include &lt;wtf/Optional.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -1685,12 +1686,12 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         if (cond == DoubleEqualOrUnordered) {
</span><del>-            // If the compare is unordered, thenCase is copied to dest and the
</del><ins>+            // If the compare is unordered, thenCase is copied to elseCase and the
</ins><span class="cx">             // next csel has all arguments equal to thenCase.
</span><span class="cx">             // If the compare is ordered, dest is unchanged and EQ decides
</span><span class="cx">             // what value to set.
</span><del>-            m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionVS);
-            m_assembler.csel&lt;datasize&gt;(dest, thenCase, dest, ARM64Assembler::ConditionEQ);
</del><ins>+            m_assembler.csel&lt;datasize&gt;(elseCase, thenCase, elseCase, ARM64Assembler::ConditionVS);
+            m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionEQ);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="lines">@@ -1706,12 +1707,12 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         if (cond == DoubleEqualOrUnordered) {
</span><del>-            // If the compare is unordered, thenCase is copied to dest and the
</del><ins>+            // If the compare is unordered, thenCase is copied to elseCase and the
</ins><span class="cx">             // next csel has all arguments equal to thenCase.
</span><span class="cx">             // If the compare is ordered, dest is unchanged and EQ decides
</span><span class="cx">             // what value to set.
</span><del>-            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionVS);
-            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, dest, ARM64Assembler::ConditionEQ);
</del><ins>+            m_assembler.fcsel&lt;datasize&gt;(elseCase, thenCase, elseCase, ARM64Assembler::ConditionVS);
+            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionEQ);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="lines">@@ -2003,6 +2004,13 @@
</span><span class="cx"> 
</span><span class="cx">     void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveConditionallyTest32(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
+
</ins><span class="cx">         if (isUInt12(right.m_value))
</span><span class="cx">             m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
</span><span class="cx">         else if (isUInt12(-right.m_value))
</span><span class="lines">@@ -2026,6 +2034,26 @@
</span><span class="cx">         m_assembler.csel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveConditionallyTest64(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
+
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;64&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;64&gt;(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp&lt;64&gt;(left, dataTempRegister);
+        }
+        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="lines">@@ -2038,6 +2066,12 @@
</span><span class="cx">         m_assembler.csel&lt;32&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionallyTest32(ResultCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        test32(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="lines">@@ -2058,6 +2092,13 @@
</span><span class="cx"> 
</span><span class="cx">     void moveDoubleConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveDoubleConditionallyTest32(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
+
</ins><span class="cx">         if (isUInt12(right.m_value))
</span><span class="cx">             m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
</span><span class="cx">         else if (isUInt12(-right.m_value))
</span><span class="lines">@@ -2077,6 +2118,13 @@
</span><span class="cx"> 
</span><span class="cx">     void moveDoubleConditionally64(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveDoubleConditionallyTest64(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
+
</ins><span class="cx">         if (isUInt12(right.m_value))
</span><span class="cx">             m_assembler.cmp&lt;64&gt;(left, UInt12(right.m_value));
</span><span class="cx">         else if (isUInt12(-right.m_value))
</span><span class="lines">@@ -2094,6 +2142,12 @@
</span><span class="cx">         m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveDoubleConditionallyTest32(ResultCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        test32(left, right);
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void moveDoubleConditionallyTest64(ResultCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.tst&lt;64&gt;(left, right);
</span><span class="lines">@@ -2126,6 +2180,11 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+                return branchTest32(*resultCondition, left, left);
+        }
+
</ins><span class="cx">         if (isUInt12(right.m_value))
</span><span class="cx">             m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
</span><span class="cx">         else if (isUInt12(-right.m_value))
</span><span class="lines">@@ -2191,6 +2250,11 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+                return branchTest64(*resultCondition, left, left);
+        }
+
</ins><span class="cx">         if (isUInt12(right.m_value))
</span><span class="cx">             m_assembler.cmp&lt;64&gt;(left, UInt12(right.m_value));
</span><span class="cx">         else if (isUInt12(-right.m_value))
</span><span class="lines">@@ -2205,6 +2269,11 @@
</span><span class="cx">     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
</span><span class="cx">     {
</span><span class="cx">         intptr_t immediate = right.m_value;
</span><ins>+        if (!immediate) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+                return branchTest64(*resultCondition, left, left);
+        }
+
</ins><span class="cx">         if (isUInt12(immediate))
</span><span class="cx">             m_assembler.cmp&lt;64&gt;(left, UInt12(static_cast&lt;int32_t&gt;(immediate)));
</span><span class="cx">         else if (isUInt12(-immediate))
</span><span class="lines">@@ -2269,25 +2338,22 @@
</span><span class="cx">     
</span><span class="cx">     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
</span><span class="cx">     {
</span><ins>+        if (reg == mask &amp;&amp; (cond == Zero || cond == NonZero))
+            return Jump(makeCompareAndBranch&lt;32&gt;(static_cast&lt;ZeroCondition&gt;(cond), reg));
</ins><span class="cx">         m_assembler.tst&lt;32&gt;(reg, mask);
</span><span class="cx">         return Jump(makeBranch(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</del><ins>+    void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</ins><span class="cx">     {
</span><span class="cx">         if (mask.m_value == -1)
</span><span class="cx">             m_assembler.tst&lt;32&gt;(reg, reg);
</span><span class="cx">         else {
</span><del>-            bool testedWithImmediate = false;
-            if ((cond == Zero) || (cond == NonZero)) {
-                LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
</del><ins>+            LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
</ins><span class="cx"> 
</span><del>-                if (logicalImm.isValid()) {
-                    m_assembler.tst&lt;32&gt;(reg, logicalImm);
-                    testedWithImmediate = true;
-                }
-            }
-            if (!testedWithImmediate) {
</del><ins>+            if (logicalImm.isValid())
+                m_assembler.tst&lt;32&gt;(reg, logicalImm);
+            else {
</ins><span class="cx">                 move(mask, getCachedDataTempRegisterIDAndInvalidate());
</span><span class="cx">                 m_assembler.tst&lt;32&gt;(reg, dataTempRegister);
</span><span class="cx">             }
</span><span class="lines">@@ -2308,13 +2374,10 @@
</span><span class="cx">         } else if (hasOneBitSet(mask.m_value) &amp;&amp; ((cond == Zero) || (cond == NonZero)))
</span><span class="cx">             return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast&lt;ZeroCondition&gt;(cond)));
</span><span class="cx">         else {
</span><del>-            if ((cond == Zero) || (cond == NonZero)) {
-                LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
-
-                if (logicalImm.isValid()) {
-                    m_assembler.tst&lt;32&gt;(reg, logicalImm);
-                    return Jump(makeBranch(cond));
-                }
</del><ins>+            LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
+            if (logicalImm.isValid()) {
+                m_assembler.tst&lt;32&gt;(reg, logicalImm);
+                return Jump(makeBranch(cond));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             move(mask, getCachedDataTempRegisterIDAndInvalidate());
</span><span class="lines">@@ -2337,6 +2400,8 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask)
</span><span class="cx">     {
</span><ins>+        if (reg == mask &amp;&amp; (cond == Zero || cond == NonZero))
+            return Jump(makeCompareAndBranch&lt;64&gt;(static_cast&lt;ZeroCondition&gt;(cond), reg));
</ins><span class="cx">         m_assembler.tst&lt;64&gt;(reg, mask);
</span><span class="cx">         return Jump(makeBranch(cond));
</span><span class="cx">     }
</span><span class="lines">@@ -2350,13 +2415,11 @@
</span><span class="cx">         } else if (hasOneBitSet(mask.m_value) &amp;&amp; ((cond == Zero) || (cond == NonZero)))
</span><span class="cx">             return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast&lt;ZeroCondition&gt;(cond)));
</span><span class="cx">         else {
</span><del>-            if ((cond == Zero) || (cond == NonZero)) {
-                LogicalImmediate logicalImm = LogicalImmediate::create64(mask.m_value);
</del><ins>+            LogicalImmediate logicalImm = LogicalImmediate::create64(mask.m_value);
</ins><span class="cx"> 
</span><del>-                if (logicalImm.isValid()) {
-                    m_assembler.tst&lt;64&gt;(reg, logicalImm);
-                    return Jump(makeBranch(cond));
-                }
</del><ins>+            if (logicalImm.isValid()) {
+                m_assembler.tst&lt;64&gt;(reg, logicalImm);
+                return Jump(makeBranch(cond));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
</span><span class="lines">@@ -2773,8 +2836,21 @@
</span><span class="cx"> 
</span><span class="cx">     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
</span><span class="cx">     {
</span><del>-        move(right, getCachedDataTempRegisterIDAndInvalidate());
-        m_assembler.cmp&lt;32&gt;(left, dataTempRegister);
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                test32(*resultCondition, left, left, dest);
+                return;
+            }
+        }
+
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;32&gt;(left, UInt12(-right.m_value));
+        else {
+            move(right, getCachedDataTempRegisterIDAndInvalidate());
+            m_assembler.cmp&lt;32&gt;(left, dataTempRegister);
+        }
</ins><span class="cx">         m_assembler.cset&lt;32&gt;(dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2786,6 +2862,13 @@
</span><span class="cx">     
</span><span class="cx">     void compare64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
</span><span class="cx">     {
</span><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                test64(*resultCondition, left, left, dest);
+                return;
+            }
+        }
+
</ins><span class="cx">         signExtend32ToPtr(right, getCachedDataTempRegisterIDAndInvalidate());
</span><span class="cx">         m_assembler.cmp&lt;64&gt;(left, dataTempRegister);
</span><span class="cx">         m_assembler.cset&lt;32&gt;(dest, ARM64Condition(cond));
</span><span class="lines">@@ -2806,12 +2889,7 @@
</span><span class="cx"> 
</span><span class="cx">     void test32(ResultCondition cond, RegisterID src, TrustedImm32 mask, RegisterID dest)
</span><span class="cx">     {
</span><del>-        if (mask.m_value == -1)
-            m_assembler.tst&lt;32&gt;(src, src);
-        else {
-            signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
-            m_assembler.tst&lt;32&gt;(src, dataTempRegister);
-        }
</del><ins>+        test32(src, mask);
</ins><span class="cx">         m_assembler.cset&lt;32&gt;(dest, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2994,6 +3072,23 @@
</span><span class="cx">         return static_cast&lt;RelationalCondition&gt;(ARM64Assembler::invert(static_cast&lt;ARM64Assembler::Condition&gt;(cond)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static Optional&lt;ResultCondition&gt; commuteCompareToZeroIntoTest(RelationalCondition cond)
+    {
+        switch (cond) {
+        case Equal:
+            return Zero;
+        case NotEqual:
+            return NonZero;
+        case LessThan:
+            return Signed;
+        case GreaterThanOrEqual:
+            return PositiveOrZero;
+            break;
+        default:
+            return Nullopt;
+        }
+    }
+
</ins><span class="cx">     static FunctionPtr readCallTarget(CodeLocationCall call)
</span><span class="cx">     {
</span><span class="cx">         return FunctionPtr(reinterpret_cast&lt;void(*)()&gt;(ARM64Assembler::readCallTarget(call.dataLocation())));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1343,7 +1343,7 @@
</span><span class="cx"> private:
</span><span class="cx"> 
</span><span class="cx">     // Should we be using TEQ for equal/not-equal?
</span><del>-    void compare32(RegisterID left, TrustedImm32 right)
</del><ins>+    void compare32AndSetFlags(RegisterID left, TrustedImm32 right)
</ins><span class="cx">     {
</span><span class="cx">         int32_t imm = right.m_value;
</span><span class="cx">         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
</span><span class="lines">@@ -1357,7 +1357,8 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void test32(RegisterID reg, TrustedImm32 mask)
</del><ins>+public:
+    void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</ins><span class="cx">     {
</span><span class="cx">         int32_t imm = mask.m_value;
</span><span class="cx"> 
</span><span class="lines">@@ -1381,12 +1382,6 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-
-public:
-    void test32(ResultCondition, RegisterID reg, TrustedImm32 mask)
-    {
-        test32(reg, mask);
-    }
</del><span class="cx">     
</span><span class="cx">     Jump branch(ResultCondition cond)
</span><span class="cx">     {
</span><span class="lines">@@ -1401,7 +1396,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><del>-        compare32(left, right);
</del><ins>+        compare32AndSetFlags(left, right);
</ins><span class="cx">         return Jump(makeBranch(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1459,7 +1454,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><del>-        compare32(left, right);
</del><ins>+        compare32AndSetFlags(left, right);
</ins><span class="cx">         return Jump(makeBranch(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1765,7 +1760,7 @@
</span><span class="cx"> 
</span><span class="cx">     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
</span><span class="cx">     {
</span><del>-        compare32(left, right);
</del><ins>+        compare32AndSetFlags(left, right);
</ins><span class="cx">         m_assembler.it(armV7Condition(cond), false);
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;X86Assembler.h&quot;
</span><span class="cx"> #include &quot;AbstractMacroAssembler.h&quot;
</span><ins>+#include &lt;wtf/Optional.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -1779,11 +1780,15 @@
</span><span class="cx"> 
</span><span class="cx">     void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
</span><span class="cx">     {
</span><del>-        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value)
-            m_assembler.testl_rr(left, left);
-        else
-            m_assembler.cmpl_ir(right.m_value, left);
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveConditionallyTest32(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
</ins><span class="cx"> 
</span><ins>+        m_assembler.cmpl_ir(right.m_value, left);
+
</ins><span class="cx">         if (thenCase != dest &amp;&amp; elseCase != dest) {
</span><span class="cx">             move(elseCase, dest);
</span><span class="cx">             elseCase = dest;
</span><span class="lines">@@ -1821,7 +1826,7 @@
</span><span class="cx"> 
</span><span class="cx">     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><del>-        test32(cond, testReg, mask);
</del><ins>+        test32(testReg, mask);
</ins><span class="cx">         cmov(x86Condition(cond), src, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1830,7 +1835,7 @@
</span><span class="cx">         ASSERT(isInvertible(cond));
</span><span class="cx">         ASSERT_WITH_MESSAGE(cond != Overflow, &quot;TEST does not set the Overflow Flag.&quot;);
</span><span class="cx"> 
</span><del>-        test32(cond, testReg, mask);
</del><ins>+        test32(testReg, mask);
</ins><span class="cx"> 
</span><span class="cx">         if (thenCase != dest &amp;&amp; elseCase != dest) {
</span><span class="cx">             move(elseCase, dest);
</span><span class="lines">@@ -1960,10 +1965,12 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><del>-        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value)
-            m_assembler.testl_rr(left, left);
-        else
-            m_assembler.cmpl_ir(right.m_value, left);
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+                return branchTest32(*resultCondition, left, left);
+        }
+
+        m_assembler.cmpl_ir(right.m_value, left);
</ins><span class="cx">         return Jump(m_assembler.jCC(x86Condition(cond)));
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -2002,7 +2009,7 @@
</span><span class="cx">         return Jump(m_assembler.jCC(x86Condition(cond)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void test32(ResultCondition, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</del><ins>+    void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</ins><span class="cx">     {
</span><span class="cx">         if (mask.m_value == -1)
</span><span class="cx">             m_assembler.testl_rr(reg, reg);
</span><span class="lines">@@ -2022,7 +2029,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><del>-        test32(cond, reg, mask);
</del><ins>+        test32(reg, mask);
</ins><span class="cx">         return branch(cond);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2290,10 +2297,14 @@
</span><span class="cx"> 
</span><span class="cx">     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
</span><span class="cx">     {
</span><del>-        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value)
-            m_assembler.testl_rr(left, left);
-        else
-            m_assembler.cmpl_ir(right.m_value, left);
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                test32(*resultCondition, left, left, dest);
+                return;
+            }
+        }
+
+        m_assembler.cmpl_ir(right.m_value, left);
</ins><span class="cx">         set32(x86Condition(cond), dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2323,6 +2334,12 @@
</span><span class="cx">         set32(x86Condition(cond), dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
+    {
+        test32(reg, mask);
+        set32(x86Condition(cond), dest);
+    }
+
</ins><span class="cx">     void setCarry(RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         set32(X86Assembler::ConditionC, dest);
</span><span class="lines">@@ -2396,6 +2413,23 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static Optional&lt;ResultCondition&gt; commuteCompareToZeroIntoTest(RelationalCondition cond)
+    {
+        switch (cond) {
+        case Equal:
+            return Zero;
+        case NotEqual:
+            return NonZero;
+        case LessThan:
+            return Signed;
+        case GreaterThanOrEqual:
+            return PositiveOrZero;
+            break;
+        default:
+            return Nullopt;
+        }
+    }
+
</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 (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -701,19 +701,21 @@
</span><span class="cx"> 
</span><span class="cx">     void compare64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
</span><span class="cx">     {
</span><del>-        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value)
-            m_assembler.testq_rr(left, left);
-        else
-            m_assembler.cmpq_ir(right.m_value, left);
-        m_assembler.setCC_r(x86Condition(cond), dest);
-        m_assembler.movzbl_rr(dest, dest);
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                test64(*resultCondition, left, left, dest);
+                return;
+            }
+        }
+
+        m_assembler.cmpq_ir(right.m_value, left);
+        set32(x86Condition(cond), dest);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compare64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.cmpq_rr(right, left);
</span><del>-        m_assembler.setCC_r(x86Condition(cond), dest);
-        m_assembler.movzbl_rr(dest, dest);
</del><ins>+        set32(x86Condition(cond), dest);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
</span><span class="lines">@@ -758,9 +760,9 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm32 right)
</span><span class="cx">     {
</span><del>-        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value) {
-            m_assembler.testq_rr(left, left);
-            return Jump(m_assembler.jCC(x86Condition(cond)));
</del><ins>+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+                return branchTest64(*resultCondition, left, left);
</ins><span class="cx">         }
</span><span class="cx">         m_assembler.cmpq_ir(right.m_value, left);
</span><span class="cx">         return Jump(m_assembler.jCC(x86Condition(cond)));
</span><span class="lines">@@ -994,6 +996,28 @@
</span><span class="cx">             cmov(x86Condition(invert(cond)), elseCase, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (!right.m_value) {
+            if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+                moveConditionallyTest64(*resultCondition, left, left, thenCase, elseCase, dest);
+                return;
+            }
+        }
+
+        m_assembler.cmpq_ir(right.m_value, 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></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1374,14 +1374,30 @@
</span><span class="cx"> 
</span><span class="cx">                 // Now handle test's that involve an immediate and a tmp.
</span><span class="cx"> 
</span><del>-                if (leftImm &amp;&amp; leftImm.isRepresentableAs&lt;uint32_t&gt;()) {
-                    if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right)))
-                        return result;
</del><ins>+                if (leftImm) {
+                    if ((width == Arg::Width32 &amp;&amp; leftImm.value() == 0xffffffff)
+                        || (width == Arg::Width64 &amp;&amp; leftImm.value() == -1)) {
+                        ArgPromise argPromise = tmpPromise(right);
+                        if (Inst result = tryTest(width, argPromise, argPromise))
+                            return result;
+                    }
+                    if (leftImm.isRepresentableAs&lt;uint32_t&gt;()) {
+                        if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right)))
+                            return result;
+                    }
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (rightImm &amp;&amp; rightImm.isRepresentableAs&lt;uint32_t&gt;()) {
-                    if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm))
-                        return result;
</del><ins>+                if (rightImm) {
+                    if ((width == Arg::Width32 &amp;&amp; rightImm.value() == 0xffffffff)
+                        || (width == Arg::Width64 &amp;&amp; rightImm.value() == -1)) {
+                        ArgPromise argPromise = tmpPromise(left);
+                        if (Inst result = tryTest(width, argPromise, argPromise))
+                            return result;
+                    }
+                    if (rightImm.isRepresentableAs&lt;uint32_t&gt;()) {
+                        if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm))
+                            return result;
+                    }
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 // Finally, just do tmp's.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -613,7 +613,7 @@
</span><span class="cx"> 
</span><span class="cx"> Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp
</span><del>-    x86: RelCond, Tmp, Imm, Tmp
</del><ins>+    RelCond, Tmp, Imm, Tmp
</ins><span class="cx"> 
</span><span class="cx"> 64: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp
</span><span class="lines">@@ -622,6 +622,7 @@
</span><span class="cx"> Test32 U:G:32, U:G:32, U:G:32, ZD:G:32
</span><span class="cx">     x86: ResCond, Addr, Imm, Tmp
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp
</span><ins>+    ResCond, Tmp, BitImm, Tmp
</ins><span class="cx"> 
</span><span class="cx"> 64: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32
</span><span class="cx">     x86: ResCond, Tmp, Imm, Tmp
</span><span class="lines">@@ -662,7 +663,7 @@
</span><span class="cx"> 
</span><span class="cx"> BranchTest32 U:G:32, U:G:32, U:G:32 /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><del>-    x86: ResCond, Tmp, Imm
</del><ins>+    ResCond, Tmp, BitImm
</ins><span class="cx">     x86: ResCond, Addr, Imm
</span><span class="cx">     x86: ResCond, Index, Imm
</span><span class="cx"> 
</span><span class="lines">@@ -670,7 +671,7 @@
</span><span class="cx"> # BranchTest32 in most cases where you use an immediate.
</span><span class="cx"> 64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><del>-    x86: ResCond, Tmp, Imm
</del><ins>+    ResCond, Tmp, BitImm64
</ins><span class="cx">     x86: ResCond, Addr, Imm
</span><span class="cx">     x86: ResCond, Addr, Tmp
</span><span class="cx">     x86: ResCond, Index, Imm
</span><span class="lines">@@ -748,6 +749,7 @@
</span><span class="cx"> 
</span><span class="cx"> 64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
</span><ins>+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><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="lines">@@ -755,7 +757,7 @@
</span><span class="cx"> 
</span><span class="cx"> MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
</span><del>-    x86: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
</del><ins>+    ResCond, Tmp, BitImm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><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="lines">@@ -795,7 +797,7 @@
</span><span class="cx"> 
</span><span class="cx"> MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
</span><del>-    x86: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
</del><ins>+    ResCond, Tmp, BitImm, Tmp, Tmp, Tmp
</ins><span class="cx">     x86: ResCond, Addr, Imm, Tmp, Tmp, Tmp
</span><span class="cx">     x86: ResCond, Index, Imm, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -150,10 +150,10 @@
</span><span class="cx"> static Vector&lt;Int64Operand&gt; int64Operands()
</span><span class="cx"> {
</span><span class="cx">     Vector&lt;Int64Operand&gt; operands;
</span><del>-    for (const auto&amp; doubleOperand : floatingPointOperands&lt;double&gt;())
-        operands.append({ doubleOperand.name, bitwise_cast&lt;int64_t&gt;(doubleOperand.value) });
</del><span class="cx">     operands.append({ &quot;1&quot;, 1 });
</span><span class="cx">     operands.append({ &quot;-1&quot;, -1 });
</span><ins>+    operands.append({ &quot;42&quot;, 42 });
+    operands.append({ &quot;-42&quot;, -42 });
</ins><span class="cx">     operands.append({ &quot;int64-max&quot;, std::numeric_limits&lt;int64_t&gt;::max() });
</span><span class="cx">     operands.append({ &quot;int64-min&quot;, std::numeric_limits&lt;int64_t&gt;::min() });
</span><span class="cx">     operands.append({ &quot;int32-max&quot;, std::numeric_limits&lt;int32_t&gt;::max() });
</span><span class="lines">@@ -8822,7 +8822,8 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-int modelCompare(B3::Opcode opcode, int left, int right)
</del><ins>+template&lt;typename InputType&gt;
+InputType modelCompare(B3::Opcode opcode, InputType left, InputType right)
</ins><span class="cx"> {
</span><span class="cx">     switch (opcode) {
</span><span class="cx">     case Equal:
</span><span class="lines">@@ -8838,13 +8839,17 @@
</span><span class="cx">     case GreaterEqual:
</span><span class="cx">         return left &gt;= right;
</span><span class="cx">     case Above:
</span><del>-        return static_cast&lt;unsigned&gt;(left) &gt; static_cast&lt;unsigned&gt;(right);
</del><ins>+        return static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(left) &gt;
+            static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(right);
</ins><span class="cx">     case Below:
</span><del>-        return static_cast&lt;unsigned&gt;(left) &lt; static_cast&lt;unsigned&gt;(right);
</del><ins>+        return static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(left) &lt;
+            static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(right);
</ins><span class="cx">     case AboveEqual:
</span><del>-        return static_cast&lt;unsigned&gt;(left) &gt;= static_cast&lt;unsigned&gt;(right);
</del><ins>+        return static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(left) &gt;=
+            static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(right);
</ins><span class="cx">     case BelowEqual:
</span><del>-        return static_cast&lt;unsigned&gt;(left) &lt;= static_cast&lt;unsigned&gt;(right);
</del><ins>+        return static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(left) &lt;=
+            static_cast&lt;typename std::make_unsigned&lt;InputType&gt;::type&gt;(right);
</ins><span class="cx">     case BitAnd:
</span><span class="cx">         return !!(left &amp; right);
</span><span class="cx">     default:
</span><span class="lines">@@ -8939,7 +8944,8 @@
</span><span class="cx"> 
</span><span class="cx"> void testCompareImpl(B3::Opcode opcode, int64_t left, int64_t right)
</span><span class="cx"> {
</span><del>-    int result = modelCompare(opcode, left, right);
</del><ins>+    int64_t result = modelCompare(opcode, left, right);
+    int32_t int32Result = modelCompare(opcode, static_cast&lt;int32_t&gt;(left), static_cast&lt;int32_t&gt;(right));
</ins><span class="cx">     
</span><span class="cx">     // Test tmp-to-tmp.
</span><span class="cx">     genericTestCompare(
</span><span class="lines">@@ -8963,7 +8969,7 @@
</span><span class="cx">                 proc, Trunc, Origin(),
</span><span class="cx">                 block-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
</span><span class="cx">         },
</span><del>-        left, right, result);
</del><ins>+        left, right, int32Result);
</ins><span class="cx"> 
</span><span class="cx">     // Test imm-to-tmp.
</span><span class="cx">     genericTestCompare(
</span><span class="lines">@@ -8985,7 +8991,7 @@
</span><span class="cx">                 proc, Trunc, Origin(),
</span><span class="cx">                 block-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
</span><span class="cx">         },
</span><del>-        left, right, result);
</del><ins>+        left, right, int32Result);
</ins><span class="cx"> 
</span><span class="cx">     // Test tmp-to-imm.
</span><span class="cx">     genericTestCompare(
</span><span class="lines">@@ -9007,7 +9013,7 @@
</span><span class="cx">         [&amp;] (BasicBlock* block, Procedure&amp; proc) {
</span><span class="cx">             return block-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), right);
</span><span class="cx">         },
</span><del>-        left, right, result);
</del><ins>+        left, right, int32Result);
</ins><span class="cx"> 
</span><span class="cx">     // Test imm-to-imm.
</span><span class="cx">     genericTestCompare(
</span><span class="lines">@@ -9027,7 +9033,7 @@
</span><span class="cx">         [&amp;] (BasicBlock* block, Procedure&amp; proc) {
</span><span class="cx">             return block-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), right);
</span><span class="cx">         },
</span><del>-        left, right, result);
</del><ins>+        left, right, int32Result);
</ins><span class="cx"> 
</span><span class="cx">     testCompareLoad&lt;int32_t&gt;(opcode, Load, left, right);
</span><span class="cx">     testCompareLoad&lt;int8_t&gt;(opcode, Load8S, left, right);
</span><span class="lines">@@ -9036,37 +9042,11 @@
</span><span class="cx">     testCompareLoad&lt;uint16_t&gt;(opcode, Load16Z, left, right);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void testCompare(B3::Opcode opcode, int left, int right)
</del><ins>+void testCompare(B3::Opcode opcode, int64_t left, int64_t right)
</ins><span class="cx"> {
</span><del>-    auto variants = [&amp;] (int left, int right) {
-        testCompareImpl(opcode, left, right);
-        testCompareImpl(opcode, left, right + 1);
-        testCompareImpl(opcode, left, right - 1);
-
-        auto multipliedTests = [&amp;] (int factor) {
-            testCompareImpl(opcode, left * factor, right);
-            testCompareImpl(opcode, left * factor, right + 1);
-            testCompareImpl(opcode, left * factor, right - 1);
-        
-            testCompareImpl(opcode, left, right * factor);
-            testCompareImpl(opcode, left, (right + 1) * factor);
-            testCompareImpl(opcode, left, (right - 1) * factor);
-        
-            testCompareImpl(opcode, left * factor, right * factor);
-            testCompareImpl(opcode, left * factor, (right + 1) * factor);
-            testCompareImpl(opcode, left * factor, (right - 1) * factor);
-        };
-
-        multipliedTests(10);
-        multipliedTests(100);
-        multipliedTests(1000);
-        multipliedTests(100000);
-    };
-
-    variants(left, right);
-    variants(-left, right);
-    variants(left, -right);
-    variants(-left, -right);
</del><ins>+    testCompareImpl(opcode, left, right);
+    testCompareImpl(opcode, left, right + 1);
+    testCompareImpl(opcode, left, right - 1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testEqualDouble(double left, double right, bool result)
</span><span class="lines">@@ -10899,6 +10879,20 @@
</span><span class="cx">     CHECK(invoke&lt;int&gt;(*code, true, false) == 667);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+double b3Pow(double x, int y)
+{
+    if (y &lt; 0 || y &gt; 1000)
+        return pow(x, y);
+    double result = 1;
+    while (y) {
+        if (y &amp; 1)
+            result *= x;
+        x *= x;
+        y &gt;&gt;= 1;
+    }
+    return result;
+}
+
</ins><span class="cx"> void testPowDoubleByIntegerLoop(double xOperand, int32_t yOperand)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -10911,7 +10905,7 @@
</span><span class="cx">     BasicBlock* continuation = result.first;
</span><span class="cx">     continuation-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result.second);
</span><span class="cx"> 
</span><del>-    CHECK(isIdentical(compileAndRun&lt;double&gt;(proc, xOperand, yOperand), pow(xOperand, yOperand)));
</del><ins>+    CHECK(isIdentical(compileAndRun&lt;double&gt;(proc, xOperand, yOperand), b3Pow(xOperand, yOperand)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testTruncOrHigh()
</span><span class="lines">@@ -12248,20 +12242,18 @@
</span><span class="cx">     RUN(testCheckMulArgumentAliasing64());
</span><span class="cx">     RUN(testCheckMulArgumentAliasing32());
</span><span class="cx"> 
</span><del>-    RUN(testCompare(Equal, 42, 42));
-    RUN(testCompare(NotEqual, 42, 42));
-    RUN(testCompare(LessThan, 42, 42));
-    RUN(testCompare(GreaterThan, 42, 42));
-    RUN(testCompare(LessEqual, 42, 42));
-    RUN(testCompare(GreaterEqual, 42, 42));
-    RUN(testCompare(Below, 42, 42));
-    RUN(testCompare(Above, 42, 42));
-    RUN(testCompare(BelowEqual, 42, 42));
-    RUN(testCompare(AboveEqual, 42, 42));
</del><ins>+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(Equal, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(NotEqual, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(LessThan, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(GreaterThan, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(LessEqual, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(GreaterEqual, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(Below, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(Above, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(BelowEqual, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(AboveEqual, a, b); }, int64Operands(), int64Operands());
+    RUN_BINARY([](int32_t a, int32_t b) { testCompare(BitAnd, a, b); }, int64Operands(), int64Operands());
</ins><span class="cx"> 
</span><del>-    RUN(testCompare(BitAnd, 42, 42));
-    RUN(testCompare(BitAnd, 42, 0));
-
</del><span class="cx">     RUN(testEqualDouble(42, 42, true));
</span><span class="cx">     RUN(testEqualDouble(0, -0, true));
</span><span class="cx">     RUN(testEqualDouble(42, 43, false));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1293,14 +1293,14 @@
</span><span class="cx">         notTaken = tmp;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (node-&gt;child1()-&gt;isBooleanConstant()) {
-        bool imm = node-&gt;child1()-&gt;asBoolean();
</del><ins>+    if (node-&gt;child1()-&gt;isInt32Constant()) {
+        int32_t imm = node-&gt;child1()-&gt;asInt32();
</ins><span class="cx">         SpeculateBooleanOperand op2(this, node-&gt;child2());
</span><del>-        branch32(condition, JITCompiler::Imm32(static_cast&lt;int32_t&gt;(JSValue::encode(jsBoolean(imm)))), op2.gpr(), taken);
-    } else if (node-&gt;child2()-&gt;isBooleanConstant()) {
</del><ins>+        branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
+    } else if (node-&gt;child2()-&gt;isInt32Constant()) {
</ins><span class="cx">         SpeculateBooleanOperand op1(this, node-&gt;child1());
</span><del>-        bool imm = node-&gt;child2()-&gt;asBoolean();
-        branch32(condition, op1.gpr(), JITCompiler::Imm32(static_cast&lt;int32_t&gt;(JSValue::encode(jsBoolean(imm)))), taken);
</del><ins>+        int32_t imm = node-&gt;child2()-&gt;asInt32();
+        branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
</ins><span class="cx">     } else {
</span><span class="cx">         SpeculateBooleanOperand op1(this, node-&gt;child1());
</span><span class="cx">         SpeculateBooleanOperand op2(this, node-&gt;child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1566,15 +1566,34 @@
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
</span><span class="cx"> {
</span><del>-    SpeculateInt32Operand op1(this, node-&gt;child1());
-    SpeculateInt32Operand op2(this, node-&gt;child2());
-    GPRTemporary result(this, Reuse, op1, op2);
-    
-    m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
-    
-    // If we add a DataFormatBool, we should use it here.
-    m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
-    jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
</del><ins>+    if (node-&gt;child1()-&gt;isInt32Constant()) {
+        SpeculateInt32Operand op2(this, node-&gt;child2());
+        GPRTemporary result(this, Reuse, op2);
+        int32_t imm = node-&gt;child1()-&gt;asInt32();
+        m_jit.compare32(condition, JITCompiler::Imm32(imm), op2.gpr(), result.gpr());
+
+        // If we add a DataFormatBool, we should use it here.
+        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+        jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+    } else if (node-&gt;child2()-&gt;isInt32Constant()) {
+        SpeculateInt32Operand op1(this, node-&gt;child1());
+        GPRTemporary result(this, Reuse, op1);
+        int32_t imm = node-&gt;child2()-&gt;asInt32();
+        m_jit.compare32(condition, op1.gpr(), JITCompiler::Imm32(imm), result.gpr());
+
+        // If we add a DataFormatBool, we should use it here.
+        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+        jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+    } else {
+        SpeculateInt32Operand op1(this, node-&gt;child1());
+        SpeculateInt32Operand op2(this, node-&gt;child2());
+        GPRTemporary result(this, Reuse, op1, op2);
+        m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
+
+        // If we add a DataFormatBool, we should use it here.
+        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+        jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileInt52Compare(Node* node, MacroAssembler::RelationalCondition condition)
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/WebCore/ChangeLog        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-03-06  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Improve codegen of Compare and Test
+        https://bugs.webkit.org/show_bug.cgi?id=155055
+
+        Reviewed by Filip Pizlo.
+
+        * cssjit/FunctionCall.h:
+        (WebCore::FunctionCall::callAndBranchOnCondition):
+
</ins><span class="cx"> 2016-03-06  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [[GetPrototypeOf]] should be a fully virtual method in the method table
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitFunctionCallh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/FunctionCall.h (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/FunctionCall.h        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/WebCore/cssjit/FunctionCall.h        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx">     JSC::MacroAssembler::Jump callAndBranchOnCondition(JSC::MacroAssembler::ResultCondition condition, JSC::MacroAssembler::TrustedImm32 mask)
</span><span class="cx">     {
</span><span class="cx">         prepareAndCall();
</span><del>-        m_assembler.test32(condition, JSC::GPRInfo::returnValueGPR, mask);
</del><ins>+        m_assembler.test32(JSC::GPRInfo::returnValueGPR, mask);
</ins><span class="cx">         cleanupPostCall();
</span><span class="cx">         return m_assembler.branch(condition);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitSelectorCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (197651 => 197652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2016-03-07 02:40:16 UTC (rev 197651)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2016-03-07 02:40:16 UTC (rev 197652)
</span><span class="lines">@@ -2389,7 +2389,7 @@
</span><span class="cx">         LocalRegister divisorRegister(m_registerAllocator);
</span><span class="cx">         m_assembler.move(Assembler::TrustedImm64(divisor), divisorRegister);
</span><span class="cx">         m_assembler.m_assembler.idivl_r(divisorRegister);
</span><del>-        m_assembler.test32(condition, remainder);
</del><ins>+        m_assembler.test32(remainder);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // 3) Return RAX and RDX.
</span></span></pre>
</div>
</div>

</body>
</html>