<!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>[206682] 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/206682">206682</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-09-30 15:29:24 -0700 (Fri, 30 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3::moveConstants should be able to edit code to minimize the number of constants
https://bugs.webkit.org/show_bug.cgi?id=162764

Reviewed by Saam Barati.
        
Source/JavaScriptCore:

There are some interesting cases where we can reduce the number of constant materializations if
we teach moveConstants() how to edit code. The two examples that this patch supports are:
        
    - Loads and stores from a constant pointer. Since loads and stores get an offset for free
      and the instruction selector is really good at handling it, and since we can query Air to
      see what kinds of offsets are legal, we can sometimes avoid using a constant pointer that
      is specific to the absolute address of that load and instead pick some other constant
      that is within offset distance of ours.
            
    - Add and Sub by a constant (x + c, x - c). Since x + c = x - -c and x - c = x + -c, we can
      flip Add to Sub or vice versa if the negated constant is available.
        
This change makes moveConstants() pick the most dominant constant that works for an value. In
the case of memory accesses, it uses Air::Arg::isValidAddrForm() to work out what other
constants would work. In the case of Add/Sub, it simply looks for the negated constant. This
should result in something like a minimal number of constants since these rules always pick the
most dominant constant that works - so if an Add's constant is already most dominant then
nothing changes, but if the negated one is more dominant then it becomes a Sub.
        
This is a 0.5% speed-up on LongSpider and neutral elsewhere. It's a speed-up because the
absolute address thing reduces the number of address materializations that we have to do, while
the add/sub thing prevents us from having to materialize 0x1000000000000 to box doubles.
However, this may introduce a pathology, which I've filed a bug for: bug 162796.

* b3/B3MoveConstants.cpp:
* b3/B3MoveConstants.h:
* b3/B3UseCounts.h:
* b3/air/AirFixObviousSpills.cpp:
* b3/testb3.cpp:
(JSC::B3::testMoveConstants):
(JSC::B3::run):

Source/WTF:

I thought it would be a good idea to document the fact that dominator traversal happens in a
particular order for a reason.

* wtf/Dominators.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MoveConstantscpp">trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MoveConstantsh">trunk/Source/JavaScriptCore/b3/B3MoveConstants.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3UseCountsh">trunk/Source/JavaScriptCore/b3/B3UseCounts.h</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="#trunkSourceWTFwtfDominatorsh">trunk/Source/WTF/wtf/Dominators.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2016-09-30  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3::moveConstants should be able to edit code to minimize the number of constants
+        https://bugs.webkit.org/show_bug.cgi?id=162764
+
+        Reviewed by Saam Barati.
+        
+        There are some interesting cases where we can reduce the number of constant materializations if
+        we teach moveConstants() how to edit code. The two examples that this patch supports are:
+        
+            - Loads and stores from a constant pointer. Since loads and stores get an offset for free
+              and the instruction selector is really good at handling it, and since we can query Air to
+              see what kinds of offsets are legal, we can sometimes avoid using a constant pointer that
+              is specific to the absolute address of that load and instead pick some other constant
+              that is within offset distance of ours.
+            
+            - Add and Sub by a constant (x + c, x - c). Since x + c = x - -c and x - c = x + -c, we can
+              flip Add to Sub or vice versa if the negated constant is available.
+        
+        This change makes moveConstants() pick the most dominant constant that works for an value. In
+        the case of memory accesses, it uses Air::Arg::isValidAddrForm() to work out what other
+        constants would work. In the case of Add/Sub, it simply looks for the negated constant. This
+        should result in something like a minimal number of constants since these rules always pick the
+        most dominant constant that works - so if an Add's constant is already most dominant then
+        nothing changes, but if the negated one is more dominant then it becomes a Sub.
+        
+        This is a 0.5% speed-up on LongSpider and neutral elsewhere. It's a speed-up because the
+        absolute address thing reduces the number of address materializations that we have to do, while
+        the add/sub thing prevents us from having to materialize 0x1000000000000 to box doubles.
+        However, this may introduce a pathology, which I've filed a bug for: bug 162796.
+
+        * b3/B3MoveConstants.cpp:
+        * b3/B3MoveConstants.h:
+        * b3/B3UseCounts.h:
+        * b3/air/AirFixObviousSpills.cpp:
+        * b3/testb3.cpp:
+        (JSC::B3::testMoveConstants):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2016-09-30  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix modules tests after r206653 handle breakpoint locations in import/export statements
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MoveConstantscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -134,10 +134,31 @@
</span><span class="cx">         for (BasicBlock* block : m_proc) {
</span><span class="cx">             for (unsigned valueIndex = 0; valueIndex &lt; block-&gt;size(); ++valueIndex) {
</span><span class="cx">                 Value* value = block-&gt;at(valueIndex);
</span><del>-                for (Value* child : value-&gt;children()) {
</del><ins>+                
+                // This finds the outermost (best) block last. So, the functor overrides the result
+                // each time it finds something acceptable.
+                auto findBestConstant = [&amp;] (const auto&amp; predicate) -&gt; Value* {
+                    Value* result = nullptr;
+                    dominators.forAllDominatorsOf(
+                        block,
+                        [&amp;] (BasicBlock* dominator) {
+                            for (Value* value : materializations[dominator]) {
+                                if (predicate(value)) {
+                                    result = value;
+                                    break;
+                                }
+                            }
+                        });
+                    return result;
+                };
+                
+                // We call this when we have found a constant that we'd like to use. It's possible that
+                // we have computed that the constant should be meterialized in this block, but we
+                // haven't inserted it yet. This inserts the constant if necessary.
+                auto materialize = [&amp;] (Value* child) {
</ins><span class="cx">                     ValueKey key = child-&gt;key();
</span><span class="cx">                     if (!filter(key))
</span><del>-                        continue;
</del><ins>+                        return;
</ins><span class="cx"> 
</span><span class="cx">                     // If we encounter a fast constant, then it must be canonical, since we already
</span><span class="cx">                     // got rid of the non-canonical ones.
</span><span class="lines">@@ -146,7 +167,7 @@
</span><span class="cx">                     if (child-&gt;owner != block) {
</span><span class="cx">                         // This constant isn't our problem. It's going to be materialized in another
</span><span class="cx">                         // block.
</span><del>-                        continue;
</del><ins>+                        return;
</ins><span class="cx">                     }
</span><span class="cx">                     
</span><span class="cx">                     // We're supposed to materialize this constant in this block, and we haven't
</span><span class="lines">@@ -153,7 +174,81 @@
</span><span class="cx">                     // done it yet.
</span><span class="cx">                     m_insertionSet.insertValue(valueIndex, child);
</span><span class="cx">                     child-&gt;owner = nullptr;
</span><ins>+                };
+                
+                if (MemoryValue* memoryValue = value-&gt;as&lt;MemoryValue&gt;()) {
+                    Value* pointer = memoryValue-&gt;lastChild();
+                    if (pointer-&gt;hasIntPtr() &amp;&amp; filter(pointer-&gt;key())) {
+                        auto desiredOffset = [&amp;] (Value* otherPointer) -&gt; intptr_t {
+                            // We would turn this:
+                            //
+                            //     Load(@p, offset = c)
+                            //
+                            // into this:
+                            //
+                            //     Load(@q, offset = ?)
+                            //
+                            // The offset should be c + @p - @q, because then we're loading from:
+                            //
+                            //     @q + c + @p - @q
+                            uintptr_t c = static_cast&lt;uintptr_t&gt;(static_cast&lt;intptr_t&gt;(memoryValue-&gt;offset()));
+                            uintptr_t p = pointer-&gt;asIntPtr();
+                            uintptr_t q = otherPointer-&gt;asIntPtr();
+                            return c + p - q;
+                        };
+                        
+                        Value* bestPointer = findBestConstant(
+                            [&amp;] (Value* candidatePointer) -&gt; bool {
+                                if (!candidatePointer-&gt;hasIntPtr())
+                                    return false;
+                                
+                                intptr_t offset = desiredOffset(candidatePointer);
+                                if (!B3::isRepresentableAs&lt;int32_t&gt;(static_cast&lt;int64_t&gt;(offset)))
+                                    return false;
+                                return Air::Arg::isValidAddrForm(
+                                    static_cast&lt;int32_t&gt;(offset),
+                                    Air::Arg::widthForBytes(memoryValue-&gt;accessByteSize()));
+                            });
+                        
+                        if (bestPointer) {
+                            memoryValue-&gt;lastChild() = bestPointer;
+                            memoryValue-&gt;setOffset(desiredOffset(bestPointer));
+                        }
+                    }
+                } else {
+                    switch (value-&gt;opcode()) {
+                    case Add:
+                    case Sub: {
+                        Value* addend = value-&gt;child(1);
+                        if (!addend-&gt;hasInt() || !filter(addend-&gt;key()))
+                            break;
+                        int64_t addendConst = addend-&gt;asInt();
+                        Value* bestAddend = findBestConstant(
+                            [&amp;] (Value* candidateAddend) -&gt; bool {
+                                if (candidateAddend-&gt;type() != addend-&gt;type())
+                                    return false;
+                                if (!candidateAddend-&gt;hasInt())
+                                    return false;
+                                return candidateAddend == addend
+                                    || candidateAddend-&gt;asInt() == -addendConst;
+                            });
+                        if (!bestAddend || bestAddend == addend)
+                            break;
+                        materialize(value-&gt;child(0));
+                        materialize(bestAddend);
+                        value-&gt;replaceWithIdentity(
+                            m_insertionSet.insert&lt;Value&gt;(
+                                valueIndex, value-&gt;opcode() == Add ? Sub : Add, value-&gt;origin(),
+                                value-&gt;child(0), bestAddend));
+                        break;
+                    }
+                    default:
+                        break;
+                    }
</ins><span class="cx">                 }
</span><ins>+                
+                for (Value* child : value-&gt;children())
+                    materialize(child);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // We may have some constants that need to be materialized right at the end of this
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MoveConstantsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MoveConstants.h (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MoveConstants.h        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/JavaScriptCore/b3/B3MoveConstants.h        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> // Moves large constants around, with the goal of placing them in the optimal points in the program.
</span><span class="cx"> 
</span><del>-void moveConstants(Procedure&amp;);
</del><ins>+JS_EXPORT_PRIVATE void moveConstants(Procedure&amp;);
</ins><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3UseCountsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3UseCounts.h (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3UseCounts.h        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/JavaScriptCore/b3/B3UseCounts.h        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -36,8 +36,8 @@
</span><span class="cx"> 
</span><span class="cx"> class UseCounts {
</span><span class="cx"> public:
</span><del>-    UseCounts(Procedure&amp;);
-    ~UseCounts();
</del><ins>+    JS_EXPORT_PRIVATE UseCounts(Procedure&amp;);
+    JS_EXPORT_PRIVATE ~UseCounts();
</ins><span class="cx"> 
</span><span class="cx">     unsigned numUses(Value* value) const { return m_counts[value].numUses; }
</span><span class="cx">     unsigned numUsingInstructions(Value* value) const { return m_counts[value].numUsingInstructions; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> #include &quot;B3LowerToAir.h&quot;
</span><span class="cx"> #include &quot;B3MathExtras.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><ins>+#include &quot;B3MoveConstants.h&quot;
</ins><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><span class="cx"> #include &quot;B3ReduceStrength.h&quot;
</span><span class="cx"> #include &quot;B3SlotBaseValue.h&quot;
</span><span class="lines">@@ -49,6 +50,7 @@
</span><span class="cx"> #include &quot;B3StackmapGenerationParams.h&quot;
</span><span class="cx"> #include &quot;B3SwitchValue.h&quot;
</span><span class="cx"> #include &quot;B3UpsilonValue.h&quot;
</span><ins>+#include &quot;B3UseCounts.h&quot;
</ins><span class="cx"> #include &quot;B3Validate.h&quot;
</span><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> #include &quot;B3VariableValue.h&quot;
</span><span class="lines">@@ -13106,6 +13108,67 @@
</span><span class="cx">     checkDoesNotUseInstruction(*code, &quot;dmb    ishst&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testMoveConstants()
+{
+    auto check = [] (Procedure&amp; proc) {
+        proc.resetReachability();
+        
+        if (shouldBeVerbose()) {
+            dataLog(&quot;IR before:\n&quot;);
+            dataLog(proc);
+        }
+        
+        moveConstants(proc);
+        
+        if (shouldBeVerbose()) {
+            dataLog(&quot;IR after:\n&quot;);
+            dataLog(proc);
+        }
+        
+        UseCounts useCounts(proc);
+        unsigned count = 0;
+        for (Value* value : proc.values()) {
+            if (useCounts.numUses(value) &amp;&amp; value-&gt;hasInt64())
+                count++;
+        }
+        
+        if (count == 1)
+            return;
+        
+        crashLock.lock();
+        dataLog(&quot;Fail in testMoveConstants: got more than one Const64:\n&quot;);
+        dataLog(proc);
+        CRASH();
+    };
+
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* a = root-&gt;appendNew&lt;MemoryValue&gt;(
+            proc, Load, Int32, Origin(), 
+            root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 0x123412341234));
+        Value* b = root-&gt;appendNew&lt;MemoryValue&gt;(
+            proc, Load, Int32, Origin(),
+            root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 0x123412341334));
+        root-&gt;appendNew&lt;CCallValue&gt;(proc, Void, Origin(), a, b);
+        root-&gt;appendNew&lt;Value&gt;(proc, Return, Origin());
+        check(proc);
+    }
+    
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* x = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* a = root-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(), x, root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 0x123412341234));
+        Value* b = root-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(), x, root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), -0x123412341234));
+        root-&gt;appendNew&lt;CCallValue&gt;(proc, Void, Origin(), a, b);
+        root-&gt;appendNew&lt;Value&gt;(proc, Return, Origin());
+        check(proc);
+    }
+}
+
</ins><span class="cx"> // Make sure the compiler does not try to optimize anything out.
</span><span class="cx"> NEVER_INLINE double zero()
</span><span class="cx"> {
</span><span class="lines">@@ -14546,6 +14609,7 @@
</span><span class="cx">     RUN(testMemoryFence());
</span><span class="cx">     RUN(testStoreFence());
</span><span class="cx">     RUN(testLoadFence());
</span><ins>+    RUN(testMoveConstants());
</ins><span class="cx">     
</span><span class="cx">     if (tasks.isEmpty())
</span><span class="cx">         usage();
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/WTF/ChangeLog        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-09-30  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3::moveConstants should be able to edit code to minimize the number of constants
+        https://bugs.webkit.org/show_bug.cgi?id=162764
+
+        Reviewed by Saam Barati.
+        
+        I thought it would be a good idea to document the fact that dominator traversal happens in a
+        particular order for a reason.
+
+        * wtf/Dominators.h:
+
</ins><span class="cx"> 2016-09-29  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Air should have a way of expressing additional instruction flags
</span></span></pre></div>
<a id="trunkSourceWTFwtfDominatorsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Dominators.h (206681 => 206682)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Dominators.h        2016-09-30 22:21:59 UTC (rev 206681)
+++ trunk/Source/WTF/wtf/Dominators.h        2016-09-30 22:29:24 UTC (rev 206682)
</span><span class="lines">@@ -136,6 +136,9 @@
</span><span class="cx">             functor(block);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    // Note: This will visit the dominators starting with the 'to' node and moving up the idom tree
+    // until it gets to the root. Some clients of this function, like B3::moveConstants(), rely on this
+    // order.
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     void forAllDominatorsOf(typename Graph::Node to, const Functor&amp; functor) const
</span><span class="cx">     {
</span></span></pre>
</div>
</div>

</body>
</html>