<!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>[192320] 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/192320">192320</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-11 12:35:31 -0800 (Wed, 11 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 should be able to compile and canonicalize Mul
https://bugs.webkit.org/show_bug.cgi?id=151124

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This was a strange trip. I wanted to do a quick patch to implement Mul. But then I realized
that our tradition when adding new lowerings was to also add the corresponding strength
reductions. So then I wrote the Mul-&gt;Shl strength reduction. But that reminded me that I needed
to canonicalize between Add(x, x) and Shl(x, 1). I decided that it would probably be better to
use Shl(x, 1), since that only has one use of x. But that means that we should compile
Shl(x, 1) to Add x, x in the backend, since that's what X86 wants. While doing that, I almost
introduced a bug where Shl(Load(x), 1) would cause the compiler to either crash or generate bad
code. That's because I was using Add(x, x) to handle Shl(x, 1), so we'd end up with
Add(Load(x), Load(x)) - i.e. we would try to duplicate the Load.

The instruction selector already defends against this, and the only reason why I would have
created the bug was by using the Add helper when compiling a Shl. Still, this was so close to
a bad bug that I added a ton of new tests that cover the Op(x, x) where x = Load case.

* b3/B3Compilation.cpp:
(JSC::B3::Compilation::Compilation):
* b3/B3Compilation.h:
(JSC::B3::Compilation::code):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::subConstant):
(JSC::B3::Const32Value::mulConstant):
(JSC::B3::Const32Value::bitAndConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::subConstant):
(JSC::B3::Const64Value::mulConstant):
(JSC::B3::Const64Value::bitAndConstant):
* b3/B3Const64Value.h:
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::subConstant):
(JSC::B3::ConstDoubleValue::mulConstant):
(JSC::B3::ConstDoubleValue::equalConstant):
* b3/B3ConstDoubleValue.h:
* b3/B3Generate.cpp:
(JSC::B3::generate):
(JSC::B3::generateToAir):
* b3/B3Generate.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::appendBinOp):
(JSC::B3::Air::LowerToAir::createGenericCompare):
(JSC::B3::Air::LowerToAir::lower):
* b3/B3ReduceStrength.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::subConstant):
(JSC::B3::Value::mulConstant):
(JSC::B3::Value::bitAndConstant):
* b3/B3Value.h:
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::compile):
(JSC::B3::testReturnConst64):
(JSC::B3::testAddArg):
(JSC::B3::testAddArgs):
(JSC::B3::testAddArgs32):
(JSC::B3::testAddLoadTwice):
(JSC::B3::testMulArg):
(JSC::B3::testMulArgs):
(JSC::B3::testMulArgImm):
(JSC::B3::testMulImmArg):
(JSC::B3::testMulArgs32):
(JSC::B3::testMulLoadTwice):
(JSC::B3::testSubArg):
(JSC::B3::testSubArgs):
(JSC::B3::testShlArgImm):
(JSC::B3::testShlArg32):
(JSC::B3::testShlArgs32):
(JSC::B3::testSShrArgImm):
(JSC::B3::testSShrArg32):
(JSC::B3::testSShrArgs32):
(JSC::B3::testZShrArgImm):
(JSC::B3::testZShrArg32):
(JSC::B3::testZShrArgs32):
(JSC::B3::genericTestCompare):
(JSC::B3::testCompareLoad):
(JSC::B3::testCompareImpl):
(JSC::B3::run):

Source/WTF:

* wtf/MathExtras.h:
(WTF::fastLog2):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Compilationcpp">trunk/Source/JavaScriptCore/b3/B3Compilation.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Compilationh">trunk/Source/JavaScriptCore/b3/B3Compilation.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valueh">trunk/Source/JavaScriptCore/b3/B3Const32Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valueh">trunk/Source/JavaScriptCore/b3/B3Const64Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ConstDoubleValuecpp">trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ConstDoubleValueh">trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Generatecpp">trunk/Source/JavaScriptCore/b3/B3Generate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Generateh">trunk/Source/JavaScriptCore/b3/B3Generate.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valuecpp">trunk/Source/JavaScriptCore/b3/B3Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</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="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfMathExtrash">trunk/Source/WTF/wtf/MathExtras.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -1,3 +1,87 @@
</span><ins>+2015-11-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should be able to compile and canonicalize Mul
+        https://bugs.webkit.org/show_bug.cgi?id=151124
+
+        Reviewed by Geoffrey Garen.
+
+        This was a strange trip. I wanted to do a quick patch to implement Mul. But then I realized
+        that our tradition when adding new lowerings was to also add the corresponding strength
+        reductions. So then I wrote the Mul-&gt;Shl strength reduction. But that reminded me that I needed
+        to canonicalize between Add(x, x) and Shl(x, 1). I decided that it would probably be better to
+        use Shl(x, 1), since that only has one use of x. But that means that we should compile
+        Shl(x, 1) to Add x, x in the backend, since that's what X86 wants. While doing that, I almost
+        introduced a bug where Shl(Load(x), 1) would cause the compiler to either crash or generate bad
+        code. That's because I was using Add(x, x) to handle Shl(x, 1), so we'd end up with
+        Add(Load(x), Load(x)) - i.e. we would try to duplicate the Load.
+
+        The instruction selector already defends against this, and the only reason why I would have
+        created the bug was by using the Add helper when compiling a Shl. Still, this was so close to
+        a bad bug that I added a ton of new tests that cover the Op(x, x) where x = Load case.
+
+        * b3/B3Compilation.cpp:
+        (JSC::B3::Compilation::Compilation):
+        * b3/B3Compilation.h:
+        (JSC::B3::Compilation::code):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::subConstant):
+        (JSC::B3::Const32Value::mulConstant):
+        (JSC::B3::Const32Value::bitAndConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::subConstant):
+        (JSC::B3::Const64Value::mulConstant):
+        (JSC::B3::Const64Value::bitAndConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3ConstDoubleValue.cpp:
+        (JSC::B3::ConstDoubleValue::subConstant):
+        (JSC::B3::ConstDoubleValue::mulConstant):
+        (JSC::B3::ConstDoubleValue::equalConstant):
+        * b3/B3ConstDoubleValue.h:
+        * b3/B3Generate.cpp:
+        (JSC::B3::generate):
+        (JSC::B3::generateToAir):
+        * b3/B3Generate.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::appendBinOp):
+        (JSC::B3::Air::LowerToAir::createGenericCompare):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::subConstant):
+        (JSC::B3::Value::mulConstant):
+        (JSC::B3::Value::bitAndConstant):
+        * b3/B3Value.h:
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::compile):
+        (JSC::B3::testReturnConst64):
+        (JSC::B3::testAddArg):
+        (JSC::B3::testAddArgs):
+        (JSC::B3::testAddArgs32):
+        (JSC::B3::testAddLoadTwice):
+        (JSC::B3::testMulArg):
+        (JSC::B3::testMulArgs):
+        (JSC::B3::testMulArgImm):
+        (JSC::B3::testMulImmArg):
+        (JSC::B3::testMulArgs32):
+        (JSC::B3::testMulLoadTwice):
+        (JSC::B3::testSubArg):
+        (JSC::B3::testSubArgs):
+        (JSC::B3::testShlArgImm):
+        (JSC::B3::testShlArg32):
+        (JSC::B3::testShlArgs32):
+        (JSC::B3::testSShrArgImm):
+        (JSC::B3::testSShrArg32):
+        (JSC::B3::testSShrArgs32):
+        (JSC::B3::testZShrArgImm):
+        (JSC::B3::testZShrArg32):
+        (JSC::B3::testZShrArgs32):
+        (JSC::B3::genericTestCompare):
+        (JSC::B3::testCompareLoad):
+        (JSC::B3::testCompareImpl):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2015-11-11  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Update ES6 Generators' status to &quot;In Development&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Compilationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Compilation.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Compilation.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Compilation.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -37,10 +37,10 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 {
</span><span class="cx"> 
</span><del>-Compilation::Compilation(VM&amp; vm, Procedure&amp; proc)
</del><ins>+Compilation::Compilation(VM&amp; vm, Procedure&amp; proc, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx">     CCallHelpers jit(&amp;vm);
</span><del>-    generate(proc, jit);
</del><ins>+    generate(proc, jit, optLevel);
</ins><span class="cx">     LinkBuffer linkBuffer(vm, jit, nullptr);
</span><span class="cx"> 
</span><span class="cx">     m_codeRef = FINALIZE_CODE(linkBuffer, (&quot;B3::Compilation&quot;));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Compilationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Compilation.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Compilation.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Compilation.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    JS_EXPORT_PRIVATE Compilation(VM&amp;, Procedure&amp;);
</del><ins>+    JS_EXPORT_PRIVATE Compilation(VM&amp;, Procedure&amp;, unsigned optLevel = 1);
</ins><span class="cx">     JS_EXPORT_PRIVATE ~Compilation();
</span><span class="cx"> 
</span><span class="cx">     MacroAssemblerCodePtr code() const { return m_codeRef.code(); }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -61,6 +61,13 @@
</span><span class="cx">     return proc.add&lt;Const32Value&gt;(origin(), m_value - other-&gt;asInt32());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const32Value::mulConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt32())
+        return nullptr;
+    return proc.add&lt;Const32Value&gt;(origin(), m_value * other-&gt;asInt32());
+}
+
</ins><span class="cx"> Value* Const32Value::divConstant(Procedure&amp; proc, const Value* other) const
</span><span class="cx"> {
</span><span class="cx">     if (!other-&gt;hasInt32())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx">     Value* addConstant(Procedure&amp;, int32_t other) const override;
</span><span class="cx">     Value* addConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* subConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* mulConstant(Procedure&amp;, const Value* other) const override;
</ins><span class="cx">     Value* divConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitAndConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitOrConstant(Procedure&amp;, const Value* other) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -61,6 +61,13 @@
</span><span class="cx">     return proc.add&lt;Const64Value&gt;(origin(), m_value - other-&gt;asInt64());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const64Value::mulConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt64())
+        return nullptr;
+    return proc.add&lt;Const64Value&gt;(origin(), m_value * other-&gt;asInt64());
+}
+
</ins><span class="cx"> Value* Const64Value::divConstant(Procedure&amp; proc, const Value* other) const
</span><span class="cx"> {
</span><span class="cx">     if (!other-&gt;hasInt64())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx">     Value* addConstant(Procedure&amp;, int32_t other) const override;
</span><span class="cx">     Value* addConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* subConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* mulConstant(Procedure&amp;, const Value* other) const override;
</ins><span class="cx">     Value* divConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitAndConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitOrConstant(Procedure&amp;, const Value* other) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ConstDoubleValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -61,6 +61,13 @@
</span><span class="cx">     return proc.add&lt;ConstDoubleValue&gt;(origin(), m_value - other-&gt;asDouble());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* ConstDoubleValue::mulConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasDouble())
+        return nullptr;
+    return proc.add&lt;ConstDoubleValue&gt;(origin(), m_value * other-&gt;asDouble());
+}
+
</ins><span class="cx"> Value* ConstDoubleValue::divConstant(Procedure&amp; proc, const Value* other) const
</span><span class="cx"> {
</span><span class="cx">     if (!other-&gt;hasDouble())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ConstDoubleValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx">     Value* addConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* subConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* divConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* mulConstant(Procedure&amp;, const Value* other) const override;
</ins><span class="cx"> 
</span><span class="cx">     TriState equalConstant(const Value* other) const override;
</span><span class="cx">     TriState notEqualConstant(const Value* other) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Generatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Generate.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -42,16 +42,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 {
</span><span class="cx"> 
</span><del>-void generate(Procedure&amp; procedure, CCallHelpers&amp; jit)
</del><ins>+void generate(Procedure&amp; procedure, CCallHelpers&amp; jit, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx">     TimingScope timingScope(&quot;generate&quot;);
</span><span class="cx"> 
</span><span class="cx">     Air::Code code(procedure);
</span><del>-    generateToAir(procedure, code);
</del><ins>+    generateToAir(procedure, code, optLevel);
</ins><span class="cx">     Air::generate(code, jit);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void generateToAir(Procedure&amp; procedure, Air::Code&amp; code)
</del><ins>+void generateToAir(Procedure&amp; procedure, Air::Code&amp; code, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx">     TimingScope timingScope(&quot;generateToAir&quot;);
</span><span class="cx">     
</span><span class="lines">@@ -69,10 +69,12 @@
</span><span class="cx"> 
</span><span class="cx">     lowerMacros(procedure);
</span><span class="cx"> 
</span><del>-    reduceStrength(procedure);
-    
-    // FIXME: Add more optimizations here.
-    // https://bugs.webkit.org/show_bug.cgi?id=150507
</del><ins>+    if (optLevel &gt;= 1) {
+        reduceStrength(procedure);
+        
+        // FIXME: Add more optimizations here.
+        // https://bugs.webkit.org/show_bug.cgi?id=150507
+    }
</ins><span class="cx"> 
</span><span class="cx">     moveConstants(procedure);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Generateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Generate.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Generate.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Generate.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -39,12 +39,12 @@
</span><span class="cx"> 
</span><span class="cx"> // This takes a B3::Procedure, optimizes it in-place, and generates it to machine code by first
</span><span class="cx"> // internally converting to an Air::Code and then generating that.
</span><del>-JS_EXPORT_PRIVATE void generate(Procedure&amp;, CCallHelpers&amp;);
</del><ins>+JS_EXPORT_PRIVATE void generate(Procedure&amp;, CCallHelpers&amp;, unsigned optLevel = 1);
</ins><span class="cx"> 
</span><span class="cx"> // This takes a B3::Procedure, optimizes it in-place, and lowers it to Air. You can then generate
</span><span class="cx"> // the Air to machine code using Air::generate(). Note that an Air::Code will have pointers into the
</span><span class="cx"> // B3::Procedure, so you need to ensure that the B3::Procedure outlives the Air::Code.
</span><del>-void generateToAir(Procedure&amp;, Air::Code&amp;);
</del><ins>+void generateToAir(Procedure&amp;, Air::Code&amp;, unsigned optLevel = 1);
</ins><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -540,7 +540,7 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // Note that no known architecture has a three-operand form of binary operations that also
</del><ins>+        // Note that no extant architecture has a three-operand form of binary operations that also
</ins><span class="cx">         // load from memory. If such an abomination did exist, we would handle it somewhere around
</span><span class="cx">         // here.
</span><span class="cx"> 
</span><span class="lines">@@ -883,7 +883,7 @@
</span><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 // Finally, handle comparison between tmps.
</span><del>-                return tryCompare(width, tmpPromise(left), tmpPromise(right));
</del><ins>+                return compare(width, relCond, tmpPromise(left), tmpPromise(right));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // Double comparisons can't really do anything smart.
</span><span class="lines">@@ -1233,6 +1233,12 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case Mul: {
+            appendBinOp&lt;Mul32, Mul64, Air::Oops, Commutative&gt;(
+                m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
+        }
+
</ins><span class="cx">         case Div: {
</span><span class="cx">             if (isInt(m_value-&gt;type())) {
</span><span class="cx">                 Tmp eax = Tmp(X86Registers::eax);
</span><span class="lines">@@ -1286,6 +1292,15 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case Shl: {
</span><ins>+            if (m_value-&gt;child(1)-&gt;isInt32(1)) {
+                // This optimization makes sense on X86. I don't know if it makes sense anywhere else.
+                append(Move, tmp(m_value-&gt;child(0)), tmp(m_value));
+                append(
+                    opcodeForType(Add32, Add64, Air::Oops, m_value-&gt;child(0)-&gt;type()),
+                    tmp(m_value), tmp(m_value));
+                return;
+            }
+            
</ins><span class="cx">             appendShift&lt;Lshift32, Lshift64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
</span><span class="cx">             return;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -156,6 +156,17 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            // Turn this: Add(value, value)
+            // Into this: Shl(value, 1)
+            // This is a useful canonicalization. It's not meant to be a strength reduction.
+            if (m_value-&gt;child(0) == m_value-&gt;child(1)) {
+                replaceWithNewValue(
+                    m_proc.add&lt;Value&gt;(
+                        Shl, m_value-&gt;origin(), m_value-&gt;child(0),
+                        m_insertionSet.insert&lt;Const32Value&gt;(m_index, m_value-&gt;origin(), 1)));
+                break;
+            }
+
</ins><span class="cx">             // Turn this: Add(value, zero)
</span><span class="cx">             // Into an Identity.
</span><span class="cx">             if (m_value-&gt;child(1)-&gt;isInt(0)) {
</span><span class="lines">@@ -186,6 +197,72 @@
</span><span class="cx"> 
</span><span class="cx">             break;
</span><span class="cx"> 
</span><ins>+        case Mul:
+            handleCommutativity();
+
+            // Turn this: Mul(constant1, constant2)
+            // Into this: constant1 * constant2
+            if (Value* value = m_value-&gt;child(0)-&gt;mulConstant(m_proc, m_value-&gt;child(1))) {
+                replaceWithNewValue(value);
+                break;
+            }
+
+            if (m_value-&gt;child(1)-&gt;hasInt()) {
+                int64_t factor = m_value-&gt;child(1)-&gt;asInt();
+
+                // Turn this: Mul(value, 0)
+                // Into this: 0
+                // Note that we don't do this for doubles because that's wrong. For example, -1 * 0
+                // and 1 * 0 yield different results.
+                if (!factor) {
+                    m_value-&gt;replaceWithIdentity(m_value-&gt;child(1));
+                    m_changed = true;
+                    break;
+                }
+
+                // Turn this: Mul(value, 1)
+                // Into this: value
+                if (factor == 1) {
+                    m_value-&gt;replaceWithIdentity(m_value-&gt;child(0));
+                    m_changed = true;
+                    break;
+                }
+
+                // Turn this: Mul(value, -1)
+                // Into this: Sub(0, value)
+                if (factor == -1) {
+                    replaceWithNewValue(
+                        m_proc.add&lt;Value&gt;(
+                            Sub, m_value-&gt;origin(),
+                            m_insertionSet.insertIntConstant(m_index, m_value, 0),
+                            m_value-&gt;child(0)));
+                    break;
+                }
+                
+                // Turn this: Mul(value, constant)
+                // Into this: Shl(value, log2(constant))
+                if (hasOneBitSet(factor)) {
+                    unsigned shiftAmount = WTF::fastLog2(static_cast&lt;uint64_t&gt;(factor));
+                    replaceWithNewValue(
+                        m_proc.add&lt;Value&gt;(
+                            Shl, m_value-&gt;origin(), m_value-&gt;child(0),
+                            m_insertionSet.insert&lt;Const32Value&gt;(
+                                m_index, m_value-&gt;origin(), shiftAmount)));
+                    break;
+                }
+            } else if (m_value-&gt;child(1)-&gt;hasDouble()) {
+                double factor = m_value-&gt;child(1)-&gt;asDouble();
+
+                // Turn this: Mul(value, 1)
+                // Into this: value
+                if (factor == 1) {
+                    m_value-&gt;replaceWithIdentity(m_value-&gt;child(0));
+                    break;
+                }
+            }
+
+            break;
+
</ins><span class="cx">         case Div:
</span><span class="cx">         case ChillDiv:
</span><span class="cx">             // Turn this: Div(constant1, constant2)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -134,6 +134,11 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Value::mulConstant(Procedure&amp;, const Value*) const
+{
+    return nullptr;
+}
+
</ins><span class="cx"> Value* Value::divConstant(Procedure&amp;, const Value*) const
</span><span class="cx"> {
</span><span class="cx">     return nullptr;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -113,6 +113,7 @@
</span><span class="cx">     virtual Value* addConstant(Procedure&amp;, int32_t other) const;
</span><span class="cx">     virtual Value* addConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* subConstant(Procedure&amp;, const Value* other) const;
</span><ins>+    virtual Value* mulConstant(Procedure&amp;, const Value* other) const;
</ins><span class="cx">     virtual Value* divConstant(Procedure&amp;, const Value* other) const; // This chooses ChillDiv semantics for integers.
</span><span class="cx">     virtual Value* bitAndConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* bitOrConstant(Procedure&amp;, const Value* other) const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -100,6 +100,12 @@
</span><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp
</span><span class="cx"> 
</span><ins>+Mul32 U:G, U:G, D:G
+    Imm, Tmp, Tmp
+
+Mul64 U:G, UD:G
+    Tmp, Tmp
+
</ins><span class="cx"> X86ConvertToDoubleWord32 U:G, D:G
</span><span class="cx">     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 (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -68,9 +68,9 @@
</span><span class="cx"> 
</span><span class="cx"> VM* vm;
</span><span class="cx"> 
</span><del>-std::unique_ptr&lt;Compilation&gt; compile(Procedure&amp; procedure)
</del><ins>+std::unique_ptr&lt;Compilation&gt; compile(Procedure&amp; procedure, unsigned optLevel = 1)
</ins><span class="cx"> {
</span><del>-    return std::make_unique&lt;Compilation&gt;(*vm, procedure);
</del><ins>+    return std::make_unique&lt;Compilation&gt;(*vm, procedure, optLevel);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T, typename... Arguments&gt;
</span><span class="lines">@@ -132,6 +132,18 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int64_t&gt;(proc) == value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testAddArg(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a) == a + a);
+}
+
</ins><span class="cx"> void testAddArgs(int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -192,6 +204,132 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, a, b) == a + b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testAddLoadTwice()
+{
+    auto test = [&amp;] (unsigned optLevel) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        int32_t value = 42;
+        Value* load = root-&gt;appendNew&lt;MemoryValue&gt;(
+            proc, Load, Int32, Origin(),
+            root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;value));
+        root-&gt;appendNew&lt;ControlValue&gt;(
+            proc, Return, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), load, load));
+
+        auto code = compile(proc, optLevel);
+        CHECK(invoke&lt;int32_t&gt;(*code) == 42 * 2);
+    };
+
+    test(0);
+    test(1);
+}
+
+void testMulArg(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Mul, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a) == a * a);
+}
+
+void testMulArgs(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a, b) == a * b);
+}
+
+void testMulArgImm(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), b)));
+
+    CHECK(compileAndRun&lt;int64_t&gt;(proc, a) == a * b);
+}
+
+void testMulImmArg(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), a),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, b) == a * b);
+}
+
+void testMulArgs32(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a, b) == a * b);
+}
+
+void testMulLoadTwice()
+{
+    auto test = [&amp;] (unsigned optLevel) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        int32_t value = 42;
+        Value* load = root-&gt;appendNew&lt;MemoryValue&gt;(
+            proc, Load, Int32, Origin(),
+            root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;value));
+        root-&gt;appendNew&lt;ControlValue&gt;(
+            proc, Return, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Mul, Origin(), load, load));
+
+        auto code = compile(proc, optLevel);
+        CHECK(invoke&lt;int32_t&gt;(*code) == 42 * 42);
+    };
+
+    test(0);
+    test(1);
+}
+
+void testSubArg(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(), value, value));
+
+    CHECK(!compileAndRun&lt;int&gt;(proc, a));
+}
+
</ins><span class="cx"> void testSubArgs(int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -1011,6 +1149,20 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int64_t&gt;(proc, a) == (a &lt;&lt; b));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testShlArg32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Shl, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;int32_t&gt;(proc, a) == (a &lt;&lt; a));
+}
+
</ins><span class="cx"> void testShlArgs32(int32_t a, int32_t b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -1103,6 +1255,20 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int64_t&gt;(proc, a) == (a &gt;&gt; b));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testSShrArg32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, SShr, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;int32_t&gt;(proc, a) == (a &gt;&gt; a));
+}
+
</ins><span class="cx"> void testSShrArgs32(int32_t a, int32_t b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -1195,6 +1361,20 @@
</span><span class="cx">     CHECK(compileAndRun&lt;uint64_t&gt;(proc, a) == (a &gt;&gt; b));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testZShrArg32(uint32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, ZShr, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;uint32_t&gt;(proc, a) == (a &gt;&gt; a));
+}
+
</ins><span class="cx"> void testZShrArgs32(uint32_t a, uint32_t b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -2523,12 +2703,14 @@
</span><span class="cx">         Procedure proc;
</span><span class="cx">         BasicBlock* root = proc.addBlock();
</span><span class="cx"> 
</span><ins>+        Value* leftValue = leftFunctor(root, proc);
+        Value* rightValue = rightFunctor(root, proc);
+        
</ins><span class="cx">         root-&gt;appendNew&lt;ControlValue&gt;(
</span><span class="cx">             proc, Return, Origin(),
</span><span class="cx">             root-&gt;appendNew&lt;Value&gt;(
</span><span class="cx">                 proc, NotEqual, Origin(),
</span><del>-                root-&gt;appendNew&lt;Value&gt;(
-                    proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)),
</del><ins>+                root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), leftValue, rightValue),
</ins><span class="cx">                 root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0)));
</span><span class="cx"> 
</span><span class="cx">         CHECK(compileAndRun&lt;int&gt;(proc, left, right) == result);
</span><span class="lines">@@ -2541,10 +2723,12 @@
</span><span class="cx">         BasicBlock* thenCase = proc.addBlock();
</span><span class="cx">         BasicBlock* elseCase = proc.addBlock();
</span><span class="cx"> 
</span><ins>+        Value* leftValue = leftFunctor(root, proc);
+        Value* rightValue = rightFunctor(root, proc);
+
</ins><span class="cx">         root-&gt;appendNew&lt;ControlValue&gt;(
</span><span class="cx">             proc, Branch, Origin(),
</span><del>-            root-&gt;appendNew&lt;Value&gt;(
-                proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)),
</del><ins>+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), leftValue, rightValue),
</ins><span class="cx">             FrequentedBlock(thenCase), FrequentedBlock(elseCase));
</span><span class="cx"> 
</span><span class="cx">         // We use a patchpoint on the then case to ensure that this doesn't get if-converted.
</span><span class="lines">@@ -2662,6 +2846,22 @@
</span><span class="cx">                 block-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;slot));
</span><span class="cx">         },
</span><span class="cx">         left, right, result);
</span><ins>+
+    // Test addr-to-addr, with the same addr.
+    slot = left;
+    Value* value;
+    genericTestCompare(
+        opcode,
+        [&amp;] (BasicBlock* block, Procedure&amp; proc) {
+            value = block-&gt;appendNew&lt;MemoryValue&gt;(
+                proc, loadOpcode, Int32, Origin(),
+                block-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;slot));
+            return value;
+        },
+        [&amp;] (BasicBlock*, Procedure&amp;) {
+            return value;
+        },
+        left, left, modelCompare(opcode, modelLoad&lt;T&gt;(left), modelLoad&lt;T&gt;(left)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testCompareImpl(B3::Opcode opcode, int left, int right)
</span><span class="lines">@@ -2990,6 +3190,7 @@
</span><span class="cx">     RUN(testReturnConst64(5));
</span><span class="cx">     RUN(testReturnConst64(-42));
</span><span class="cx"> 
</span><ins>+    RUN(testAddArg(111));
</ins><span class="cx">     RUN(testAddArgs(1, 1));
</span><span class="cx">     RUN(testAddArgs(1, 2));
</span><span class="cx">     RUN(testAddArgImm(1, 2));
</span><span class="lines">@@ -3000,7 +3201,45 @@
</span><span class="cx">     RUN(testAddImmArg(1, 0));
</span><span class="cx">     RUN(testAddArgs32(1, 1));
</span><span class="cx">     RUN(testAddArgs32(1, 2));
</span><ins>+    RUN(testAddLoadTwice());
</ins><span class="cx"> 
</span><ins>+    RUN(testMulArg(5));
+    RUN(testMulArgs(1, 1));
+    RUN(testMulArgs(1, 2));
+    RUN(testMulArgs(3, 3));
+    RUN(testMulArgImm(1, 2));
+    RUN(testMulArgImm(1, 4));
+    RUN(testMulArgImm(1, 8));
+    RUN(testMulArgImm(1, 16));
+    RUN(testMulArgImm(1, 0x80000000llu));
+    RUN(testMulArgImm(1, 0x800000000000llu));
+    RUN(testMulArgImm(7, 2));
+    RUN(testMulArgImm(7, 4));
+    RUN(testMulArgImm(7, 8));
+    RUN(testMulArgImm(7, 16));
+    RUN(testMulArgImm(7, 0x80000000llu));
+    RUN(testMulArgImm(7, 0x800000000000llu));
+    RUN(testMulArgImm(-42, 2));
+    RUN(testMulArgImm(-42, 4));
+    RUN(testMulArgImm(-42, 8));
+    RUN(testMulArgImm(-42, 16));
+    RUN(testMulArgImm(-42, 0x80000000llu));
+    RUN(testMulArgImm(-42, 0x800000000000llu));
+    RUN(testMulArgImm(0, 2));
+    RUN(testMulArgImm(1, 0));
+    RUN(testMulArgImm(3, 3));
+    RUN(testMulArgImm(3, -1));
+    RUN(testMulArgImm(-3, -1));
+    RUN(testMulArgImm(0, -1));
+    RUN(testMulImmArg(1, 2));
+    RUN(testMulImmArg(0, 2));
+    RUN(testMulImmArg(1, 0));
+    RUN(testMulImmArg(3, 3));
+    RUN(testMulArgs32(1, 1));
+    RUN(testMulArgs32(1, 2));
+    RUN(testMulLoadTwice());
+
+    RUN(testSubArg(24));
</ins><span class="cx">     RUN(testSubArgs(1, 1));
</span><span class="cx">     RUN(testSubArgs(1, 2));
</span><span class="cx">     RUN(testSubArgs(13, -42));
</span><span class="lines">@@ -3207,6 +3446,7 @@
</span><span class="cx">     RUN(testShlArgImm(0xffffffffffffffff, 0));
</span><span class="cx">     RUN(testShlArgImm(0xffffffffffffffff, 1));
</span><span class="cx">     RUN(testShlArgImm(0xffffffffffffffff, 63));
</span><ins>+    RUN(testShlArg32(2));
</ins><span class="cx">     RUN(testShlArgs32(1, 0));
</span><span class="cx">     RUN(testShlArgs32(1, 1));
</span><span class="cx">     RUN(testShlArgs32(1, 62));
</span><span class="lines">@@ -3248,6 +3488,7 @@
</span><span class="cx">     RUN(testSShrArgImm(0xffffffffffffffff, 0));
</span><span class="cx">     RUN(testSShrArgImm(0xffffffffffffffff, 1));
</span><span class="cx">     RUN(testSShrArgImm(0xffffffffffffffff, 63));
</span><ins>+    RUN(testSShrArg32(32));
</ins><span class="cx">     RUN(testSShrArgs32(1, 0));
</span><span class="cx">     RUN(testSShrArgs32(1, 1));
</span><span class="cx">     RUN(testSShrArgs32(1, 62));
</span><span class="lines">@@ -3289,6 +3530,7 @@
</span><span class="cx">     RUN(testZShrArgImm(0xffffffffffffffff, 0));
</span><span class="cx">     RUN(testZShrArgImm(0xffffffffffffffff, 1));
</span><span class="cx">     RUN(testZShrArgImm(0xffffffffffffffff, 63));
</span><ins>+    RUN(testZShrArg32(32));
</ins><span class="cx">     RUN(testZShrArgs32(1, 0));
</span><span class="cx">     RUN(testZShrArgs32(1, 1));
</span><span class="cx">     RUN(testZShrArgs32(1, 62));
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/WTF/ChangeLog        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2015-11-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should be able to compile and canonicalize Mul
+        https://bugs.webkit.org/show_bug.cgi?id=151124
+
+        Reviewed by Geoffrey Garen.
+
+        * wtf/MathExtras.h:
+        (WTF::fastLog2):
+
</ins><span class="cx"> 2015-11-10  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         B3 should be able to compile a program with ChillDiv
</span></span></pre></div>
<a id="trunkSourceWTFwtfMathExtrash"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MathExtras.h (192319 => 192320)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MathExtras.h        2015-11-11 19:50:25 UTC (rev 192319)
+++ trunk/Source/WTF/wtf/MathExtras.h        2015-11-11 20:35:31 UTC (rev 192320)
</span><span class="lines">@@ -368,6 +368,14 @@
</span><span class="cx">     return log2;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline unsigned fastLog2(uint64_t value)
+{
+    unsigned high = static_cast&lt;unsigned&gt;(value &gt;&gt; 32);
+    if (high)
+        return fastLog2(high) + 32;
+    return fastLog2(static_cast&lt;unsigned&gt;(value));
+}
+
</ins><span class="cx"> template &lt;typename T&gt;
</span><span class="cx"> inline typename std::enable_if&lt;std::is_floating_point&lt;T&gt;::value, T&gt;::type safeFPDivision(T u, T v)
</span><span class="cx"> {
</span></span></pre>
</div>
</div>

</body>
</html>