<!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>[194402] 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/194402">194402</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-12-23 16:26:04 -0800 (Wed, 23 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>FTL B3 should be able to run crypto-sha1 in eager mode
https://bugs.webkit.org/show_bug.cgi?id=152539

Reviewed by Saam Barati.

This patch contains one real bug fix and some other fixes that are primarily there for sanity
because I don't believe they are symptomatic.

The real fix is the instruction selector's handling of Phi. It was assuming that the correct
lowering of Phi is to do nothing and the correct lowering of Upsilon is to store into the tmp
that the Phi uses. But this fails for code patterns like:

    @a = Phi()
    Upsilon(@x, ^a)
    use(@a) // this should see the value that @a had at the point that &quot;@a = Phi()&quot; executed.

This arises when we have a lot of Upsilons in a row and they are trying to perform a
shuffling. Prior to this change, &quot;use(@a)&quot; would see the new value of @a, i.e. @x. That's
wrong. So, this changes the lowering to make each Phi have a special shadow Tmp, and Upsilon
stores to it while Phi loads from it. Most of these assignments get copy-propagated by IRC,
so it doesn't really hurt us. I couldn't find any benchmarks that slowed down because of
this. In fact, I believe that the only time that this would lead to extra interference or
extra assignments is when it's actually needed to be correct.

This also contains other fixes, which are probably not for real bugs, but they make me feel
all warm and fuzzy:

- spillEverything() works again.  Previously, it didn't have all of IRC's smarts for handling
  a spill of a ZDef.  I fixed this by creating a helper phase that finds all subwidth ZDefs
  to spill slots and amends them with zero-fills of the top bits.

- IRC no longer requires precise TmpWidth analysis.  Previously, if TmpWidth gave pessimistic
  results, the subwidth ZDef bug would return.  That probably means that it was never fixed
  to begin with, since it's totally cool for just a single def or use of a tmp to cause it
  to become pessimistic. But there may still have been some subwidth ZDefs.  The way that I
  fixed this bug is to have IRC also run the ZDef fixup code that spillEverything() uses.
  This is abstracted behind the beautifully named Air::fixSpillSlotZDef().

- B3::validate() does dominance checks!  So, if you shoot yourself in the foot by using
  something before defining it, validate() will tell you.

- Air::TmpWidth is now easy to &quot;turn off&quot; - i.e. to make it go fully conservative. It's not
  an Option; you have to hack code. But that's better than nothing, and it's consistent with
  what we do for other super-internal compiler options that we use rarely.

- You can now run spillEverything() without hacking code.  Just use
  Options::airSpillSeverything().

* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::LowerToAir):
(JSC::B3::Air::LowerToAir::run):
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Validate.cpp:
* b3/air/AirCode.h:
(JSC::B3::Air::Code::specials):
(JSC::B3::Air::Code::forAllTmps):
(JSC::B3::Air::Code::isFastTmp):
* b3/air/AirFixSpillSlotZDef.h: Added.
(JSC::B3::Air::fixSpillSlotZDef):
* b3/air/AirGenerate.cpp:
(JSC::B3::Air::prepareForGeneration):
* b3/air/AirIteratedRegisterCoalescing.cpp:
* b3/air/AirSpillEverything.cpp:
(JSC::B3::Air::spillEverything):
* b3/air/AirTmpWidth.cpp:
(JSC::B3::Air::TmpWidth::recompute):
* jit/JITOperations.cpp:
* runtime/Options.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodeh">trunk/Source/JavaScriptCore/b3/air/AirCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirGeneratecpp">trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirIteratedRegisterCoalescingcpp">trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp">trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpWidthcpp">trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirFixSpillSlotZDefh">trunk/Source/JavaScriptCore/b3/air/AirFixSpillSlotZDef.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -1,5 +1,77 @@
</span><span class="cx"> 2015-12-23  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        FTL B3 should be able to run crypto-sha1 in eager mode
+        https://bugs.webkit.org/show_bug.cgi?id=152539
+
+        Reviewed by Saam Barati.
+
+        This patch contains one real bug fix and some other fixes that are primarily there for sanity
+        because I don't believe they are symptomatic.
+
+        The real fix is the instruction selector's handling of Phi. It was assuming that the correct
+        lowering of Phi is to do nothing and the correct lowering of Upsilon is to store into the tmp
+        that the Phi uses. But this fails for code patterns like:
+
+            @a = Phi()
+            Upsilon(@x, ^a)
+            use(@a) // this should see the value that @a had at the point that &quot;@a = Phi()&quot; executed.
+
+        This arises when we have a lot of Upsilons in a row and they are trying to perform a
+        shuffling. Prior to this change, &quot;use(@a)&quot; would see the new value of @a, i.e. @x. That's
+        wrong. So, this changes the lowering to make each Phi have a special shadow Tmp, and Upsilon
+        stores to it while Phi loads from it. Most of these assignments get copy-propagated by IRC,
+        so it doesn't really hurt us. I couldn't find any benchmarks that slowed down because of
+        this. In fact, I believe that the only time that this would lead to extra interference or
+        extra assignments is when it's actually needed to be correct.
+
+        This also contains other fixes, which are probably not for real bugs, but they make me feel
+        all warm and fuzzy:
+
+        - spillEverything() works again.  Previously, it didn't have all of IRC's smarts for handling
+          a spill of a ZDef.  I fixed this by creating a helper phase that finds all subwidth ZDefs
+          to spill slots and amends them with zero-fills of the top bits.
+
+        - IRC no longer requires precise TmpWidth analysis.  Previously, if TmpWidth gave pessimistic
+          results, the subwidth ZDef bug would return.  That probably means that it was never fixed
+          to begin with, since it's totally cool for just a single def or use of a tmp to cause it
+          to become pessimistic. But there may still have been some subwidth ZDefs.  The way that I
+          fixed this bug is to have IRC also run the ZDef fixup code that spillEverything() uses.
+          This is abstracted behind the beautifully named Air::fixSpillSlotZDef().
+
+        - B3::validate() does dominance checks!  So, if you shoot yourself in the foot by using
+          something before defining it, validate() will tell you.
+
+        - Air::TmpWidth is now easy to &quot;turn off&quot; - i.e. to make it go fully conservative. It's not
+          an Option; you have to hack code. But that's better than nothing, and it's consistent with
+          what we do for other super-internal compiler options that we use rarely.
+
+        - You can now run spillEverything() without hacking code.  Just use
+          Options::airSpillSeverything().
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::LowerToAir):
+        (JSC::B3::Air::LowerToAir::run):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3Validate.cpp:
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::specials):
+        (JSC::B3::Air::Code::forAllTmps):
+        (JSC::B3::Air::Code::isFastTmp):
+        * b3/air/AirFixSpillSlotZDef.h: Added.
+        (JSC::B3::Air::fixSpillSlotZDef):
+        * b3/air/AirGenerate.cpp:
+        (JSC::B3::Air::prepareForGeneration):
+        * b3/air/AirIteratedRegisterCoalescing.cpp:
+        * b3/air/AirSpillEverything.cpp:
+        (JSC::B3::Air::spillEverything):
+        * b3/air/AirTmpWidth.cpp:
+        (JSC::B3::Air::TmpWidth::recompute):
+        * jit/JITOperations.cpp:
+        * runtime/Options.h:
+
+2015-12-23  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Need a story for platform-specific Args
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=152529
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -374,6 +374,7 @@
</span><span class="cx">                 0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F493AF816D0CAD10084508B /* SourceProvider.cpp */; };
</span><span class="cx">                 0F4B94DC17B9F07500DD03A4 /* TypedArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4B94DB17B9F07500DD03A4 /* TypedArrayInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F4C91661C29F4F2004341A6 /* B3OriginDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4C91651C29F4F2004341A6 /* B3OriginDump.h */; };
</span><ins>+                0F4C91681C2B3D68004341A6 /* AirFixSpillSlotZDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4C91671C2B3D68004341A6 /* AirFixSpillSlotZDef.h */; };
</ins><span class="cx">                 0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */; };
</span><span class="cx">                 0F4F29E018B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */; };
</span><span class="cx">                 0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */; };
</span><span class="lines">@@ -2508,6 +2509,7 @@
</span><span class="cx">                 0F493AF816D0CAD10084508B /* SourceProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SourceProvider.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F4B94DB17B9F07500DD03A4 /* TypedArrayInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F4C91651C29F4F2004341A6 /* B3OriginDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3OriginDump.h; path = b3/B3OriginDump.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F4C91671C2B3D68004341A6 /* AirFixSpillSlotZDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirFixSpillSlotZDef.h; path = b3/air/AirFixSpillSlotZDef.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStaticExecutionCountEstimationPhase.cpp; path = dfg/DFGStaticExecutionCountEstimationPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStaticExecutionCountEstimationPhase.h; path = dfg/DFGStaticExecutionCountEstimationPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureClobberState.h; path = dfg/DFGStructureClobberState.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4776,6 +4778,7 @@
</span><span class="cx">                                 0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */,
</span><span class="cx">                                 262D85B41C0D650F006ACB61 /* AirFixPartialRegisterStalls.cpp */,
</span><span class="cx">                                 262D85B51C0D650F006ACB61 /* AirFixPartialRegisterStalls.h */,
</span><ins>+                                0F4C91671C2B3D68004341A6 /* AirFixSpillSlotZDef.h */,
</ins><span class="cx">                                 0FEC85521BDACDC70080FF74 /* AirFrequentedBlock.h */,
</span><span class="cx">                                 0FEC85531BDACDC70080FF74 /* AirGenerate.cpp */,
</span><span class="cx">                                 0FEC85541BDACDC70080FF74 /* AirGenerate.h */,
</span><span class="lines">@@ -7216,6 +7219,7 @@
</span><span class="cx">                                 DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */,
</span><span class="cx">                                 0FBE0F7516C1DB0B0082C5E8 /* DFGPredictionInjectionPhase.h in Headers */,
</span><span class="cx">                                 0FFFC95E14EF90B700C72532 /* DFGPredictionPropagationPhase.h in Headers */,
</span><ins>+                                0F4C91681C2B3D68004341A6 /* AirFixSpillSlotZDef.h in Headers */,
</ins><span class="cx">                                 0F3E01AB19D353A500F61B7F /* DFGPrePostNumbering.h in Headers */,
</span><span class="cx">                                 0F2B9CED19D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h in Headers */,
</span><span class="cx">                                 0FFC92161B94FB3E0071DD66 /* DFGPropertyTypeKey.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -64,6 +64,7 @@
</span><span class="cx"> public:
</span><span class="cx">     LowerToAir(Procedure&amp; procedure)
</span><span class="cx">         : m_valueToTmp(procedure.values().size())
</span><ins>+        , m_phiToTmp(procedure.values().size())
</ins><span class="cx">         , m_blockToBlock(procedure.size())
</span><span class="cx">         , m_useCounts(procedure)
</span><span class="cx">         , m_phiChildren(procedure)
</span><span class="lines">@@ -76,9 +77,21 @@
</span><span class="cx">     {
</span><span class="cx">         for (B3::BasicBlock* block : m_procedure)
</span><span class="cx">             m_blockToBlock[block] = m_code.addBlock(block-&gt;frequency());
</span><ins>+        
</ins><span class="cx">         for (Value* value : m_procedure.values()) {
</span><del>-            if (StackSlotValue* stackSlotValue = value-&gt;as&lt;StackSlotValue&gt;())
</del><ins>+            switch (value-&gt;opcode()) {
+            case Phi: {
+                m_phiToTmp[value] = m_code.newTmp(Arg::typeForB3Type(value-&gt;type()));
+                break;
+            }
+            case B3::StackSlot: {
+                StackSlotValue* stackSlotValue = value-&gt;as&lt;StackSlotValue&gt;();
</ins><span class="cx">                 m_stackToStack.add(stackSlotValue, m_code.addStackSlot(stackSlotValue));
</span><ins>+                break;
+            }
+            default:
+                break;
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         m_procedure.resetValueOwners(); // Used by crossesInterference().
</span><span class="lines">@@ -2126,12 +2139,17 @@
</span><span class="cx">             Value* value = m_value-&gt;child(0);
</span><span class="cx">             append(
</span><span class="cx">                 relaxedMoveForType(value-&gt;type()), immOrTmp(value),
</span><del>-                tmp(m_value-&gt;as&lt;UpsilonValue&gt;()-&gt;phi()));
</del><ins>+                m_phiToTmp[m_value-&gt;as&lt;UpsilonValue&gt;()-&gt;phi()]);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case Phi: {
</span><del>-            // Our semantics are determined by Upsilons, so we have nothing to do here.
</del><ins>+            // Snapshot the value of the Phi. It may change under us because you could do:
+            // a = Phi()
+            // Upsilon(@x, ^a)
+            // @a =&gt; this should get the value of the Phi before the Upsilon, i.e. not @x.
+
+            append(relaxedMoveForType(m_value-&gt;type()), m_phiToTmp[m_value], tmp(m_value));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2209,6 +2227,7 @@
</span><span class="cx"> 
</span><span class="cx">     IndexSet&lt;Value&gt; m_locked; // These are values that will have no Tmp in Air.
</span><span class="cx">     IndexMap&lt;Value, Tmp&gt; m_valueToTmp; // These are values that must have a Tmp in Air. We say that a Value* with a non-null Tmp is &quot;pinned&quot;.
</span><ins>+    IndexMap&lt;Value, Tmp&gt; m_phiToTmp; // Each Phi gets its own Tmp.
</ins><span class="cx">     IndexMap&lt;B3::BasicBlock, Air::BasicBlock*&gt; m_blockToBlock;
</span><span class="cx">     HashMap&lt;StackSlotValue*, Air::StackSlot*&gt; m_stackToStack;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;B3ArgumentRegValue.h&quot;
</span><span class="cx"> #include &quot;B3BasicBlockInlines.h&quot;
</span><ins>+#include &quot;B3Dominators.h&quot;
</ins><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><span class="cx"> #include &quot;B3StackSlotValue.h&quot;
</span><span class="lines">@@ -62,11 +63,17 @@
</span><span class="cx">         HashSet&lt;BasicBlock*&gt; blocks;
</span><span class="cx">         HashSet&lt;Value*&gt; valueInProc;
</span><span class="cx">         HashMap&lt;Value*, unsigned&gt; valueInBlock;
</span><ins>+        HashMap&lt;Value*, BasicBlock*&gt; valueOwner;
+        HashMap&lt;Value*, unsigned&gt; valueIndex;
</ins><span class="cx"> 
</span><span class="cx">         for (BasicBlock* block : m_procedure) {
</span><span class="cx">             blocks.add(block);
</span><del>-            for (Value* value : *block)
</del><ins>+            for (unsigned i = 0; i &lt; block-&gt;size(); ++i) {
+                Value* value = block-&gt;at(i);
</ins><span class="cx">                 valueInBlock.add(value, 0).iterator-&gt;value++;
</span><ins>+                valueOwner.add(value, block);
+                valueIndex.add(value, i);
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         for (Value* value : m_procedure.values())
</span><span class="lines">@@ -79,10 +86,17 @@
</span><span class="cx">             VALIDATE(entry.value == 1, (&quot;At &quot;, *entry.key));
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // Compute dominators ourselves to avoid perturbing Procedure.
+        Dominators dominators(m_procedure);
+
</ins><span class="cx">         for (Value* value : valueInProc) {
</span><span class="cx">             for (Value* child : value-&gt;children()) {
</span><span class="cx">                 VALIDATE(child, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(valueInProc.contains(child), (&quot;At &quot;, *value, &quot;-&gt;&quot;, pointerDump(child)));
</span><ins>+                if (valueOwner.get(child) == valueOwner.get(value))
+                    VALIDATE(valueIndex.get(value) &gt; valueIndex.get(child), (&quot;At &quot;, *value, &quot;-&gt;&quot;, pointerDump(child)));
+                else
+                    VALIDATE(dominators.dominates(valueOwner.get(child), valueOwner.get(value)), (&quot;at &quot;, *value, &quot;-&gt;&quot;, pointerDump(child)));
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.h (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.h        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.h        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -57,6 +57,9 @@
</span><span class="cx"> 
</span><span class="cx">     BasicBlock* addBlock(double frequency = 1);
</span><span class="cx"> 
</span><ins>+    // Note that you can rely on stack slots always getting indices that are larger than the index
+    // of any prior stack slot. In fact, all stack slots you create in the future will have an index
+    // that is &gt;= stackSlots().size().
</ins><span class="cx">     StackSlot* addStackSlot(unsigned byteSize, StackSlotKind, StackSlotValue* = nullptr);
</span><span class="cx">     StackSlot* addStackSlot(StackSlotValue*);
</span><span class="cx"> 
</span><span class="lines">@@ -291,6 +294,15 @@
</span><span class="cx"> 
</span><span class="cx">     SpecialsCollection specials() const { return SpecialsCollection(*this); }
</span><span class="cx"> 
</span><ins>+    template&lt;typename Callback&gt;
+    void forAllTmps(const Callback&amp; callback) const
+    {
+        for (unsigned i = m_numGPTmps; i--;)
+            callback(Tmp::gpTmpForIndex(i));
+        for (unsigned i = m_numFPTmps; i--;)
+            callback(Tmp::fpTmpForIndex(i));
+    }
+
</ins><span class="cx">     void addFastTmp(Tmp);
</span><span class="cx">     bool isFastTmp(Tmp tmp) const { return m_fastTmps.contains(tmp); }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirFixSpillSlotZDefh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirFixSpillSlotZDef.h (0 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirFixSpillSlotZDef.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirFixSpillSlotZDef.h        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef AirFixSpillSlotZDef_h
+#define AirFixSpillSlotZDef_h
+
+#include &quot;AirCode.h&quot;
+#include &quot;AirInsertionSet.h&quot;
+#include &quot;AirInstInlines.h&quot;
+
+namespace JSC { namespace B3 { namespace Air {
+
+template&lt;typename IsSpillSlot&gt;
+void fixSpillSlotZDef(Code&amp; code, const IsSpillSlot&amp; isSpillSlot)
+{
+    // We could have introduced ZDef's to StackSlots that are wider than the def. In that case, we
+    // need to emit code to zero-fill the top bits of the StackSlot.
+    InsertionSet insertionSet(code);
+    for (BasicBlock* block : code) {
+        for (unsigned instIndex = 0; instIndex &lt; block-&gt;size(); ++instIndex) {
+            Inst&amp; inst = block-&gt;at(instIndex);
+
+            inst.forEachArg(
+                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type, Arg::Width width) {
+                    if (!Arg::isZDef(role))
+                        return;
+                    if (!arg.isStack())
+                        return;
+                    if (!isSpillSlot(arg.stackSlot()))
+                        return;
+                    if (arg.stackSlot()-&gt;byteSize() == Arg::bytes(width))
+                        return;
+
+                    // Currently we only handle this simple case because it's the only one that
+                    // arises: ZDef's are only 32-bit right now. So, when we hit these
+                    // assertions it means that we need to implement those other kinds of zero
+                    // fills.
+                    RELEASE_ASSERT(arg.stackSlot()-&gt;byteSize() == 8);
+                    RELEASE_ASSERT(width == Arg::Width32);
+
+                    // We rely on the fact that there must be some way to move zero to a memory
+                    // location without first burning a register. On ARM, we would do this using
+                    // zr.
+                    RELEASE_ASSERT(isValidForm(Move32, Arg::Imm, Arg::Stack));
+                    insertionSet.insert(
+                        instIndex + 1, Move32, inst.origin, Arg::imm(0), arg.withOffset(4));
+                });
+        }
+        insertionSet.execute(block);
+    }
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // AirFixSpillSlotZDef_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirGeneratecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     // After this phase, every Tmp has a reg.
</span><span class="cx">     //
</span><span class="cx">     // For debugging, you can use spillEverything() to put everything to the stack between each Inst.
</span><del>-    if (false)
</del><ins>+    if (Options::airSpillsEverything())
</ins><span class="cx">         spillEverything(code);
</span><span class="cx">     else
</span><span class="cx">         iteratedRegisterCoalescing(code);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirIteratedRegisterCoalescingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirCode.h&quot;
</span><ins>+#include &quot;AirFixSpillSlotZDef.h&quot;
</ins><span class="cx"> #include &quot;AirInsertionSet.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><span class="cx"> #include &quot;AirLiveness.h&quot;
</span><span class="lines">@@ -1164,6 +1165,7 @@
</span><span class="cx">     void addSpillAndFill(const ColoringAllocator&lt;type&gt;&amp; allocator, HashSet&lt;unsigned&gt;&amp; unspillableTmps)
</span><span class="cx">     {
</span><span class="cx">         HashMap&lt;Tmp, StackSlot*&gt; stackSlots;
</span><ins>+        unsigned newStackSlotThreshold = m_code.stackSlots().size();
</ins><span class="cx">         for (Tmp tmp : allocator.spilledTmps()) {
</span><span class="cx">             // All the spilled values become unspillable.
</span><span class="cx">             unspillableTmps.add(AbsoluteTmpMapper&lt;type&gt;::absoluteIndex(tmp));
</span><span class="lines">@@ -1260,6 +1262,12 @@
</span><span class="cx">                 });
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+
+        fixSpillSlotZDef(
+            m_code,
+            [&amp;] (StackSlot* stackSlot) -&gt; bool {
+                return stackSlot-&gt;index() &gt;= newStackSlotThreshold;
+            });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Code&amp; m_code;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirCode.h&quot;
</span><ins>+#include &quot;AirFixSpillSlotZDef.h&quot;
</ins><span class="cx"> #include &quot;AirInsertionSet.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><span class="cx"> #include &quot;AirLiveness.h&quot;
</span><span class="lines">@@ -86,6 +87,7 @@
</span><span class="cx"> 
</span><span class="cx">     // Allocate a stack slot for each tmp.
</span><span class="cx">     Vector&lt;StackSlot*&gt; allStackSlots[Arg::numTypes];
</span><ins>+    unsigned newStackSlotThreshold = code.stackSlots().size();
</ins><span class="cx">     for (unsigned typeIndex = 0; typeIndex &lt; Arg::numTypes; ++typeIndex) {
</span><span class="cx">         Vector&lt;StackSlot*&gt;&amp; stackSlots = allStackSlots[typeIndex];
</span><span class="cx">         Arg::Type type = static_cast&lt;Arg::Type&gt;(typeIndex);
</span><span class="lines">@@ -109,7 +111,7 @@
</span><span class="cx">                     if (arg.isReg())
</span><span class="cx">                         continue;
</span><span class="cx"> 
</span><del>-                    if (inst.admitsStack(i)) { 
</del><ins>+                    if (inst.admitsStack(i)) {
</ins><span class="cx">                         StackSlot* stackSlot = allStackSlots[arg.type()][arg.tmpIndex()];
</span><span class="cx">                         arg = Arg::stack(stackSlot);
</span><span class="cx">                         continue;
</span><span class="lines">@@ -184,6 +186,12 @@
</span><span class="cx">         }
</span><span class="cx">         insertionSet.execute(block);
</span><span class="cx">     }
</span><ins>+
+    fixSpillSlotZDef(
+        code,
+        [&amp;] (StackSlot* stackSlot) -&gt; bool {
+            return stackSlot-&gt;index() &gt;= newStackSlotThreshold;
+        });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } } // namespace JSC::B3::Air
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpWidthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -48,17 +48,31 @@
</span><span class="cx"> 
</span><span class="cx"> void TmpWidth::recompute(Code&amp; code)
</span><span class="cx"> {
</span><ins>+    // Set this to true to cause this analysis to always return pessimistic results.
+    const bool beCareful = false;
+    
</ins><span class="cx">     m_width.clear();
</span><span class="cx">     
</span><ins>+    auto assumeTheWorst = [&amp;] (Tmp tmp) {
+        Widths&amp; widths = m_width.add(tmp, Widths()).iterator-&gt;value;
+        Arg::Type type = Arg(tmp).type();
+        widths.use = Arg::conservativeWidth(type);
+        widths.def = Arg::conservativeWidth(type);
+    };
+    
</ins><span class="cx">     // Assume the worst for registers.
</span><span class="cx">     RegisterSet::allRegisters().forEach(
</span><span class="cx">         [&amp;] (Reg reg) {
</span><del>-            Widths&amp; widths = m_width.add(Tmp(reg), Widths()).iterator-&gt;value;
-            Arg::Type type = Arg(Tmp(reg)).type();
-            widths.use = Arg::conservativeWidth(type);
-            widths.def = Arg::conservativeWidth(type);
</del><ins>+            assumeTheWorst(Tmp(reg));
</ins><span class="cx">         });
</span><del>-    
</del><ins>+
+    if (beCareful) {
+        code.forAllTmps(assumeTheWorst);
+        
+        // We fall through because the fixpoint that follows can only make things even more
+        // conservative. This mode isn't meant to be fast, just safe.
+    }
+
</ins><span class="cx">     // Now really analyze everything but Move's over Tmp's, but set aside those Move's so we can find
</span><span class="cx">     // them quickly during the fixpoint below. Note that we can make this analysis stronger by
</span><span class="cx">     // recognizing more kinds of Move's or anything that has Move-like behavior, though it's probably not
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (194401 => 194402)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2015-12-24 00:14:13 UTC (rev 194401)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2015-12-24 00:26:04 UTC (rev 194402)
</span><span class="lines">@@ -340,6 +340,7 @@
</span><span class="cx">     \
</span><span class="cx">     v(bool, logB3PhaseTimes, false, nullptr) \
</span><span class="cx">     v(double, rareBlockPenalty, 0.001, nullptr) \
</span><ins>+    v(bool, airSpillsEverything, false, nullptr) \
</ins><span class="cx">     \
</span><span class="cx">     v(bool, useDollarVM, false, &quot;installs the $vm debugging tool in global objects&quot;) \
</span><span class="cx">     v(optionString, functionOverrides, nullptr, &quot;file with debugging overrides for function bodies&quot;) \
</span></span></pre>
</div>
</div>

</body>
</html>