<!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>[192699] 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/192699">192699</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-20 14:31:19 -0800 (Fri, 20 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 should have a Select opcode
https://bugs.webkit.org/show_bug.cgi?id=150762

Reviewed by Benjamin Poulain.

This cleans up our conditional move implementation - specifically so that it distinguishes between
comparing the low 32 bits of a GPR and all bits of a GPR - and fixes bugs with operand ordering. It
then adds a Select opcode to B3 and adds all of the strength reduction and lowering magic that it
needs. Finally this change implements FTL::Output::select() in terms of B3::Select.

This patch lets us run Kraken/imaging-gaussian-blur. Running that benchmark using FTL+B3 is a 17%
speed-up. The compile times go down dramatically (by about 7x) and code quality stays about the same.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::moveDoubleConditionally32):
(JSC::MacroAssembler::moveDoubleConditionally64):
(JSC::MacroAssembler::moveDoubleConditionallyTest32):
(JSC::MacroAssembler::moveDoubleConditionallyTest64):
(JSC::MacroAssembler::moveDoubleConditionallyDouble):
(JSC::MacroAssembler::lea):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::move):
(JSC::MacroAssemblerX86Common::moveConditionallyDouble):
(JSC::MacroAssemblerX86Common::zeroExtend32ToPtr):
(JSC::MacroAssemblerX86Common::moveConditionally32):
(JSC::MacroAssemblerX86Common::moveConditionallyTest32):
(JSC::MacroAssemblerX86Common::set32):
(JSC::MacroAssemblerX86Common::cmov):
(JSC::MacroAssemblerX86Common::moveConditionally): Deleted.
(JSC::MacroAssemblerX86Common::moveConditionallyTest): Deleted.
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::branchNeg64):
(JSC::MacroAssemblerX86_64::moveConditionally64):
(JSC::MacroAssemblerX86_64::moveConditionallyTest64):
(JSC::MacroAssemblerX86_64::abortWithReason):
* assembler/X86Assembler.h:
(JSC::X86Assembler::cmovl_rr):
(JSC::X86Assembler::cmovl_mr):
(JSC::X86Assembler::cmovel_rr):
(JSC::X86Assembler::cmovnel_rr):
(JSC::X86Assembler::cmovpl_rr):
(JSC::X86Assembler::cmovnpl_rr):
(JSC::X86Assembler::cmovq_rr):
(JSC::X86Assembler::cmovq_mr):
(JSC::X86Assembler::cmoveq_rr):
(JSC::X86Assembler::cmovneq_rr):
(JSC::X86Assembler::cmovpq_rr):
(JSC::X86Assembler::cmovnpq_rr):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::createCompare):
(JSC::B3::Air::LowerToAir::createSelect):
(JSC::B3::Air::LowerToAir::marshallCCallArgument):
(JSC::B3::Air::LowerToAir::lower):
* b3/B3MoveConstants.cpp:
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3ReduceStrength.cpp:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::effects):
(JSC::B3::Value::key):
(JSC::B3::Value::checkOpcode):
(JSC::B3::Value::typeFor):
* b3/B3Value.h:
* b3/B3ValueKey.cpp:
(JSC::B3::ValueKey::dump):
(JSC::B3::ValueKey::materialize):
* b3/B3ValueKey.h:
(JSC::B3::ValueKey::ValueKey):
(JSC::B3::ValueKey::hash):
(JSC::B3::ValueKey::operator bool):
* b3/B3ValueKeyInlines.h:
(JSC::B3::ValueKey::ValueKey):
(JSC::B3::ValueKey::child):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::testTruncSExt32):
(JSC::B3::testBasicSelect):
(JSC::B3::testSelectTest):
(JSC::B3::testSelectCompareDouble):
(JSC::B3::testSelectDouble):
(JSC::B3::testSelectDoubleTest):
(JSC::B3::testSelectDoubleCompareDouble):
(JSC::B3::zero):
(JSC::B3::run):
* ftl/FTLB3Output.h:
(JSC::FTL::Output::testIsZeroPtr):
(JSC::FTL::Output::testNonZeroPtr):
(JSC::FTL::Output::select):
(JSC::FTL::Output::extractValue):
(JSC::FTL::Output::fence):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerX86Assemblerh">trunk/Source/JavaScriptCore/assembler/X86Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MoveConstantscpp">trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Opcodecpp">trunk/Source/JavaScriptCore/b3/B3Opcode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Opcodeh">trunk/Source/JavaScriptCore/b3/B3Opcode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valuecpp">trunk/Source/JavaScriptCore/b3/B3Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueKeycpp">trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueKeyh">trunk/Source/JavaScriptCore/b3/B3ValueKey.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueKeyInlinesh">trunk/Source/JavaScriptCore/b3/B3ValueKeyInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeapcpp">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeaph">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLB3Outputh">trunk/Source/JavaScriptCore/ftl/FTLB3Output.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -1,3 +1,98 @@
</span><ins>+2015-11-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should have a Select opcode
+        https://bugs.webkit.org/show_bug.cgi?id=150762
+
+        Reviewed by Benjamin Poulain.
+
+        This cleans up our conditional move implementation - specifically so that it distinguishes between
+        comparing the low 32 bits of a GPR and all bits of a GPR - and fixes bugs with operand ordering. It
+        then adds a Select opcode to B3 and adds all of the strength reduction and lowering magic that it
+        needs. Finally this change implements FTL::Output::select() in terms of B3::Select.
+
+        This patch lets us run Kraken/imaging-gaussian-blur. Running that benchmark using FTL+B3 is a 17%
+        speed-up. The compile times go down dramatically (by about 7x) and code quality stays about the same.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::moveDoubleConditionally32):
+        (JSC::MacroAssembler::moveDoubleConditionally64):
+        (JSC::MacroAssembler::moveDoubleConditionallyTest32):
+        (JSC::MacroAssembler::moveDoubleConditionallyTest64):
+        (JSC::MacroAssembler::moveDoubleConditionallyDouble):
+        (JSC::MacroAssembler::lea):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::move):
+        (JSC::MacroAssemblerX86Common::moveConditionallyDouble):
+        (JSC::MacroAssemblerX86Common::zeroExtend32ToPtr):
+        (JSC::MacroAssemblerX86Common::moveConditionally32):
+        (JSC::MacroAssemblerX86Common::moveConditionallyTest32):
+        (JSC::MacroAssemblerX86Common::set32):
+        (JSC::MacroAssemblerX86Common::cmov):
+        (JSC::MacroAssemblerX86Common::moveConditionally): Deleted.
+        (JSC::MacroAssemblerX86Common::moveConditionallyTest): Deleted.
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::branchNeg64):
+        (JSC::MacroAssemblerX86_64::moveConditionally64):
+        (JSC::MacroAssemblerX86_64::moveConditionallyTest64):
+        (JSC::MacroAssemblerX86_64::abortWithReason):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::cmovl_rr):
+        (JSC::X86Assembler::cmovl_mr):
+        (JSC::X86Assembler::cmovel_rr):
+        (JSC::X86Assembler::cmovnel_rr):
+        (JSC::X86Assembler::cmovpl_rr):
+        (JSC::X86Assembler::cmovnpl_rr):
+        (JSC::X86Assembler::cmovq_rr):
+        (JSC::X86Assembler::cmovq_mr):
+        (JSC::X86Assembler::cmoveq_rr):
+        (JSC::X86Assembler::cmovneq_rr):
+        (JSC::X86Assembler::cmovpq_rr):
+        (JSC::X86Assembler::cmovnpq_rr):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::createCompare):
+        (JSC::B3::Air::LowerToAir::createSelect):
+        (JSC::B3::Air::LowerToAir::marshallCCallArgument):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3MoveConstants.cpp:
+        * b3/B3Opcode.cpp:
+        (WTF::printInternal):
+        * b3/B3Opcode.h:
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::effects):
+        (JSC::B3::Value::key):
+        (JSC::B3::Value::checkOpcode):
+        (JSC::B3::Value::typeFor):
+        * b3/B3Value.h:
+        * b3/B3ValueKey.cpp:
+        (JSC::B3::ValueKey::dump):
+        (JSC::B3::ValueKey::materialize):
+        * b3/B3ValueKey.h:
+        (JSC::B3::ValueKey::ValueKey):
+        (JSC::B3::ValueKey::hash):
+        (JSC::B3::ValueKey::operator bool):
+        * b3/B3ValueKeyInlines.h:
+        (JSC::B3::ValueKey::ValueKey):
+        (JSC::B3::ValueKey::child):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::testTruncSExt32):
+        (JSC::B3::testBasicSelect):
+        (JSC::B3::testSelectTest):
+        (JSC::B3::testSelectCompareDouble):
+        (JSC::B3::testSelectDouble):
+        (JSC::B3::testSelectDoubleTest):
+        (JSC::B3::testSelectDoubleCompareDouble):
+        (JSC::B3::zero):
+        (JSC::B3::run):
+        * ftl/FTLB3Output.h:
+        (JSC::FTL::Output::testIsZeroPtr):
+        (JSC::FTL::Output::testNonZeroPtr):
+        (JSC::FTL::Output::select):
+        (JSC::FTL::Output::extractValue):
+        (JSC::FTL::Output::fence):
+
</ins><span class="cx"> 2015-11-20  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Add Air lowering to BitNot() for Xor(value, -1)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -1301,6 +1301,61 @@
</span><span class="cx"> 
</span><span class="cx"> #endif // !CPU(X86_64)
</span><span class="cx"> 
</span><ins>+    template&lt;typename LeftType, typename RightType&gt;
+    void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
+    {
+        Jump falseCase = branch32(invert(cond), left, right);
+        moveDouble(src, dest);
+        falseCase.link(this);
+    }
+
+    template&lt;typename LeftType, typename RightType&gt;
+    void moveDoubleConditionally64(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
+    {
+        Jump falseCase = branch64(invert(cond), left, right);
+        moveDouble(src, dest);
+        falseCase.link(this);
+    }
+
+    template&lt;typename TestType, typename MaskType&gt;
+    void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
+    {
+        if (isInvertible(cond)) {
+            Jump falseCase = branchTest32(invert(cond), test, mask);
+            moveDouble(src, dest);
+            falseCase.link(this);
+        }
+
+        Jump trueCase = branchTest32(cond, test, mask);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(src, dest);
+        falseCase.link(this);
+    }
+
+    template&lt;typename TestType, typename MaskType&gt;
+    void moveDoubleConditionallyTest64(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
+    {
+        if (isInvertible(cond)) {
+            Jump falseCase = branchTest64(invert(cond), test, mask);
+            moveDouble(src, dest);
+            falseCase.link(this);
+        }
+
+        Jump trueCase = branchTest64(cond, test, mask);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(src, dest);
+        falseCase.link(this);
+    }
+
+    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID src, FPRegisterID dest)
+    {
+        Jump falseCase = branchDouble(invert(cond), left, right);
+        moveDouble(src, dest);
+        falseCase.link(this);
+    }
+
</ins><span class="cx">     void lea(Address address, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         addPtr(TrustedImm32(address.offset), address.base, dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -1091,18 +1091,6 @@
</span><span class="cx">         m_assembler.movq_i64r(imm.m_value, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void moveConditionally(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
-    {
-        m_assembler.cmpq_rr(right, left);
-        m_assembler.cmovq_rr(x86Condition(cond), src, dest);
-    }
-
-    void moveConditionallyTest(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
-    {
-        m_assembler.testq_rr(testReg, mask);
-        m_assembler.cmovq_rr(x86Condition(cond), src, dest);
-    }
-    
</del><span class="cx">     void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(isSSE2Present());
</span><span class="lines">@@ -1171,18 +1159,6 @@
</span><span class="cx">         m_assembler.movl_i32r(imm.asIntptr(), dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void moveConditionally(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
-    {
-        m_assembler.cmpl_rr(right, left);
-        m_assembler.cmovl_rr(x86Condition(cond), src, dest);
-    }
-
-    void moveConditionallyTest(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
-    {
-        m_assembler.testl_rr(testReg, mask);
-        m_assembler.cmovl_rr(x86Condition(cond), src, dest);
-    }
-
</del><span class="cx">     void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(isSSE2Present());
</span><span class="lines">@@ -1236,7 +1212,25 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+    {
+        m_assembler.cmpl_rr(right, left);
+        cmov(x86Condition(cond), src, dest);
+    }
</ins><span class="cx"> 
</span><ins>+    void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+    {
+        m_assembler.testl_rr(testReg, mask);
+        cmov(x86Condition(cond), src, dest);
+    }
+    
+    void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
+    {
+        test32(cond, testReg, mask);
+        cmov(x86Condition(cond), src, dest);
+    }
+    
+
</ins><span class="cx">     // Forwards / external control flow operations:
</span><span class="cx">     //
</span><span class="cx">     // This set of jump and conditional branch operations return a Jump
</span><span class="lines">@@ -1684,6 +1678,15 @@
</span><span class="cx">         m_assembler.movzbl_rr(dest, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void cmov(X86Assembler::Condition cond, RegisterID src, RegisterID dest)
+    {
+#if CPU(X86_64)
+        m_assembler.cmovq_rr(cond, src, dest);
+#else
+        m_assembler.cmovl_rr(cond, src, dest);
+#endif
+    }
+    
</ins><span class="cx"> private:
</span><span class="cx">     // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
</span><span class="cx">     // x86_64, and clients &amp; subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -837,6 +837,30 @@
</span><span class="cx">         return Jump(m_assembler.jCC(x86Condition(cond)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+    {
+        m_assembler.cmpq_rr(right, left);
+        cmov(x86Condition(cond), src, dest);
+    }
+
+    void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+    {
+        m_assembler.testq_rr(testReg, mask);
+        cmov(x86Condition(cond), src, dest);
+    }
+    
+    void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
+    {
+        // if we are only interested in the low seven bits, this can be tested with a testb
+        if (mask.m_value == -1)
+            m_assembler.testq_rr(testReg, testReg);
+        else if ((mask.m_value &amp; ~0x7f) == 0)
+            m_assembler.testb_i8r(mask.m_value, testReg);
+        else
+            m_assembler.testq_i32r(mask.m_value, testReg);
+        cmov(x86Condition(cond), src, dest);
+    }
+    
</ins><span class="cx">     void abortWithReason(AbortReason reason)
</span><span class="cx">     {
</span><span class="cx">         move(TrustedImm32(reason), X86Registers::r11);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -1650,7 +1650,7 @@
</span><span class="cx"> 
</span><span class="cx">     void cmovl_rr(Condition cond, RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp(cmovcc(cond), src, dst);
</del><ins>+        m_formatter.twoByteOp(cmovcc(cond), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void cmovl_mr(Condition cond, int offset, RegisterID base, RegisterID dst)
</span><span class="lines">@@ -1665,28 +1665,28 @@
</span><span class="cx"> 
</span><span class="cx">     void cmovel_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp(cmovcc(ConditionE), src, dst);
</del><ins>+        m_formatter.twoByteOp(cmovcc(ConditionE), dst, src);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void cmovnel_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp(cmovcc(ConditionNE), src, dst);
</del><ins>+        m_formatter.twoByteOp(cmovcc(ConditionNE), dst, src);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void cmovpl_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp(cmovcc(ConditionP), src, dst);
</del><ins>+        m_formatter.twoByteOp(cmovcc(ConditionP), dst, src);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void cmovnpl_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp(cmovcc(ConditionNP), src, dst);
</del><ins>+        m_formatter.twoByteOp(cmovcc(ConditionNP), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if CPU(X86_64)
</span><span class="cx">     void cmovq_rr(Condition cond, RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp64(cmovcc(cond), src, dst);
</del><ins>+        m_formatter.twoByteOp64(cmovcc(cond), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void cmovq_mr(Condition cond, int offset, RegisterID base, RegisterID dst)
</span><span class="lines">@@ -1701,22 +1701,22 @@
</span><span class="cx"> 
</span><span class="cx">     void cmoveq_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp64(cmovcc(ConditionE), src, dst);
</del><ins>+        m_formatter.twoByteOp64(cmovcc(ConditionE), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void cmovneq_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp64(cmovcc(ConditionNE), src, dst);
</del><ins>+        m_formatter.twoByteOp64(cmovcc(ConditionNE), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void cmovpq_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp64(cmovcc(ConditionP), src, dst);
</del><ins>+        m_formatter.twoByteOp64(cmovcc(ConditionP), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void cmovnpq_rr(RegisterID src, RegisterID dst)
</span><span class="cx">     {
</span><del>-        m_formatter.twoByteOp64(cmovcc(ConditionNP), src, dst);
</del><ins>+        m_formatter.twoByteOp64(cmovcc(ConditionNP), dst, src);
</ins><span class="cx">     }
</span><span class="cx"> #else
</span><span class="cx">     void cmovl_mr(Condition cond, const void* addr, RegisterID dst)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -1185,6 +1185,82 @@
</span><span class="cx">             inverted);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    struct MoveConditionallyConfig {
+        Air::Opcode moveConditionally32;
+        Air::Opcode moveConditionally64;
+        Air::Opcode moveConditionallyTest32;
+        Air::Opcode moveConditionallyTest64;
+        Air::Opcode moveConditionallyDouble;
+        Tmp source;
+        Tmp destination;
+    };
+    Inst createSelect(Value* value, const MoveConditionallyConfig&amp; config, bool inverted = false)
+    {
+        return createGenericCompare(
+            value,
+            [&amp;] (
+                Arg::Width width, const Arg&amp; relCond,
+                const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
+                switch (width) {
+                case Arg::Width8:
+                    // FIXME: Support these things.
+                    // https://bugs.webkit.org/show_bug.cgi?id=151504
+                    return Inst();
+                case Arg::Width16:
+                    return Inst();
+                case Arg::Width32:
+                    if (isValidForm(config.moveConditionally32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                        return Inst(
+                            config.moveConditionally32, m_value, relCond,
+                            left.consume(*this), right.consume(*this), config.source, config.destination);
+                    }
+                    return Inst();
+                case Arg::Width64:
+                    if (isValidForm(config.moveConditionally64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                        return Inst(
+                            config.moveConditionally64, m_value, relCond,
+                            left.consume(*this), right.consume(*this), config.source, config.destination);
+                    }
+                    return Inst();
+                }
+            },
+            [&amp;] (
+                Arg::Width width, const Arg&amp; resCond,
+                const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
+                switch (width) {
+                case Arg::Width8:
+                    // FIXME: Support more things.
+                    // https://bugs.webkit.org/show_bug.cgi?id=151504
+                    return Inst();
+                case Arg::Width16:
+                    return Inst();
+                case Arg::Width32:
+                    if (isValidForm(config.moveConditionallyTest32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                        return Inst(
+                            config.moveConditionallyTest32, m_value, resCond,
+                            left.consume(*this), right.consume(*this), config.source, config.destination);
+                    }
+                    return Inst();
+                case Arg::Width64:
+                    if (isValidForm(config.moveConditionallyTest64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                        return Inst(
+                            config.moveConditionallyTest64, m_value, resCond,
+                            left.consume(*this), right.consume(*this), config.source, config.destination);
+                    }
+                    return Inst();
+                }
+            },
+            [&amp;] (Arg doubleCond, const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
+                if (isValidForm(config.moveConditionallyDouble, Arg::DoubleCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+                    return Inst(
+                        config.moveConditionallyDouble, m_value, doubleCond,
+                        left.consume(*this), right.consume(*this), config.source, config.destination);
+                }
+                return Inst();
+            },
+            inverted);
+    }
+
</ins><span class="cx">     template&lt;typename BankInfo&gt;
</span><span class="cx">     Arg marshallCCallArgument(unsigned&amp; argumentCount, unsigned&amp; stackCount, Value* child)
</span><span class="cx">     {
</span><span class="lines">@@ -1470,6 +1546,33 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case Select: {
+            Tmp result = tmp(m_value);
+            append(relaxedMoveForType(m_value-&gt;type()), tmp(m_value-&gt;child(2)), result);
+
+            MoveConditionallyConfig config;
+            config.source = tmp(m_value-&gt;child(1));
+            config.destination = result;
+
+            if (isInt(m_value-&gt;type())) {
+                config.moveConditionally32 = MoveConditionally32;
+                config.moveConditionally64 = MoveConditionally64;
+                config.moveConditionallyTest32 = MoveConditionallyTest32;
+                config.moveConditionallyTest64 = MoveConditionallyTest64;
+                config.moveConditionallyDouble = MoveConditionallyDouble;
+            } else {
+                // FIXME: it's not obvious that these are particularly efficient.
+                config.moveConditionally32 = MoveDoubleConditionally32;
+                config.moveConditionally64 = MoveDoubleConditionally64;
+                config.moveConditionallyTest32 = MoveDoubleConditionallyTest32;
+                config.moveConditionallyTest64 = MoveDoubleConditionallyTest64;
+                config.moveConditionallyDouble = MoveDoubleConditionallyDouble;
+            }
+            
+            m_insts.last().append(createSelect(m_value-&gt;child(0), config));
+            return;
+        }
+
</ins><span class="cx">         case IToD: {
</span><span class="cx">             appendUnOp&lt;ConvertInt32ToDouble, ConvertInt64ToDouble, Air::Oops&gt;(m_value-&gt;child(0));
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MoveConstantscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -51,8 +51,10 @@
</span><span class="cx">     void run()
</span><span class="cx">     {
</span><span class="cx">         // Eventually this phase will do smart things. For now, it uses a super simple heuristic: it
</span><del>-        // places large constants in the block that uses them, and makes sure that each block has
-        // only one materialization for each large constant.
</del><ins>+        // places constants in the block that uses them, and makes sure that each block has only one
+        // materialization for each constant. Note that this mostly only matters for large constants, since
+        // small constants get fused into the instructions that use them. But it might matter for small
+        // constants if they are used in instructions that don't do immediates, like conditional moves.
</ins><span class="cx"> 
</span><span class="cx">         // FIXME: Implement a better story for constants. At a minimum this should allow the B3
</span><span class="cx">         // client to specify important constants that always get hoisted. Also, the table used to
</span><span class="lines">@@ -147,16 +149,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool needsMotion(const Value* value)
</span><span class="cx">     {
</span><del>-        if (!value-&gt;isConstant())
-            return false;
-        
-        // We currently assume that 32-bit int constants are always cheap to materialize.
-        // This is wrong for ARM. We need some abstract query like &quot;isImmediate(int64_t)&quot;. On
-        // ARM64 this would take into account the way that ARM64 can encode large constants.
-        if (value-&gt;hasInt() &amp;&amp; value-&gt;representableAs&lt;int32_t&gt;())
-            return false;
-
-        return true;
</del><ins>+        return value-&gt;isConstant();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static ValueKey doubleZero()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -194,6 +194,9 @@
</span><span class="cx">     case BelowEqual:
</span><span class="cx">         out.print(&quot;BelowEqual&quot;);
</span><span class="cx">         return;
</span><ins>+    case Select:
+        out.print(&quot;Select&quot;);
+        return;
</ins><span class="cx">     case Load8Z:
</span><span class="cx">         out.print(&quot;Load8Z&quot;);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -114,6 +114,10 @@
</span><span class="cx">     AboveEqual,
</span><span class="cx">     BelowEqual,
</span><span class="cx"> 
</span><ins>+    // SSA form of conditional move. The first child is evaluated for truthiness. If true, the second child
+    // is returned. Otherwise, the third child is returned.
+    Select,
+
</ins><span class="cx">     // Memory loads. Opcode indicates how we load and the loaded type. These use MemoryValue.
</span><span class="cx">     // These return Int32:
</span><span class="cx">     Load8Z,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -541,6 +541,45 @@
</span><span class="cx">             }
</span><span class="cx">             break;
</span><span class="cx"> 
</span><ins>+        case Select:
+            // Turn this: Select(constant, a, b)
+            // Into this: constant ? a : b
+            if (m_value-&gt;child(0)-&gt;hasInt32()) {
+                m_value-&gt;replaceWithIdentity(
+                    m_value-&gt;child(0)-&gt;asInt32() ? m_value-&gt;child(1) : m_value-&gt;child(2));
+                m_changed = true;
+                break;
+            }
+
+            // Turn this: Select(Equal(x, 0), a, b)
+            // Into this: Select(x, b, a)
+            if (m_value-&gt;child(0)-&gt;opcode() == Equal &amp;&amp; m_value-&gt;child(0)-&gt;child(1)-&gt;isInt(0)) {
+                m_value-&gt;child(0) = m_value-&gt;child(0)-&gt;child(0);
+                std::swap(m_value-&gt;child(1), m_value-&gt;child(2));
+                m_changed = true;
+                break;
+            }
+
+            // Turn this: Select(BitXor(bool, 1), a, b)
+            // Into this: Select(bool, b, a)
+            if (m_value-&gt;child(0)-&gt;opcode() == BitXor
+                &amp;&amp; m_value-&gt;child(0)-&gt;child(1)-&gt;isInt32(1)
+                &amp;&amp; m_value-&gt;child(0)-&gt;child(0)-&gt;returnsBool()) {
+                m_value-&gt;child(0) = m_value-&gt;child(0)-&gt;child(0);
+                std::swap(m_value-&gt;child(1), m_value-&gt;child(2));
+                m_changed = true;
+                break;
+            }
+
+            // Turn this: Select(stuff, x, x)
+            // Into this: x
+            if (m_value-&gt;child(1) == m_value-&gt;child(2)) {
+                m_value-&gt;replaceWithIdentity(m_value-&gt;child(1));
+                m_changed = true;
+                break;
+            }
+            break;
+
</ins><span class="cx">         case Load8Z:
</span><span class="cx">         case Load8S:
</span><span class="cx">         case Load16Z:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -231,6 +231,12 @@
</span><span class="cx">                 VALIDATE(isInt(value-&gt;child(0)-&gt;type()), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Int32, (&quot;At &quot;, *value));
</span><span class="cx">                 break;
</span><ins>+            case Select:
+                VALIDATE(value-&gt;numChildren() == 3, (&quot;At &quot;, *value));
+                VALIDATE(isInt(value-&gt;child(0)-&gt;type()), (&quot;At &quot;, *value));
+                VALIDATE(value-&gt;type() == value-&gt;child(1)-&gt;type(), (&quot;At &quot;, *value));
+                VALIDATE(value-&gt;type() == value-&gt;child(2)-&gt;type(), (&quot;At &quot;, *value));
+                break;
</ins><span class="cx">             case Load8Z:
</span><span class="cx">             case Load8S:
</span><span class="cx">             case Load16Z:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -344,6 +344,7 @@
</span><span class="cx">     case Below:
</span><span class="cx">     case AboveEqual:
</span><span class="cx">     case BelowEqual:
</span><ins>+    case Select:
</ins><span class="cx">         break;
</span><span class="cx">     case Div:
</span><span class="cx">         result.controlDependent = true;
</span><span class="lines">@@ -433,6 +434,8 @@
</span><span class="cx">     case CheckSub:
</span><span class="cx">     case CheckMul:
</span><span class="cx">         return ValueKey(opcode(), type(), child(0), child(1));
</span><ins>+    case Select:
+        return ValueKey(opcode(), type(), child(0), child(1), child(2));
</ins><span class="cx">     case Const32:
</span><span class="cx">         return ValueKey(Const32, type(), static_cast&lt;int64_t&gt;(asInt32()));
</span><span class="cx">     case Const64:
</span><span class="lines">@@ -477,7 +480,7 @@
</span><span class="cx"> }
</span><span class="cx"> #endif // !ASSERT_DISABLED
</span><span class="cx"> 
</span><del>-Type Value::typeFor(Opcode opcode, Value* firstChild)
</del><ins>+Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
</ins><span class="cx"> {
</span><span class="cx">     switch (opcode) {
</span><span class="cx">     case Identity:
</span><span class="lines">@@ -529,6 +532,9 @@
</span><span class="cx">         return Void;
</span><span class="cx">     case Nop:
</span><span class="cx">         return Void;
</span><ins>+    case Select:
+        ASSERT(secondChild);
+        return secondChild-&gt;type();
</ins><span class="cx">     default:
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -230,14 +230,24 @@
</span><span class="cx">     }
</span><span class="cx">     // This form is for those opcodes that can infer their type from the opcode and first child:
</span><span class="cx">     template&lt;typename... Arguments&gt;
</span><del>-    explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild, Arguments... arguments)
</del><ins>+    explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild)
</ins><span class="cx">         : m_index(index)
</span><span class="cx">         , m_opcode(opcode)
</span><span class="cx">         , m_type(typeFor(opcode, firstChild))
</span><span class="cx">         , m_origin(origin)
</span><del>-        , m_children{ firstChild, arguments... }
</del><ins>+        , m_children{ firstChild }
</ins><span class="cx">     {
</span><span class="cx">     }
</span><ins>+    // This form is for those opcodes that can infer their type from the opcode and first and second child:
+    template&lt;typename... Arguments&gt;
+    explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
+        : m_index(index)
+        , m_opcode(opcode)
+        , m_type(typeFor(opcode, firstChild, secondChild))
+        , m_origin(origin)
+        , m_children{ firstChild, secondChild, arguments... }
+    {
+    }
</ins><span class="cx">     // This form is for those opcodes that can infer their type from the opcode alone, and that don't
</span><span class="cx">     // take any arguments:
</span><span class="cx">     explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin)
</span><span class="lines">@@ -277,7 +287,7 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class CheckValue; // CheckValue::convertToAdd() modifies m_opcode.
</span><span class="cx">     
</span><del>-    static Type typeFor(Opcode, Value* firstChild);
</del><ins>+    static Type typeFor(Opcode, Value* firstChild, Value* secondChild = nullptr);
</ins><span class="cx"> 
</span><span class="cx">     // This group of fields is arranged to fit in 64 bits.
</span><span class="cx">     unsigned m_index;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueKeycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ValueKey::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><del>-    out.print(m_type, &quot; &quot;, m_opcode, &quot;(&quot;, u.indices[0], &quot;, &quot;, u.indices[1], &quot;)&quot;);
</del><ins>+    out.print(m_type, &quot; &quot;, m_opcode, &quot;(&quot;, u.indices[0], &quot;, &quot;, u.indices[1], &quot;, &quot;, u.indices[2], &quot;)&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Value* ValueKey::materialize(Procedure&amp; proc, Origin origin) const
</span><span class="lines">@@ -77,6 +77,8 @@
</span><span class="cx">     case BelowEqual:
</span><span class="cx">     case Div:
</span><span class="cx">         return proc.add&lt;Value&gt;(opcode(), type(), origin, child(proc, 0), child(proc, 1));
</span><ins>+    case Select:
+        return proc.add&lt;Value&gt;(opcode(), type(), origin, child(proc, 0), child(proc, 1), child(proc, 2));
</ins><span class="cx">     case Const32:
</span><span class="cx">         return proc.add&lt;Const32Value&gt;(origin, static_cast&lt;int32_t&gt;(value()));
</span><span class="cx">     case Const64:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueKeyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueKey.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueKey.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3ValueKey.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -62,6 +62,8 @@
</span><span class="cx"> 
</span><span class="cx">     ValueKey(Opcode, Type, Value* left, Value* right);
</span><span class="cx"> 
</span><ins>+    ValueKey(Opcode, Type, Value* a, Value* b, Value* c);
+
</ins><span class="cx">     ValueKey(Opcode opcode, Type type, int64_t value)
</span><span class="cx">         : m_opcode(opcode)
</span><span class="cx">         , m_type(type)
</span><span class="lines">@@ -97,7 +99,7 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned hash() const
</span><span class="cx">     {
</span><del>-        return m_opcode + m_type + WTF::IntHash&lt;int64_t&gt;::hash(u.value);
</del><ins>+        return m_opcode + m_type + WTF::IntHash&lt;int32_t&gt;::hash(u.indices[0]) + u.indices[1] + u.indices[2];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     explicit operator bool() const { return *this != ValueKey(); }
</span><span class="lines">@@ -137,18 +139,22 @@
</span><span class="cx">     Opcode m_opcode { Oops };
</span><span class="cx">     Type m_type { Void };
</span><span class="cx">     union U {
</span><del>-        unsigned indices[2];
</del><ins>+        unsigned indices[3];
</ins><span class="cx">         int64_t value;
</span><span class="cx">         double doubleValue;
</span><span class="cx"> 
</span><span class="cx">         U()
</span><span class="cx">         {
</span><del>-            value = 0;
</del><ins>+            indices[0] = 0;
+            indices[1] = 0;
+            indices[2] = 0;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         bool operator==(const U&amp; other) const
</span><span class="cx">         {
</span><del>-            return value == other.value;
</del><ins>+            return indices[0] == other.indices[0]
+                &amp;&amp; indices[1] == other.indices[1]
+                &amp;&amp; indices[2] == other.indices[2];
</ins><span class="cx">         }
</span><span class="cx">     } u;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueKeyInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueKeyInlines.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueKeyInlines.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/B3ValueKeyInlines.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -49,6 +49,15 @@
</span><span class="cx">     u.indices[1] = right-&gt;index();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline ValueKey::ValueKey(Opcode opcode, Type type, Value* a, Value* b, Value* c)
+    : m_opcode(opcode)
+    , m_type(type)
+{
+    u.indices[0] = a-&gt;index();
+    u.indices[1] = b-&gt;index();
+    u.indices[2] = c-&gt;index();
+}
+
</ins><span class="cx"> inline Value* ValueKey::child(Procedure&amp; proc, unsigned index) const
</span><span class="cx"> {
</span><span class="cx">     return proc.values()[index];
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -364,6 +364,40 @@
</span><span class="cx"> BranchNeg64 U:G, UD:G /branch
</span><span class="cx">     ResCond, Tmp
</span><span class="cx"> 
</span><ins>+MoveConditionally32 U:G, U:G, U:G, U:G, UD:G
+    RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveConditionally64 U:G, U:G, U:G, U:G, UD:G
+    RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveConditionallyTest32 U:G, U:G, U:G, U:G, UD:G
+    ResCond, Tmp, Tmp, Tmp, Tmp
+    ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveConditionallyTest64 U:G, U:G, U:G, U:G, UD:G
+    ResCond, Tmp, Tmp, Tmp, Tmp
+    ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveConditionallyDouble U:G, U:F, U:F, U:G, UD:G
+    DoubleCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionally32 U:G, U:G, U:G, U:F, UD:F
+    RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionally64 U:G, U:G, U:G, U:F, UD:F
+    RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionallyTest32 U:G, U:G, U:G, U:F, UD:F
+    ResCond, Tmp, Tmp, Tmp, Tmp
+    ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveDoubleConditionallyTest64 U:G, U:G, U:G, U:F, UD:F
+    ResCond, Tmp, Tmp, Tmp, Tmp
+    ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveDoubleConditionallyDouble U:G, U:F, U:F, U:F, UD:F
+    DoubleCond, Tmp, Tmp, Tmp, Tmp
+
</ins><span class="cx"> Jump /branch
</span><span class="cx"> 
</span><span class="cx"> Ret /terminal
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -4886,6 +4886,179 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int32_t&gt;(proc, value) == value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testBasicSelect()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Equal, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+                root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 42)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 1, 2) == 1);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 43, 1, 2) == 2);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 43, 642462, 32533) == 32533);
+}
+
+void testSelectTest()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 1, 2) == 1);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 0, 1, 2) == 2);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 0, 642462, 32533) == 32533);
+}
+
+void testSelectCompareDouble()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, LessThan, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;intptr_t&gt;(*code, -1.0, 1.0, 1, 2) == 1);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42.5, 42.51, 642462, 32533) == 642462);
+    CHECK(invoke&lt;intptr_t&gt;(*code, PNaN, 0.0, 1, 2) == 2);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42.51, 42.5, 642462, 32533) == 32533);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42.52, 42.52, 524978245, 352) == 352);
+}
+
+void testSelectDouble()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Equal, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+                root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 42)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;double&gt;(*code, 42, 1.5, 2.6) == 1.5);
+    CHECK(invoke&lt;double&gt;(*code, 42, 642462.7, 32533.8) == 642462.7);
+    CHECK(invoke&lt;double&gt;(*code, 43, 1.9, 2.0) == 2.0);
+    CHECK(invoke&lt;double&gt;(*code, 43, 642462.1, 32533.2) == 32533.2);
+}
+
+void testSelectDoubleTest()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;double&gt;(*code, 42, 1.5, 2.6) == 1.5);
+    CHECK(invoke&lt;double&gt;(*code, 42, 642462.7, 32533.8) == 642462.7);
+    CHECK(invoke&lt;double&gt;(*code, 0, 1.9, 2.0) == 2.0);
+    CHECK(invoke&lt;double&gt;(*code, 0, 642462.1, 32533.2) == 32533.2);
+}
+
+void testSelectDoubleCompareDouble()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, LessThan, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR3)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;double&gt;(*code, -1.0, 1.0, 1.1, 2.2) == 1.1);
+    CHECK(invoke&lt;double&gt;(*code, 42.5, 42.51, 642462.3, 32533.4) == 642462.3);
+    CHECK(invoke&lt;double&gt;(*code, PNaN, 0.0, 1.5, 2.6) == 2.6);
+    CHECK(invoke&lt;double&gt;(*code, 42.51, 42.5, 642462.7, 32533.8) == 32533.8);
+    CHECK(invoke&lt;double&gt;(*code, 42.52, 42.52, 524978245.9, 352.0) == 352.0);
+}
+
+void testSelectFold(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Equal, Origin(),
+                root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), value),
+                root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 42)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 1, 2) == (value == 42 ? 1 : 2));
+    CHECK(invoke&lt;intptr_t&gt;(*code, 642462, 32533) == (value == 42 ? 642462 : 32533));
+}
+
+void testSelectInvert()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Equal, Origin(),
+                root-&gt;appendNew&lt;Value&gt;(
+                    proc, NotEqual, Origin(),
+                    root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+                    root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 42)),
+                root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0)),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+
+    auto code = compile(proc);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 1, 2) == 1);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 43, 1, 2) == 2);
+    CHECK(invoke&lt;intptr_t&gt;(*code, 43, 642462, 32533) == 32533);
+}
+
</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">@@ -5696,6 +5869,16 @@
</span><span class="cx">     RUN(testTruncSExt32(1000000000ll));
</span><span class="cx">     RUN(testTruncSExt32(-1000000000ll));
</span><span class="cx"> 
</span><ins>+    RUN(testBasicSelect());
+    RUN(testSelectTest());
+    RUN(testSelectCompareDouble());
+    RUN(testSelectDouble());
+    RUN(testSelectDoubleTest());
+    RUN(testSelectDoubleCompareDouble());
+    RUN(testSelectFold(42));
+    RUN(testSelectFold(43));
+    RUN(testSelectInvert());
+
</ins><span class="cx">     if (tasks.isEmpty())
</span><span class="cx">         usage();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -82,8 +82,10 @@
</span><span class="cx">     , m_heapNameLength(strlen(heapName))
</span><span class="cx">     , m_offset(offset)
</span><span class="cx">     , m_elementSize(elementSize)
</span><ins>+#if !FTL_USES_B3
</ins><span class="cx">     , m_scaleTerm(0)
</span><span class="cx">     , m_canShift(false)
</span><ins>+#endif
</ins><span class="cx"> {
</span><span class="cx"> #if FTL_USES_B3
</span><span class="cx">     UNUSED_PARAM(context);
</span><span class="lines">@@ -112,7 +114,10 @@
</span><span class="cx"> {
</span><span class="cx">     if (indexAsConstant.isInt32())
</span><span class="cx">         return out.address(base, at(indexAsConstant.asInt32()), offset);
</span><del>-    
</del><ins>+
+#if FTL_USES_B3
+    LValue result = out.add(base, out.mul(index, out.constIntPtr(m_elementSize)));
+#else
</ins><span class="cx">     LValue result;
</span><span class="cx">     if (m_canShift) {
</span><span class="cx">         if (!m_scaleTerm)
</span><span class="lines">@@ -121,6 +126,7 @@
</span><span class="cx">             result = out.add(base, out.shl(index, m_scaleTerm));
</span><span class="cx">     } else
</span><span class="cx">         result = out.add(base, out.mul(index, m_scaleTerm));
</span><ins>+#endif
</ins><span class="cx">     
</span><span class="cx">     return TypedPointer(atAnyIndex(), out.addPtr(result, m_offset + offset));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -188,8 +188,10 @@
</span><span class="cx">     size_t m_heapNameLength;
</span><span class="cx">     ptrdiff_t m_offset;
</span><span class="cx">     size_t m_elementSize;
</span><ins>+#if !FTL_USES_B3
</ins><span class="cx">     LValue m_scaleTerm;
</span><span class="cx">     bool m_canShift;
</span><ins>+#endif
</ins><span class="cx">     std::array&lt;AbstractField, 16&gt; m_smallIndices;
</span><span class="cx">     
</span><span class="cx">     struct WithoutZeroOrOneHashTraits : WTF::GenericHashTraits&lt;ptrdiff_t&gt; {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLB3Outputh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLB3Output.h (192698 => 192699)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLB3Output.h        2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/JavaScriptCore/ftl/FTLB3Output.h        2015-11-20 22:31:19 UTC (rev 192699)
</span><span class="lines">@@ -185,7 +185,11 @@
</span><span class="cx">     LValue unsignedToFP(LValue value, LType type) { CRASH(); }
</span><span class="cx">     LValue unsignedToDouble(LValue value) { CRASH(); }
</span><span class="cx">     LValue intCast(LValue value, LType type) { CRASH(); }
</span><del>-    LValue castToInt32(LValue value) { return m_block-&gt;appendNew&lt;B3::Value&gt;(m_proc, B3::Trunc, origin(), value); }
</del><ins>+    LValue castToInt32(LValue value)
+    {
+        return value-&gt;type() == B3::Int32 ? value :
+            m_block-&gt;appendNew&lt;B3::Value&gt;(m_proc, B3::Trunc, origin(), value);
+    }
</ins><span class="cx">     LValue fpCast(LValue value, LType type) { CRASH(); }
</span><span class="cx">     LValue intToPtr(LValue value, LType type) { CRASH(); }
</span><span class="cx">     LValue ptrToInt(LValue value, LType type) { CRASH(); }
</span><span class="lines">@@ -344,7 +348,7 @@
</span><span class="cx">     LValue testIsZeroPtr(LValue value, LValue mask) { return isNull(bitAnd(value, mask)); }
</span><span class="cx">     LValue testNonZeroPtr(LValue value, LValue mask) { return notNull(bitAnd(value, mask)); }
</span><span class="cx"> 
</span><del>-    LValue select(LValue value, LValue taken, LValue notTaken) { CRASH(); }
</del><ins>+    LValue select(LValue value, LValue taken, LValue notTaken) { return m_block-&gt;appendNew&lt;B3::Value&gt;(m_proc, B3::Select, origin(), value, taken, notTaken); }
</ins><span class="cx">     LValue extractValue(LValue aggVal, unsigned index) { CRASH(); }
</span><span class="cx"> 
</span><span class="cx">     LValue fence(LAtomicOrdering ordering = LLVMAtomicOrderingSequentiallyConsistent, SynchronizationScope scope = CrossThread) { CRASH(); }
</span></span></pre>
</div>
</div>

</body>
</html>