<!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>[210919] trunk/Source/JavaScriptCore</title>
</head>
<body>

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

<h3>Log Message</h3>
<pre>[B3] B3 strength reduction could encounter Value without owner in PureCSE
https://bugs.webkit.org/show_bug.cgi?id=167161

Reviewed by Filip Pizlo.

PureCSE relies on the fact that all the stored Values have owner member.
This assumption is broken when you execute specializeSelect in B3ReduceStrength phase.
It clears owner of Values which are in between Select and Check to clone them to then/else
blocks. If these cleared Values are already stored in PureCSE map, this map poses a Value
with nullptr owner in PureCSE.

This patch changes PureCSE to ignore stored Values tha have nullptr owner. This even means
that a client of PureCSE could deliberately null the owner if they wanted to signal the
Value should be ignored.

While PureCSE ignores chance for optimization if Value's owner is nullptr, in the current
strength reduction algorithm, this does not hurt optimization because CSE will be eventually
applied since the strength reduction phase want to reach fixed point. But even without
this iterations, our result itself is valid since PureCSE is allowed to be conservative.

* b3/B3PureCSE.cpp:
(JSC::B3::PureCSE::findMatch):
(JSC::B3::PureCSE::process):
* b3/testb3.cpp:
(JSC::B3::testCheckSelectAndCSE):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PureCSEcpp">trunk/Source/JavaScriptCore/b3/B3PureCSE.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210918 => 210919)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-19 08:21:37 UTC (rev 210918)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-19 08:40:05 UTC (rev 210919)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2017-01-18  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [B3] B3 strength reduction could encounter Value without owner in PureCSE
+        https://bugs.webkit.org/show_bug.cgi?id=167161
+
+        Reviewed by Filip Pizlo.
+
+        PureCSE relies on the fact that all the stored Values have owner member.
+        This assumption is broken when you execute specializeSelect in B3ReduceStrength phase.
+        It clears owner of Values which are in between Select and Check to clone them to then/else
+        blocks. If these cleared Values are already stored in PureCSE map, this map poses a Value
+        with nullptr owner in PureCSE.
+
+        This patch changes PureCSE to ignore stored Values tha have nullptr owner. This even means
+        that a client of PureCSE could deliberately null the owner if they wanted to signal the
+        Value should be ignored.
+
+        While PureCSE ignores chance for optimization if Value's owner is nullptr, in the current
+        strength reduction algorithm, this does not hurt optimization because CSE will be eventually
+        applied since the strength reduction phase want to reach fixed point. But even without
+        this iterations, our result itself is valid since PureCSE is allowed to be conservative.
+
+        * b3/B3PureCSE.cpp:
+        (JSC::B3::PureCSE::findMatch):
+        (JSC::B3::PureCSE::process):
+        * b3/testb3.cpp:
+        (JSC::B3::testCheckSelectAndCSE):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2017-01-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSSegmentedVariableObject and its subclasses should have a sane destruction story
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PureCSEcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PureCSE.cpp (210918 => 210919)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PureCSE.cpp        2017-01-19 08:21:37 UTC (rev 210918)
+++ trunk/Source/JavaScriptCore/b3/B3PureCSE.cpp        2017-01-19 08:40:05 UTC (rev 210919)
</span><span class="lines">@@ -56,6 +56,8 @@
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="cx">     for (Value* match : iter-&gt;value) {
</span><ins>+        if (!match-&gt;owner)
+            continue;
</ins><span class="cx">         if (dominators.dominates(match-&gt;owner, block))
</span><span class="cx">             return match;
</span><span class="cx">     }
</span><span class="lines">@@ -75,6 +77,8 @@
</span><span class="cx">     Matches&amp; matches = m_map.add(key, Matches()).iterator-&gt;value;
</span><span class="cx"> 
</span><span class="cx">     for (Value* match : matches) {
</span><ins>+        if (!match-&gt;owner)
+            continue;
</ins><span class="cx">         if (dominators.dominates(match-&gt;owner, value-&gt;owner)) {
</span><span class="cx">             value-&gt;replaceWithIdentity(match);
</span><span class="cx">             return true;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (210918 => 210919)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2017-01-19 08:21:37 UTC (rev 210918)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2017-01-19 08:40:05 UTC (rev 210919)
</span><span class="lines">@@ -11831,6 +11831,50 @@
</span><span class="cx">     CHECK(invoke&lt;int&gt;(*code, true, false) == 667);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testCheckSelectAndCSE()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    auto* selectValue = root-&gt;appendNew&lt;Value&gt;(
+        proc, Select, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, BitAnd, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(
+                    proc, Origin(), GPRInfo::argumentGPR0)),
+            root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0xff)),
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), -42),
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 35));
+
+    auto* constant = root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 42);
+    auto* addValue = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), selectValue, constant);
+
+    CheckValue* check = root-&gt;appendNew&lt;CheckValue&gt;(proc, Check, Origin(), addValue);
+    unsigned generationCount = 0;
+    check-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp;) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+
+            generationCount++;
+            jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+
+    auto* addValue2 = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), selectValue, constant);
+
+    root-&gt;appendNewControlValue(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), addValue, addValue2));
+
+    auto code = compile(proc);
+    CHECK(generationCount == 1);
+    CHECK(invoke&lt;int&gt;(*code, true) == 0);
+    CHECK(invoke&lt;int&gt;(*code, false) == 666);
+}
+
</ins><span class="cx"> double b3Pow(double x, int y)
</span><span class="cx"> {
</span><span class="cx">     if (y &lt; 0 || y &gt; 1000)
</span><span class="lines">@@ -15433,6 +15477,7 @@
</span><span class="cx">     RUN(testSelectInvert());
</span><span class="cx">     RUN(testCheckSelect());
</span><span class="cx">     RUN(testCheckSelectCheckSelect());
</span><ins>+    RUN(testCheckSelectAndCSE());
</ins><span class="cx">     RUN_BINARY(testPowDoubleByIntegerLoop, floatingPointOperands&lt;double&gt;(), int64Operands());
</span><span class="cx"> 
</span><span class="cx">     RUN(testTruncOrHigh());
</span></span></pre>
</div>
</div>

</body>
</html>