<!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>[197756] releases/WebKitGTK/webkit-2.12/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/197756">197756</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-08 04:57:22 -0800 (Tue, 08 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/197490">r197490</a> - [JSC] Improve Select of Doubles based on Double condition
https://bugs.webkit.org/show_bug.cgi?id=154572

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-03-02
Reviewed by Filip Pizlo.

Octane has a bunch of Select on Double based on comparing Doubles.
A few nodes generate that: ValueRep, Min, Max, etc.

On ARM64, we can improve our code a lot. ARM can do a select
based on flags with the FCSEL instruction.

On x86, this patch adds aggressive aliasing for moveDoubleConditionallyXXX.
This has obviously a much more limited impact.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::moveDoubleConditionally32): Deleted.
(JSC::MacroAssembler::moveDoubleConditionally64): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyTest32): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyTest64): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyDouble): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyFloat): Deleted.
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyDouble):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyFloat):
(JSC::MacroAssemblerARM64::moveConditionally32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally64):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyTest64):
(JSC::MacroAssemblerARM64::branch64):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::moveConditionally32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionally32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyTest32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyDouble):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyFloat):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::moveDoubleConditionally64):
(JSC::MacroAssemblerX86_64::moveDoubleConditionallyTest64):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::Inst::shouldTryAliasingDef):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::populateWithInterestingValues):
(JSC::B3::floatingPointOperands):
(JSC::B3::int64Operands):
(JSC::B3::int32Operands):
(JSC::B3::testSelectCompareFloat):
(JSC::B3::testSelectCompareFloatToDouble):
(JSC::B3::testSelectDoubleCompareDouble):
(JSC::B3::testSelectDoubleCompareDoubleWithAliasing):
(JSC::B3::testSelectFloatCompareFloat):
(JSC::B3::testSelectFloatCompareFloatWithAliasing):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreChangeLog">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerh">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerARM64h">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerX86_64h">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreb3airAirInstInlinesh">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirInstInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreb3airAirOpcodeopcodes">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#releasesWebKitGTKwebkit212SourceJavaScriptCoreb3testb3cpp">releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/testb3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/ChangeLog (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/ChangeLog        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/ChangeLog        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -1,3 +1,61 @@
</span><ins>+2016-03-02  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Improve Select of Doubles based on Double condition
+        https://bugs.webkit.org/show_bug.cgi?id=154572
+
+        Reviewed by Filip Pizlo.
+
+        Octane has a bunch of Select on Double based on comparing Doubles.
+        A few nodes generate that: ValueRep, Min, Max, etc.
+
+        On ARM64, we can improve our code a lot. ARM can do a select
+        based on flags with the FCSEL instruction.
+
+        On x86, this patch adds aggressive aliasing for moveDoubleConditionallyXXX.
+        This has obviously a much more limited impact.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::moveDoubleConditionally32): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionally64): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyTest32): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyTest64): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyDouble): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyFloat): Deleted.
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyDouble):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyFloat):
+        (JSC::MacroAssemblerARM64::moveConditionally32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally64):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyTest64):
+        (JSC::MacroAssemblerARM64::branch64):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::moveConditionally32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionally32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyTest32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyDouble):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyFloat):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::moveDoubleConditionally64):
+        (JSC::MacroAssemblerX86_64::moveDoubleConditionallyTest64):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::Inst::shouldTryAliasingDef):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::populateWithInterestingValues):
+        (JSC::B3::floatingPointOperands):
+        (JSC::B3::int64Operands):
+        (JSC::B3::int32Operands):
+        (JSC::B3::testSelectCompareFloat):
+        (JSC::B3::testSelectCompareFloatToDouble):
+        (JSC::B3::testSelectDoubleCompareDouble):
+        (JSC::B3::testSelectDoubleCompareDoubleWithAliasing):
+        (JSC::B3::testSelectFloatCompareFloat):
+        (JSC::B3::testSelectFloatCompareFloatWithAliasing):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2016-03-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         RegExpPrototype should check for exceptions after calling toString and doing so should not be expensive
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssembler.h (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssembler.h        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -1315,68 +1315,6 @@
</span><span class="cx"> #endif // !CPU(X86_64)
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><del>-    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);
-    }
-
-    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID src, FPRegisterID dest)
-    {
-        Jump falseCase = branchFloat(invert(cond), left, right);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
</del><span class="cx">     // We should implement this the right way eventually, but for now, it's fine because it arises so
</span><span class="cx">     // infrequently.
</span><span class="cx">     void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -1666,6 +1666,39 @@
</span><span class="cx">         m_assembler.csel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template&lt;int datasize&gt;
+    void moveDoubleConditionallyAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (cond == DoubleNotEqual) {
+            Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionNE);
+            unordered.link(this);
+            return;
+        }
+        if (cond == DoubleEqualOrUnordered) {
+            // If the compare is unordered, thenCase is copied to dest and the
+            // next csel has all arguments equal to thenCase.
+            // If the compare is ordered, dest is unchanged and EQ decides
+            // what value to set.
+            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Assembler::ConditionVS);
+            m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, dest, ARM64Assembler::ConditionEQ);
+            return;
+        }
+        m_assembler.fcsel&lt;datasize&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.fcmp&lt;64&gt;(left, right);
+        moveDoubleConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, thenCase, elseCase, dest);
+    }
+
+    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.fcmp&lt;32&gt;(left, right);
+        moveDoubleConditionallyAfterFloatingPointCompare&lt;64&gt;(cond, thenCase, elseCase, dest);
+    }
+
</ins><span class="cx">     void mulDouble(FPRegisterID src, FPRegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         mulDouble(dest, src, dest);
</span><span class="lines">@@ -1938,6 +1971,19 @@
</span><span class="cx">         m_assembler.csel&lt;32&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;32&gt;(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp&lt;32&gt;(left, dataTempRegister);
+        }
+        m_assembler.csel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</ins><span class="cx">     void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.cmp&lt;64&gt;(left, right);
</span><span class="lines">@@ -1974,6 +2020,56 @@
</span><span class="cx">         m_assembler.csel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveDoubleConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.cmp&lt;32&gt;(left, right);
+        m_assembler.fcsel&lt;32&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;32&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;32&gt;(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp&lt;32&gt;(left, dataTempRegister);
+        }
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.cmp&lt;64&gt;(left, right);
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally64(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;64&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;64&gt;(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp&lt;64&gt;(left, dataTempRegister);
+        }
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.tst&lt;32&gt;(left, right);
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyTest64(ResultCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.tst&lt;64&gt;(left, right);
+        m_assembler.fcsel&lt;64&gt;(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
</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">@@ -2063,6 +2159,19 @@
</span><span class="cx">         return Jump(makeBranch(cond));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm32 right)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp&lt;64&gt;(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn&lt;64&gt;(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp&lt;64&gt;(left, dataTempRegister);
+        }
+        return Jump(makeBranch(cond));
+    }
+
</ins><span class="cx">     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
</span><span class="cx">     {
</span><span class="cx">         intptr_t immediate = right.m_value;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -1777,6 +1777,24 @@
</span><span class="cx">             cmov(x86Condition(invert(cond)), elseCase, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (((cond == Equal) || (cond == NotEqual)) &amp;&amp; !right.m_value)
+            m_assembler.testl_rr(left, left);
+        else
+            m_assembler.cmpl_ir(right.m_value, left);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
</ins><span class="cx">     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.testl_rr(testReg, mask);
</span><span class="lines">@@ -1825,6 +1843,90 @@
</span><span class="cx">             cmov(x86Condition(invert(cond)), elseCase, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template&lt;typename LeftType, typename RightType&gt;
+    void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same&lt;LeftType, FPRegisterID&gt;::value &amp;&amp; !std::is_same&lt;RightType, FPRegisterID&gt;::value, &quot;One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().&quot;);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            moveDouble(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest) {
+            Jump falseCase = branch32(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else {
+            Jump trueCase = branch32(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+    }
+
+    template&lt;typename TestType, typename MaskType&gt;
+    void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same&lt;TestType, FPRegisterID&gt;::value &amp;&amp; !std::is_same&lt;MaskType, FPRegisterID&gt;::value, &quot;One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().&quot;);
+
+        if (elseCase == dest &amp;&amp; isInvertible(cond)) {
+            Jump falseCase = branchTest32(invert(cond), test, mask);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchTest32(cond, test, mask);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+
+        Jump trueCase = branchTest32(cond, test, mask);
+        moveDouble(elseCase, dest);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(thenCase, dest);
+        falseCase.link(this);
+    }
+
+    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (elseCase == dest) {
+            Jump falseCase = branchDouble(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchDouble(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        } else {
+            Jump trueCase = branchDouble(cond, left, right);
+            moveDouble(elseCase, dest);
+            Jump falseCase = jump();
+            trueCase.link(this);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        }
+    }
+
+    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (elseCase == dest) {
+            Jump falseCase = branchFloat(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchFloat(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        } else {
+            Jump trueCase = branchFloat(cond, left, right);
+            moveDouble(elseCase, dest);
+            Jump falseCase = jump();
+            trueCase.link(this);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        }
+    }
+
</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></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -1052,6 +1052,50 @@
</span><span class="cx">         else
</span><span class="cx">             cmov(x86Condition(invert(cond)), elseCase, dest);
</span><span class="cx">     }
</span><ins>+
+    template&lt;typename LeftType, typename RightType&gt;
+    void moveDoubleConditionally64(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same&lt;LeftType, FPRegisterID&gt;::value &amp;&amp; !std::is_same&lt;RightType, FPRegisterID&gt;::value, &quot;One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().&quot;);
+
+        if (thenCase != dest &amp;&amp; elseCase != dest) {
+            moveDouble(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest) {
+            Jump falseCase = branch64(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else {
+            Jump trueCase = branch64(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+    }
+
+    template&lt;typename TestType, typename MaskType&gt;
+    void moveDoubleConditionallyTest64(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same&lt;TestType, FPRegisterID&gt;::value &amp;&amp; !std::is_same&lt;MaskType, FPRegisterID&gt;::value, &quot;One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().&quot;);
+
+        if (elseCase == dest &amp;&amp; isInvertible(cond)) {
+            Jump falseCase = branchTest64(invert(cond), test, mask);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchTest64(cond, test, mask);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+
+        Jump trueCase = branchTest64(cond, test, mask);
+        moveDouble(elseCase, dest);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(thenCase, dest);
+        falseCase.link(this);
+    }
</ins><span class="cx">     
</span><span class="cx">     void abortWithReason(AbortReason reason)
</span><span class="cx">     {
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreb3airAirInstInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirInstInlines.h (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -202,6 +202,12 @@
</span><span class="cx">     case MoveConditionallyTest64:
</span><span class="cx">     case MoveConditionallyDouble:
</span><span class="cx">     case MoveConditionallyFloat:
</span><ins>+    case MoveDoubleConditionally32:
+    case MoveDoubleConditionally64:
+    case MoveDoubleConditionallyTest32:
+    case MoveDoubleConditionallyTest64:
+    case MoveDoubleConditionallyDouble:
+    case MoveDoubleConditionallyFloat:
</ins><span class="cx">         if (args.size() == 6)
</span><span class="cx">             return 5;
</span><span class="cx">         break;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -632,7 +632,7 @@
</span><span class="cx"> 
</span><span class="cx"> 64: Branch64 U:G:32, U:G:64, U:G:64 /branch
</span><span class="cx">     RelCond, Tmp, Tmp
</span><del>-    x86: RelCond, Tmp, Imm
</del><ins>+    RelCond, Tmp, Imm
</ins><span class="cx">     x86: RelCond, Tmp, Addr
</span><span class="cx">     x86: RelCond, Addr, Tmp
</span><span class="cx">     x86: RelCond, Addr, Imm
</span><span class="lines">@@ -723,6 +723,7 @@
</span><span class="cx"> 
</span><span class="cx"> MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
</span><ins>+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><span class="cx"> 64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="lines">@@ -758,25 +759,42 @@
</span><span class="cx"> MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
</span><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
-    RelCond, Tmp, Tmp, Tmp, Tmp
</del><ins>+MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86: RelCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
+    x86: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86: RelCond, Index, Imm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><del>-64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
-    RelCond, Tmp, Tmp, Tmp, Tmp
</del><ins>+64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86_64: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
+    x86_64: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86_64: RelCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86_64: RelCond, Index, Tmp, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><del>-MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
-    ResCond, Tmp, Tmp, Tmp, Tmp
-    x86: ResCond, Tmp, Imm, Tmp, Tmp
</del><ins>+MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86: ResCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86: ResCond, Index, Imm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><del>-64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
-    ResCond, Tmp, Tmp, Tmp, Tmp
-    ResCond, Tmp, Imm, Tmp, Tmp
</del><ins>+# Warning: forms that take an immediate will sign-extend their immediate. You probably want
+# MoveDoubleConditionallyTest32 in most cases where you use an immediate.
+64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86_64: ResCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86_64: ResCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86_64: ResCond, Index, Imm, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><del>-MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, UD:F:64
-    DoubleCond, Tmp, Tmp, Tmp, Tmp
</del><ins>+MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, U:F:64, D:F:64
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><del>-MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, UD:F:64
-    DoubleCond, Tmp, Tmp, Tmp, Tmp
</del><ins>+MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, U:F:64, D:F:64
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><span class="cx"> Jump /branch
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit212SourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/testb3.cpp (197755 => 197756)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/testb3.cpp        2016-03-08 12:21:28 UTC (rev 197755)
+++ releases/WebKitGTK/webkit-2.12/Source/JavaScriptCore/b3/testb3.cpp        2016-03-08 12:57:22 UTC (rev 197756)
</span><span class="lines">@@ -104,6 +104,78 @@
</span><span class="cx">     return invoke&lt;T&gt;(*compile(procedure), arguments...);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename Type&gt;
+struct Operand {
+    const char* name;
+    Type value;
+};
+
+typedef Operand&lt;int64_t&gt; Int64Operand;
+typedef Operand&lt;int32_t&gt; Int32Operand;
+
+template&lt;typename FloatType&gt;
+void populateWithInterestingValues(Vector&lt;Operand&lt;FloatType&gt;&gt;&amp; operands)
+{
+    operands.append({ &quot;0.&quot;, static_cast&lt;FloatType&gt;(0.) });
+    operands.append({ &quot;-0.&quot;, static_cast&lt;FloatType&gt;(-0.) });
+    operands.append({ &quot;0.4&quot;, static_cast&lt;FloatType&gt;(0.5) });
+    operands.append({ &quot;-0.4&quot;, static_cast&lt;FloatType&gt;(-0.5) });
+    operands.append({ &quot;0.5&quot;, static_cast&lt;FloatType&gt;(0.5) });
+    operands.append({ &quot;-0.5&quot;, static_cast&lt;FloatType&gt;(-0.5) });
+    operands.append({ &quot;0.6&quot;, static_cast&lt;FloatType&gt;(0.5) });
+    operands.append({ &quot;-0.6&quot;, static_cast&lt;FloatType&gt;(-0.5) });
+    operands.append({ &quot;1.&quot;, static_cast&lt;FloatType&gt;(1.) });
+    operands.append({ &quot;-1.&quot;, static_cast&lt;FloatType&gt;(-1.) });
+    operands.append({ &quot;2.&quot;, static_cast&lt;FloatType&gt;(2.) });
+    operands.append({ &quot;-2.&quot;, static_cast&lt;FloatType&gt;(-2.) });
+    operands.append({ &quot;M_PI&quot;, static_cast&lt;FloatType&gt;(M_PI) });
+    operands.append({ &quot;-M_PI&quot;, static_cast&lt;FloatType&gt;(-M_PI) });
+    operands.append({ &quot;min&quot;, std::numeric_limits&lt;FloatType&gt;::min() });
+    operands.append({ &quot;max&quot;, std::numeric_limits&lt;FloatType&gt;::max() });
+    operands.append({ &quot;lowest&quot;, std::numeric_limits&lt;FloatType&gt;::lowest() });
+    operands.append({ &quot;epsilon&quot;, std::numeric_limits&lt;FloatType&gt;::epsilon() });
+    operands.append({ &quot;infiniti&quot;, std::numeric_limits&lt;FloatType&gt;::infinity() });
+    operands.append({ &quot;-infiniti&quot;, - std::numeric_limits&lt;FloatType&gt;::infinity() });
+    operands.append({ &quot;PNaN&quot;, static_cast&lt;FloatType&gt;(PNaN) });
+}
+
+template&lt;typename FloatType&gt;
+Vector&lt;Operand&lt;FloatType&gt;&gt; floatingPointOperands()
+{
+    Vector&lt;Operand&lt;FloatType&gt;&gt; operands;
+    populateWithInterestingValues(operands);
+    return operands;
+};
+
+static Vector&lt;Int64Operand&gt; int64Operands()
+{
+    Vector&lt;Int64Operand&gt; operands;
+    for (const auto&amp; doubleOperand : floatingPointOperands&lt;double&gt;())
+        operands.append({ doubleOperand.name, bitwise_cast&lt;int64_t&gt;(doubleOperand.value) });
+    operands.append({ &quot;1&quot;, 1 });
+    operands.append({ &quot;-1&quot;, -1 });
+    operands.append({ &quot;int64-max&quot;, std::numeric_limits&lt;int64_t&gt;::max() });
+    operands.append({ &quot;int64-min&quot;, std::numeric_limits&lt;int64_t&gt;::min() });
+    operands.append({ &quot;int32-max&quot;, std::numeric_limits&lt;int32_t&gt;::max() });
+    operands.append({ &quot;int32-min&quot;, std::numeric_limits&lt;int32_t&gt;::min() });
+
+    return operands;
+}
+
+static Vector&lt;Int32Operand&gt; int32Operands()
+{
+    Vector&lt;Int32Operand&gt; operands({
+        { &quot;0&quot;, 0 },
+        { &quot;1&quot;, 1 },
+        { &quot;-1&quot;, -1 },
+        { &quot;42&quot;, 42 },
+        { &quot;-42&quot;, -42 },
+        { &quot;int32-max&quot;, std::numeric_limits&lt;int32_t&gt;::max() },
+        { &quot;int32-min&quot;, std::numeric_limits&lt;int32_t&gt;::min() }
+    });
+    return operands;
+}
+
</ins><span class="cx"> void add32(CCallHelpers&amp; jit, GPRReg src1, GPRReg src2, GPRReg dest)
</span><span class="cx"> {
</span><span class="cx">     if (src2 == dest)
</span><span class="lines">@@ -9856,6 +9928,7 @@
</span><span class="cx">     testSelectCompareFloat&lt;GreaterThan&gt;(a, b, [](float a, float b) -&gt; bool { return a &gt; b; });
</span><span class="cx">     testSelectCompareFloat&lt;LessEqual&gt;(a, b, [](float a, float b) -&gt; bool { return a &lt;= b; });
</span><span class="cx">     testSelectCompareFloat&lt;GreaterEqual&gt;(a, b, [](float a, float b) -&gt; bool { return a &gt;= b; });
</span><ins>+    testSelectCompareFloat&lt;EqualOrUnordered&gt;(a, b, [](float a, float b) -&gt; bool { return a != a || b != b || a == b; });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;B3::Opcode opcode&gt;
</span><span class="lines">@@ -9893,6 +9966,7 @@
</span><span class="cx">     testSelectCompareFloatToDouble&lt;GreaterThan&gt;(a, b, [](float a, float b) -&gt; bool { return a &gt; b; });
</span><span class="cx">     testSelectCompareFloatToDouble&lt;LessEqual&gt;(a, b, [](float a, float b) -&gt; bool { return a &lt;= b; });
</span><span class="cx">     testSelectCompareFloatToDouble&lt;GreaterEqual&gt;(a, b, [](float a, float b) -&gt; bool { return a &gt;= b; });
</span><ins>+    testSelectCompareFloatToDouble&lt;EqualOrUnordered&gt;(a, b, [](float a, float b) -&gt; bool { return a != a || b != b || a == b; });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void testSelectDouble()
</span><span class="lines">@@ -10015,6 +10089,406 @@
</span><span class="cx">     CHECK(isIdentical(compileAndRun&lt;float&gt;(proc, bitwise_cast&lt;int32_t&gt;(a), bitwise_cast&lt;int32_t&gt;(b), bitwise_cast&lt;int32_t&gt;(1.1f), bitwise_cast&lt;int32_t&gt;(-42.f)), a &lt; b ? 1.1f : -42.f));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+template&lt;B3::Opcode opcode&gt;
+void testSelectDoubleCompareDouble(bool (*operation)(double, double))
+{
+    { // Compare arguments and selected arguments are all different.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR3);
+
+        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, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg3));
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. &quot;thenCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. &quot;elseCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. Both cases are live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the &quot;elseCase&quot; argument.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+
+        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, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg0));
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, left.value), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the &quot;elseCase&quot; argument. &quot;thenCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), FPRInfo::argumentFPR2);
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg0);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;double&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;double&gt;()) {
+                double expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke&lt;double&gt;(*code, left.value, right.value, 42.5, left.value), expected));
+            }
+        }
+    }
+}
+
+void testSelectDoubleCompareDoubleWithAliasing()
+{
+    testSelectDoubleCompareDouble&lt;Equal&gt;([](double a, double b) -&gt; bool { return a == b; });
+    testSelectDoubleCompareDouble&lt;NotEqual&gt;([](double a, double b) -&gt; bool { return a != b; });
+    testSelectDoubleCompareDouble&lt;LessThan&gt;([](double a, double b) -&gt; bool { return a &lt; b; });
+    testSelectDoubleCompareDouble&lt;GreaterThan&gt;([](double a, double b) -&gt; bool { return a &gt; b; });
+    testSelectDoubleCompareDouble&lt;LessEqual&gt;([](double a, double b) -&gt; bool { return a &lt;= b; });
+    testSelectDoubleCompareDouble&lt;GreaterEqual&gt;([](double a, double b) -&gt; bool { return a &gt;= b; });
+    testSelectDoubleCompareDouble&lt;EqualOrUnordered&gt;([](double a, double b) -&gt; bool { return a != a || b != b || a == b; });
+}
+
+template&lt;B3::Opcode opcode&gt;
+void testSelectFloatCompareFloat(bool (*operation)(float, float))
+{
+    { // Compare arguments and selected arguments are all different.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        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, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg3));
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. &quot;thenCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. &quot;elseCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. Both cases are live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(-66.5f)), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the &quot;elseCase&quot; argument.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+
+        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, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg0));
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(left.value)), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the &quot;elseCase&quot; argument. &quot;thenCase&quot; is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root-&gt;appendNew&lt;Value&gt;(proc, BitwiseCast, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2)));
+
+        Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Select, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg0);
+
+        PatchpointValue* keepValuesLive = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Void, Origin());
+        keepValuesLive-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive-&gt;setGenerator([&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) { });
+
+        root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto&amp; left : floatingPointOperands&lt;float&gt;()) {
+            for (auto&amp; right : floatingPointOperands&lt;float&gt;()) {
+                float expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke&lt;float&gt;(*code, bitwise_cast&lt;int32_t&gt;(left.value), bitwise_cast&lt;int32_t&gt;(right.value), bitwise_cast&lt;int32_t&gt;(42.5f), bitwise_cast&lt;int32_t&gt;(left.value)), expected));
+            }
+        }
+    }
+}
+
+void testSelectFloatCompareFloatWithAliasing()
+{
+    testSelectFloatCompareFloat&lt;Equal&gt;([](float a, float b) -&gt; bool { return a == b; });
+    testSelectFloatCompareFloat&lt;NotEqual&gt;([](float a, float b) -&gt; bool { return a != b; });
+    testSelectFloatCompareFloat&lt;LessThan&gt;([](float a, float b) -&gt; bool { return a &lt; b; });
+    testSelectFloatCompareFloat&lt;GreaterThan&gt;([](float a, float b) -&gt; bool { return a &gt; b; });
+    testSelectFloatCompareFloat&lt;LessEqual&gt;([](float a, float b) -&gt; bool { return a &lt;= b; });
+    testSelectFloatCompareFloat&lt;GreaterEqual&gt;([](float a, float b) -&gt; bool { return a &gt;= b; });
+    testSelectFloatCompareFloat&lt;EqualOrUnordered&gt;([](float a, float b) -&gt; bool { return a != a || b != b || a == b; });
+}
+
</ins><span class="cx"> void testSelectFold(intptr_t value)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -10701,78 +11175,8 @@
</span><span class="cx">     return -zero();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;typename Type&gt;
-struct Operand {
-    const char* name;
-    Type value;
-};
</del><span class="cx"> 
</span><del>-typedef Operand&lt;int64_t&gt; Int64Operand;
-typedef Operand&lt;int32_t&gt; Int32Operand;
</del><span class="cx"> 
</span><del>-template&lt;typename FloatType&gt;
-void populateWithInterestingValues(Vector&lt;Operand&lt;FloatType&gt;&gt;&amp; operands)
-{
-    operands.append({ &quot;0.&quot;, static_cast&lt;FloatType&gt;(0.) });
-    operands.append({ &quot;-0.&quot;, static_cast&lt;FloatType&gt;(-0.) });
-    operands.append({ &quot;0.4&quot;, static_cast&lt;FloatType&gt;(0.5) });
-    operands.append({ &quot;-0.4&quot;, static_cast&lt;FloatType&gt;(-0.5) });
-    operands.append({ &quot;0.5&quot;, static_cast&lt;FloatType&gt;(0.5) });
-    operands.append({ &quot;-0.5&quot;, static_cast&lt;FloatType&gt;(-0.5) });
-    operands.append({ &quot;0.6&quot;, static_cast&lt;FloatType&gt;(0.5) });
-    operands.append({ &quot;-0.6&quot;, static_cast&lt;FloatType&gt;(-0.5) });
-    operands.append({ &quot;1.&quot;, static_cast&lt;FloatType&gt;(1.) });
-    operands.append({ &quot;-1.&quot;, static_cast&lt;FloatType&gt;(-1.) });
-    operands.append({ &quot;2.&quot;, static_cast&lt;FloatType&gt;(2.) });
-    operands.append({ &quot;-2.&quot;, static_cast&lt;FloatType&gt;(-2.) });
-    operands.append({ &quot;M_PI&quot;, static_cast&lt;FloatType&gt;(M_PI) });
-    operands.append({ &quot;-M_PI&quot;, static_cast&lt;FloatType&gt;(-M_PI) });
-    operands.append({ &quot;min&quot;, std::numeric_limits&lt;FloatType&gt;::min() });
-    operands.append({ &quot;max&quot;, std::numeric_limits&lt;FloatType&gt;::max() });
-    operands.append({ &quot;lowest&quot;, std::numeric_limits&lt;FloatType&gt;::lowest() });
-    operands.append({ &quot;epsilon&quot;, std::numeric_limits&lt;FloatType&gt;::epsilon() });
-    operands.append({ &quot;infiniti&quot;, std::numeric_limits&lt;FloatType&gt;::infinity() });
-    operands.append({ &quot;-infiniti&quot;, - std::numeric_limits&lt;FloatType&gt;::infinity() });
-    operands.append({ &quot;PNaN&quot;, static_cast&lt;FloatType&gt;(PNaN) });
-}
-
-template&lt;typename FloatType&gt;
-Vector&lt;Operand&lt;FloatType&gt;&gt; floatingPointOperands()
-{
-    Vector&lt;Operand&lt;FloatType&gt;&gt; operands;
-    populateWithInterestingValues(operands);
-    return operands;
-};
-
-static Vector&lt;Int64Operand&gt; int64Operands()
-{
-    Vector&lt;Int64Operand&gt; operands;
-    for (const auto&amp; doubleOperand : floatingPointOperands&lt;double&gt;())
-        operands.append({ doubleOperand.name, bitwise_cast&lt;int64_t&gt;(doubleOperand.value) });
-    operands.append({ &quot;1&quot;, 1 });
-    operands.append({ &quot;-1&quot;, -1 });
-    operands.append({ &quot;int64-max&quot;, std::numeric_limits&lt;int64_t&gt;::max() });
-    operands.append({ &quot;int64-min&quot;, std::numeric_limits&lt;int64_t&gt;::min() });
-    operands.append({ &quot;int32-max&quot;, std::numeric_limits&lt;int32_t&gt;::max() });
-    operands.append({ &quot;int32-min&quot;, std::numeric_limits&lt;int32_t&gt;::min() });
-
-    return operands;
-}
-
-static Vector&lt;Int32Operand&gt; int32Operands()
-{
-    Vector&lt;Int32Operand&gt; operands({
-        { &quot;0&quot;, 0 },
-        { &quot;1&quot;, 1 },
-        { &quot;-1&quot;, -1 },
-        { &quot;42&quot;, 42 },
-        { &quot;-42&quot;, -42 },
-        { &quot;int32-max&quot;, std::numeric_limits&lt;int32_t&gt;::max() },
-        { &quot;int32-min&quot;, std::numeric_limits&lt;int32_t&gt;::min() }
-    });
-    return operands;
-}
-
</del><span class="cx"> #define RUN(test) do {                          \
</span><span class="cx">         if (!shouldRun(#test))                  \
</span><span class="cx">             break;                              \
</span><span class="lines">@@ -11978,6 +12382,8 @@
</span><span class="cx">     RUN(testSelectDoubleCompareDouble());
</span><span class="cx">     RUN_BINARY(testSelectDoubleCompareFloat, floatingPointOperands&lt;float&gt;(), floatingPointOperands&lt;float&gt;());
</span><span class="cx">     RUN_BINARY(testSelectFloatCompareFloat, floatingPointOperands&lt;float&gt;(), floatingPointOperands&lt;float&gt;());
</span><ins>+    RUN(testSelectDoubleCompareDoubleWithAliasing());
+    RUN(testSelectFloatCompareFloatWithAliasing());
</ins><span class="cx">     RUN(testSelectFold(42));
</span><span class="cx">     RUN(testSelectFold(43));
</span><span class="cx">     RUN(testSelectInvert());
</span></span></pre>
</div>
</div>

</body>
</html>