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

<h3>Log Message</h3>
<pre>B3 should be able to compile a program with Switch
https://bugs.webkit.org/show_bug.cgi?id=151115

Reviewed by Benjamin Poulain.

Adds lowering of Switch to a binary switch. This doesn't require any Air support.

* b3/B3BasicBlock.cpp:
(JSC::B3::BasicBlock::append):
(JSC::B3::BasicBlock::removeLast):
(JSC::B3::BasicBlock::replaceLast):
* b3/B3BasicBlock.h:
* b3/B3BlockInsertionSet.cpp:
(JSC::B3::BlockInsertionSet::insertBefore):
(JSC::B3::BlockInsertionSet::insertAfter):
(JSC::B3::BlockInsertionSet::splitForward):
* b3/B3BlockInsertionSet.h:
* b3/B3ControlValue.h:
* b3/B3Generate.cpp:
(JSC::B3::generateToAir):
* b3/B3LowerMacros.cpp:
* b3/B3SwitchValue.cpp:
(JSC::B3::SwitchValue::dumpMeta):
(JSC::B3::SwitchValue::SwitchValue):
* b3/B3SwitchValue.h:
* b3/testb3.cpp:
(JSC::B3::testChillDiv64):
(JSC::B3::testSwitch):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3BasicBlockcpp">trunk/Source/JavaScriptCore/b3/B3BasicBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3BasicBlockh">trunk/Source/JavaScriptCore/b3/B3BasicBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3BlockInsertionSetcpp">trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3BlockInsertionSeth">trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ControlValueh">trunk/Source/JavaScriptCore/b3/B3ControlValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Generatecpp">trunk/Source/JavaScriptCore/b3/B3Generate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerMacroscpp">trunk/Source/JavaScriptCore/b3/B3LowerMacros.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3SwitchValuecpp">trunk/Source/JavaScriptCore/b3/B3SwitchValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3SwitchValueh">trunk/Source/JavaScriptCore/b3/B3SwitchValue.h</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 (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -1,5 +1,37 @@
</span><span class="cx"> 2015-11-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        B3 should be able to compile a program with Switch
+        https://bugs.webkit.org/show_bug.cgi?id=151115
+
+        Reviewed by Benjamin Poulain.
+
+        Adds lowering of Switch to a binary switch. This doesn't require any Air support.
+
+        * b3/B3BasicBlock.cpp:
+        (JSC::B3::BasicBlock::append):
+        (JSC::B3::BasicBlock::removeLast):
+        (JSC::B3::BasicBlock::replaceLast):
+        * b3/B3BasicBlock.h:
+        * b3/B3BlockInsertionSet.cpp:
+        (JSC::B3::BlockInsertionSet::insertBefore):
+        (JSC::B3::BlockInsertionSet::insertAfter):
+        (JSC::B3::BlockInsertionSet::splitForward):
+        * b3/B3BlockInsertionSet.h:
+        * b3/B3ControlValue.h:
+        * b3/B3Generate.cpp:
+        (JSC::B3::generateToAir):
+        * b3/B3LowerMacros.cpp:
+        * b3/B3SwitchValue.cpp:
+        (JSC::B3::SwitchValue::dumpMeta):
+        (JSC::B3::SwitchValue::SwitchValue):
+        * b3/B3SwitchValue.h:
+        * b3/testb3.cpp:
+        (JSC::B3::testChillDiv64):
+        (JSC::B3::testSwitch):
+        (JSC::B3::run):
+
+2015-11-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Patchpoints with stackArgument constraints should work
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=151177
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BasicBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3BasicBlock.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BasicBlock.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3BasicBlock.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -54,10 +54,16 @@
</span><span class="cx">     m_values.append(value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void BasicBlock::removeLast(Procedure&amp; proc)
+{
+    ASSERT(!m_values.isEmpty());
+    proc.deleteValue(m_values.takeLast());
+}
+
</ins><span class="cx"> void BasicBlock::replaceLast(Procedure&amp; proc, Value* value)
</span><span class="cx"> {
</span><del>-    proc.deleteValue(last());
-    last() = value;
</del><ins>+    removeLast(proc);
+    append(value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Value* BasicBlock::appendIntConstant(Procedure&amp; proc, Origin origin, Type type, int64_t value)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BasicBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3BasicBlock.h (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BasicBlock.h        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3BasicBlock.h        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -78,6 +78,8 @@
</span><span class="cx"> 
</span><span class="cx">     Value* appendIntConstant(Procedure&amp;, Origin, Type, int64_t value);
</span><span class="cx">     Value* appendIntConstant(Procedure&amp;, Value* likeValue, int64_t value);
</span><ins>+
+    void removeLast(Procedure&amp;);
</ins><span class="cx">     
</span><span class="cx">     template&lt;typename ValueType, typename... Arguments&gt;
</span><span class="cx">     ValueType* replaceLastWithNew(Procedure&amp;, Arguments...);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BlockInsertionSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -60,6 +60,11 @@
</span><span class="cx">     return insert(before-&gt;index(), frequency == frequency ? frequency : before-&gt;frequency());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+BasicBlock* BlockInsertionSet::insertAfter(BasicBlock* after, double frequency)
+{
+    return insert(after-&gt;index() + 1, frequency == frequency ? frequency : after-&gt;frequency());
+}
+
</ins><span class="cx"> BasicBlock* BlockInsertionSet::splitForward(
</span><span class="cx">     BasicBlock* block, unsigned&amp; valueIndex, InsertionSet* insertionSet, double frequency)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BlockInsertionSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.h (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.h        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3BlockInsertionSet.h        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -53,6 +53,9 @@
</span><span class="cx">     // usually what you want.
</span><span class="cx">     BasicBlock* insertBefore(BasicBlock* before, double frequency = PNaN);
</span><span class="cx"> 
</span><ins>+    // Inserts a new block after the given block.
+    BasicBlock* insertAfter(BasicBlock* after, double frequency = PNaN);
+
</ins><span class="cx">     // A helper to split a block when forward iterating over it. It creates a new block to hold
</span><span class="cx">     // everything before the instruction at valueIndex. The current block is left with
</span><span class="cx">     // everything at and after valueIndex. If the optional InsertionSet is provided, it will get
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ControlValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ControlValue.h (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ControlValue.h        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3ControlValue.h        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">     // Use this for subclasses.
</span><span class="cx">     template&lt;typename... Arguments&gt;
</span><span class="cx">     ControlValue(unsigned index, Opcode opcode, Type type, Origin origin, Arguments... arguments)
</span><del>-        : Value(index, opcode, type, origin, arguments...)
</del><ins>+        : Value(index, CheckedOpcode, opcode, type, origin, arguments...)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(accepts(opcode));
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Generatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Generate.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -55,18 +55,17 @@
</span><span class="cx"> {
</span><span class="cx">     TimingScope timingScope(&quot;generateToAir&quot;);
</span><span class="cx">     
</span><ins>+    if (shouldDumpIR() &amp;&amp; !shouldDumpIRAtEachPhase()) {
+        dataLog(&quot;Initial B3:\n&quot;);
+        dataLog(procedure);
+    }
+
</ins><span class="cx">     // We don't require the incoming IR to have predecessors computed.
</span><span class="cx">     procedure.resetReachability();
</span><span class="cx">     
</span><span class="cx">     if (shouldValidateIR())
</span><span class="cx">         validate(procedure);
</span><span class="cx"> 
</span><del>-    // If we're doing super verbose dumping, the phase scope of any phase will already do a dump.
-    if (shouldDumpIR() &amp;&amp; !shouldDumpIRAtEachPhase()) {
-        dataLog(&quot;Initial B3:\n&quot;);
-        dataLog(procedure);
-    }
-
</del><span class="cx">     lowerMacros(procedure);
</span><span class="cx"> 
</span><span class="cx">     if (optLevel &gt;= 1) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerMacroscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerMacros.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerMacros.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3LowerMacros.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;B3InsertionSetInlines.h&quot;
</span><span class="cx"> #include &quot;B3PhaseScope.h&quot;
</span><span class="cx"> #include &quot;B3ProcedureInlines.h&quot;
</span><ins>+#include &quot;B3SwitchValue.h&quot;
</ins><span class="cx"> #include &quot;B3UpsilonValue.h&quot;
</span><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -67,6 +68,7 @@
</span><span class="cx">     {
</span><span class="cx">         for (m_index = 0; m_index &lt; m_block-&gt;size(); ++m_index) {
</span><span class="cx">             m_value = m_block-&gt;at(m_index);
</span><ins>+            m_origin = m_value-&gt;origin();
</ins><span class="cx">             switch (m_value-&gt;opcode()) {
</span><span class="cx">             case ChillDiv: {
</span><span class="cx">                 // ARM supports this instruction natively.
</span><span class="lines">@@ -96,8 +98,8 @@
</span><span class="cx">                 Value* one =
</span><span class="cx">                     m_insertionSet.insertIntConstant(m_index, m_value, 1);
</span><span class="cx">                 Value* isDenOK = m_insertionSet.insert&lt;Value&gt;(
</span><del>-                    m_index, Above, m_value-&gt;origin(),
-                    m_insertionSet.insert&lt;Value&gt;(m_index, Add, m_value-&gt;origin(), den, one),
</del><ins>+                    m_index, Above, m_origin,
+                    m_insertionSet.insert&lt;Value&gt;(m_index, Add, m_origin, den, one),
</ins><span class="cx">                     one);
</span><span class="cx"> 
</span><span class="cx">                 BasicBlock* before =
</span><span class="lines">@@ -110,26 +112,26 @@
</span><span class="cx">                 BasicBlock* intMinCase = m_blockInsertionSet.insertBefore(m_block);
</span><span class="cx"> 
</span><span class="cx">                 before-&gt;replaceLastWithNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Branch, m_value-&gt;origin(), isDenOK,
</del><ins>+                    m_proc, Branch, m_origin, isDenOK,
</ins><span class="cx">                     FrequentedBlock(normalDivCase, FrequencyClass::Normal),
</span><span class="cx">                     FrequentedBlock(shadyDenCase, FrequencyClass::Rare));
</span><span class="cx"> 
</span><span class="cx">                 UpsilonValue* normalResult = normalDivCase-&gt;appendNew&lt;UpsilonValue&gt;(
</span><del>-                    m_proc, m_value-&gt;origin(),
-                    normalDivCase-&gt;appendNew&lt;Value&gt;(m_proc, Div, m_value-&gt;origin(), num, den));
</del><ins>+                    m_proc, m_origin,
+                    normalDivCase-&gt;appendNew&lt;Value&gt;(m_proc, Div, m_origin, num, den));
</ins><span class="cx">                 normalDivCase-&gt;appendNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Jump, m_value-&gt;origin(), FrequentedBlock(m_block));
</del><ins>+                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
</ins><span class="cx"> 
</span><span class="cx">                 shadyDenCase-&gt;appendNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Branch, m_value-&gt;origin(), den,
</del><ins>+                    m_proc, Branch, m_origin, den,
</ins><span class="cx">                     FrequentedBlock(neg1DenCase, FrequencyClass::Normal),
</span><span class="cx">                     FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
</span><span class="cx"> 
</span><span class="cx">                 UpsilonValue* zeroResult = zeroDenCase-&gt;appendNew&lt;UpsilonValue&gt;(
</span><del>-                    m_proc, m_value-&gt;origin(),
</del><ins>+                    m_proc, m_origin,
</ins><span class="cx">                     zeroDenCase-&gt;appendIntConstant(m_proc, m_value, 0));
</span><span class="cx">                 zeroDenCase-&gt;appendNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Jump, m_value-&gt;origin(), FrequentedBlock(m_block));
</del><ins>+                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
</ins><span class="cx"> 
</span><span class="cx">                 int64_t badNumeratorConst;
</span><span class="cx">                 switch (m_value-&gt;type()) {
</span><span class="lines">@@ -148,19 +150,19 @@
</span><span class="cx">                     neg1DenCase-&gt;appendIntConstant(m_proc, m_value, badNumeratorConst);
</span><span class="cx"> 
</span><span class="cx">                 neg1DenCase-&gt;appendNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Branch, m_value-&gt;origin(),
</del><ins>+                    m_proc, Branch, m_origin,
</ins><span class="cx">                     neg1DenCase-&gt;appendNew&lt;Value&gt;(
</span><del>-                        m_proc, Equal, m_value-&gt;origin(), num, badNumerator),
</del><ins>+                        m_proc, Equal, m_origin, num, badNumerator),
</ins><span class="cx">                     FrequentedBlock(intMinCase, FrequencyClass::Rare),
</span><span class="cx">                     FrequentedBlock(normalDivCase, FrequencyClass::Normal));
</span><span class="cx"> 
</span><span class="cx">                 UpsilonValue* intMinResult = intMinCase-&gt;appendNew&lt;UpsilonValue&gt;(
</span><del>-                    m_proc, m_value-&gt;origin(), badNumerator);
</del><ins>+                    m_proc, m_origin, badNumerator);
</ins><span class="cx">                 intMinCase-&gt;appendNew&lt;ControlValue&gt;(
</span><del>-                    m_proc, Jump, m_value-&gt;origin(), FrequentedBlock(m_block));
</del><ins>+                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
</ins><span class="cx"> 
</span><span class="cx">                 Value* phi = m_insertionSet.insert&lt;Value&gt;(
</span><del>-                    m_index, Phi, m_value-&gt;type(), m_value-&gt;origin());
</del><ins>+                    m_index, Phi, m_value-&gt;type(), m_origin);
</ins><span class="cx">                 normalResult-&gt;setPhi(phi);
</span><span class="cx">                 zeroResult-&gt;setPhi(phi);
</span><span class="cx">                 intMinResult-&gt;setPhi(phi);
</span><span class="lines">@@ -170,8 +172,23 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            // FIXME: Implement Switch.
-            // https://bugs.webkit.org/show_bug.cgi?id=151115
</del><ins>+            case Switch: {
+                SwitchValue* switchValue = m_value-&gt;as&lt;SwitchValue&gt;();
+                Vector&lt;SwitchCase&gt; cases;
+                for (const SwitchCase&amp; switchCase : *switchValue)
+                    cases.append(switchCase);
+                std::sort(
+                    cases.begin(), cases.end(),
+                    [] (const SwitchCase&amp; left, const SwitchCase&amp; right) {
+                        return left.caseValue() &lt; right.caseValue();
+                    });
+                m_block-&gt;values().removeLast();
+                recursivelyBuildSwitch(cases, 0, false, cases.size(), m_block);
+                m_proc.deleteValue(switchValue);
+                m_block-&gt;updatePredecessorsAfter();
+                m_changed = true;
+                break;
+            }
</ins><span class="cx"> 
</span><span class="cx">             default:
</span><span class="cx">                 break;
</span><span class="lines">@@ -179,6 +196,79 @@
</span><span class="cx">         }
</span><span class="cx">         m_insertionSet.execute(m_block);
</span><span class="cx">     }
</span><ins>+
+    void recursivelyBuildSwitch(
+        const Vector&lt;SwitchCase&gt;&amp; cases, unsigned start, bool hardStart, unsigned end,
+        BasicBlock* before)
+    {
+        // FIXME: Add table-based switch lowering.
+        // https://bugs.webkit.org/show_bug.cgi?id=151141
+        
+        // See comments in jit/BinarySwitch.cpp for a justification of this algorithm. The only
+        // thing we do differently is that we don't use randomness.
+
+        const unsigned leafThreshold = 3;
+
+        unsigned size = end - start;
+
+        if (size &lt;= leafThreshold) {
+            bool allConsecutive = false;
+
+            if ((hardStart || (start &amp;&amp; cases[start - 1].caseValue() == cases[start].caseValue() - 1))
+                &amp;&amp; end &lt; cases.size()
+                &amp;&amp; cases[end - 1].caseValue() == cases[end].caseValue() - 1) {
+                allConsecutive = true;
+                for (unsigned i = 0; i &lt; size - 1; ++i) {
+                    if (cases[start + i].caseValue() + 1 != cases[start + i + 1].caseValue()) {
+                        allConsecutive = false;
+                        break;
+                    }
+                }
+            }
+
+            unsigned limit = allConsecutive ? size - 1 : size;
+            
+            for (unsigned i = 0; i &lt; limit; ++i) {
+                BasicBlock* nextCheck = m_blockInsertionSet.insertAfter(m_block);
+                before-&gt;appendNew&lt;ControlValue&gt;(
+                    m_proc, Branch, m_origin,
+                    before-&gt;appendNew&lt;Value&gt;(
+                        m_proc, Equal, m_origin, m_value-&gt;child(0),
+                        before-&gt;appendIntConstant(
+                            m_proc, m_origin, m_value-&gt;child(0)-&gt;type(),
+                            cases[start + i].caseValue())),
+                    cases[start + i].target(), FrequentedBlock(nextCheck));
+
+                before = nextCheck;
+            }
+
+            if (allConsecutive) {
+                before-&gt;appendNew&lt;ControlValue&gt;(
+                    m_proc, Jump, m_origin, cases[end - 1].target());
+            } else {
+                before-&gt;appendNew&lt;ControlValue&gt;(
+                    m_proc, Jump, m_origin, m_value-&gt;as&lt;SwitchValue&gt;()-&gt;fallThrough());
+            }
+            return;
+        }
+
+        unsigned medianIndex = (start + end) / 2;
+
+        BasicBlock* left = m_blockInsertionSet.insertAfter(m_block);
+        BasicBlock* right = m_blockInsertionSet.insertAfter(m_block);
+
+        before-&gt;appendNew&lt;ControlValue&gt;(
+            m_proc, Branch, m_origin,
+            before-&gt;appendNew&lt;Value&gt;(
+                m_proc, LessThan, m_origin, m_value-&gt;child(0),
+                before-&gt;appendIntConstant(
+                    m_proc, m_origin, m_value-&gt;child(0)-&gt;type(),
+                    cases[medianIndex].caseValue())),
+            FrequentedBlock(left), FrequentedBlock(right));
+
+        recursivelyBuildSwitch(cases, start, hardStart, medianIndex, left);
+        recursivelyBuildSwitch(cases, medianIndex, true, end, right);
+    }
</ins><span class="cx">     
</span><span class="cx">     Procedure&amp; m_proc;
</span><span class="cx">     BlockInsertionSet m_blockInsertionSet;
</span><span class="lines">@@ -186,6 +276,7 @@
</span><span class="cx">     BasicBlock* m_block;
</span><span class="cx">     unsigned m_index;
</span><span class="cx">     Value* m_value;
</span><ins>+    Origin m_origin;
</ins><span class="cx">     bool m_changed { false };
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3SwitchValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3SwitchValue.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3SwitchValue.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3SwitchValue.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -63,8 +63,9 @@
</span><span class="cx">     out.print(comma, &quot;fallThrough = &quot;, fallThrough());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SwitchValue::SwitchValue(unsigned index, Origin origin, const FrequentedBlock&amp; fallThrough)
-    : ControlValue(index, Switch, Void, origin)
</del><ins>+SwitchValue::SwitchValue(
+    unsigned index, Origin origin, Value* child, const FrequentedBlock&amp; fallThrough)
+    : ControlValue(index, Switch, Void, origin, child)
</ins><span class="cx"> {
</span><span class="cx">     m_successors.append(fallThrough);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3SwitchValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3SwitchValue.h (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3SwitchValue.h        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/B3SwitchValue.h        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -111,7 +111,7 @@
</span><span class="cx">     // contain some other case value). This removes the case that was removed.
</span><span class="cx">     SwitchCase removeCase(unsigned index);
</span><span class="cx"> 
</span><del>-    void appendCase(const SwitchCase&amp;);
</del><ins>+    JS_EXPORT_PRIVATE void appendCase(const SwitchCase&amp;);
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><span class="cx">     void dumpMeta(CommaPrinter&amp;, PrintStream&amp;) const override;
</span><span class="lines">@@ -119,7 +119,8 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class Procedure;
</span><span class="cx"> 
</span><del>-    SwitchValue(unsigned index, Origin, const FrequentedBlock&amp; fallThrough);
</del><ins>+    JS_EXPORT_PRIVATE SwitchValue(
+        unsigned index, Origin, Value* child, const FrequentedBlock&amp; fallThrough);
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;int64_t&gt; m_values;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (192345 => 192346)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-12 03:39:00 UTC (rev 192345)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-12 04:08:46 UTC (rev 192346)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><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><ins>+#include &quot;B3SwitchValue.h&quot;
</ins><span class="cx"> #include &quot;B3UpsilonValue.h&quot;
</span><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="lines">@@ -1266,7 +1267,7 @@
</span><span class="cx">         proc, Return, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;Value&gt;(proc, SShr, Origin(), value, value));
</span><span class="cx"> 
</span><del>-    CHECK(compileAndRun&lt;int32_t&gt;(proc, a) == (a &gt;&gt; a));
</del><ins>+    CHECK(compileAndRun&lt;int32_t&gt;(proc, a) == (a &gt;&gt; (a &amp; 31)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testSShrArgs32(int32_t a, int32_t b)
</span><span class="lines">@@ -1372,7 +1373,7 @@
</span><span class="cx">         proc, Return, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;Value&gt;(proc, ZShr, Origin(), value, value));
</span><span class="cx"> 
</span><del>-    CHECK(compileAndRun&lt;uint32_t&gt;(proc, a) == (a &gt;&gt; a));
</del><ins>+    CHECK(compileAndRun&lt;uint32_t&gt;(proc, a) == (a &gt;&gt; (a &amp; 31)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testZShrArgs32(uint32_t a, uint32_t b)
</span><span class="lines">@@ -3188,6 +3189,89 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testSwitch(unsigned degree, unsigned gap = 1)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    BasicBlock* terminate = proc.addBlock();
+    terminate-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        terminate-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    SwitchValue* switchValue = root-&gt;appendNew&lt;SwitchValue&gt;(
+        proc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(terminate));
+
+    for (unsigned i = 0; i &lt; degree; ++i) {
+        BasicBlock* newBlock = proc.addBlock();
+        newBlock-&gt;appendNew&lt;ControlValue&gt;(
+            proc, Return, Origin(),
+            newBlock-&gt;appendNew&lt;ArgumentRegValue&gt;(
+                proc, Origin(), (i &amp; 1) ? GPRInfo::argumentGPR2 : GPRInfo::argumentGPR1));
+        switchValue-&gt;appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
+    }
+
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i &lt; degree; ++i) {
+        CHECK(invoke&lt;int32_t&gt;(*code, i * gap, 42, 11) == ((i &amp; 1) ? 11 : 42));
+        if (gap &gt; 1) {
+            CHECK(!invoke&lt;int32_t&gt;(*code, i * gap + 1, 42, 11));
+            CHECK(!invoke&lt;int32_t&gt;(*code, i * gap - 1, 42, 11));
+        }
+    }
+
+    CHECK(!invoke&lt;int32_t&gt;(*code, -1, 42, 11));
+    CHECK(!invoke&lt;int32_t&gt;(*code, degree * gap, 42, 11));
+    CHECK(!invoke&lt;int32_t&gt;(*code, degree * gap + 1, 42, 11));
+}
+
+void testSwitchChillDiv(unsigned degree, unsigned gap = 1)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* left = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* right = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2);
+
+    BasicBlock* terminate = proc.addBlock();
+    terminate-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        terminate-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    SwitchValue* switchValue = root-&gt;appendNew&lt;SwitchValue&gt;(
+        proc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(terminate));
+
+    for (unsigned i = 0; i &lt; degree; ++i) {
+        BasicBlock* newBlock = proc.addBlock();
+
+        newBlock-&gt;appendNew&lt;ControlValue&gt;(
+            proc, Return, Origin(),
+            newBlock-&gt;appendNew&lt;Value&gt;(
+                proc, ChillDiv, Origin(), (i &amp; 1) ? right : left, (i &amp; 1) ? left : right));
+        
+        switchValue-&gt;appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
+    }
+
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i &lt; degree; ++i) {
+        CHECK(invoke&lt;int32_t&gt;(*code, i * gap, 42, 11) == ((i &amp; 1) ? 11/42 : 42/11));
+        if (gap &gt; 1) {
+            CHECK(!invoke&lt;int32_t&gt;(*code, i * gap + 1, 42, 11));
+            CHECK(!invoke&lt;int32_t&gt;(*code, i * gap - 1, 42, 11));
+        }
+    }
+
+    CHECK(!invoke&lt;int32_t&gt;(*code, -1, 42, 11));
+    CHECK(!invoke&lt;int32_t&gt;(*code, degree * gap, 42, 11));
+    CHECK(!invoke&lt;int32_t&gt;(*code, degree * gap + 1, 42, 11));
+}
+
</ins><span class="cx"> #define RUN(test) do {                          \
</span><span class="cx">         if (!shouldRun(#test))                  \
</span><span class="cx">             break;                              \
</span><span class="lines">@@ -3729,6 +3813,24 @@
</span><span class="cx">     RUN(testChillDivTwice(4, 0, 6, 2, 3));
</span><span class="cx">     RUN(testChillDivTwice(4, 2, 6, 0, 2));
</span><span class="cx"> 
</span><ins>+    RUN(testSwitch(0, 1));
+    RUN(testSwitch(1, 1));
+    RUN(testSwitch(2, 1));
+    RUN(testSwitch(2, 2));
+    RUN(testSwitch(10, 1));
+    RUN(testSwitch(10, 2));
+    RUN(testSwitch(100, 1));
+    RUN(testSwitch(100, 100));
+
+    RUN(testSwitchChillDiv(0, 1));
+    RUN(testSwitchChillDiv(1, 1));
+    RUN(testSwitchChillDiv(2, 1));
+    RUN(testSwitchChillDiv(2, 2));
+    RUN(testSwitchChillDiv(10, 1));
+    RUN(testSwitchChillDiv(10, 2));
+    RUN(testSwitchChillDiv(100, 1));
+    RUN(testSwitchChillDiv(100, 100));
+
</ins><span class="cx">     if (tasks.isEmpty())
</span><span class="cx">         usage();
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>