<!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>[208848] 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/208848">208848</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-11-17 09:52:03 -0800 (Thu, 17 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add support for rotate in B3 and the relevant assemblers
https://bugs.webkit.org/show_bug.cgi?id=164869

Reviewed by Geoffrey Garen.

This patch runs RotR and RotL (rotate right and left respectively)
through B3 and B3's assemblers. One thing of note is that ARM64 does
not support rotate left instead it allows negative right rotations.

This patch also fixes a theoretical bug in the assembler where
on X86 doing someShiftOp(reg, edx) would instead shift the shift
amount by the value. Additionally, this patch refactors some
of the X86 assembler to use templates when deciding how to format
the appropriate shift instruction.

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::rotateRight32):
(JSC::MacroAssemblerARM64::rotateRight64):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::rotateRight32):
(JSC::MacroAssemblerX86Common::rotateLeft32):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::lshift64):
(JSC::MacroAssemblerX86_64::rshift64):
(JSC::MacroAssemblerX86_64::urshift64):
(JSC::MacroAssemblerX86_64::rotateRight64):
(JSC::MacroAssemblerX86_64::rotateLeft64):
(JSC::MacroAssemblerX86_64::or64):
* assembler/X86Assembler.h:
(JSC::X86Assembler::xorq_rm):
(JSC::X86Assembler::shiftInstruction32):
(JSC::X86Assembler::sarl_i8r):
(JSC::X86Assembler::shrl_i8r):
(JSC::X86Assembler::shll_i8r):
(JSC::X86Assembler::rorl_i8r):
(JSC::X86Assembler::rorl_CLr):
(JSC::X86Assembler::roll_i8r):
(JSC::X86Assembler::roll_CLr):
(JSC::X86Assembler::shiftInstruction64):
(JSC::X86Assembler::sarq_CLr):
(JSC::X86Assembler::sarq_i8r):
(JSC::X86Assembler::shrq_i8r):
(JSC::X86Assembler::shlq_i8r):
(JSC::X86Assembler::rorq_i8r):
(JSC::X86Assembler::rorq_CLr):
(JSC::X86Assembler::rolq_i8r):
(JSC::X86Assembler::rolq_CLr):
* b3/B3Common.h:
(JSC::B3::rotateRight):
(JSC::B3::rotateLeft):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::rotRConstant):
(JSC::B3::Const32Value::rotLConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::rotRConstant):
(JSC::B3::Const64Value::rotLConstant):
* b3/B3Const64Value.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3ReduceStrength.cpp:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::rotRConstant):
(JSC::B3::Value::rotLConstant):
(JSC::B3::Value::effects):
(JSC::B3::Value::key):
(JSC::B3::Value::typeFor):
* b3/B3Value.h:
* b3/B3ValueKey.cpp:
(JSC::B3::ValueKey::materialize):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::isRotateRight32Valid):
(JSC::B3::Air::isRotateLeft32Valid):
(JSC::B3::Air::isRotateRight64Valid):
(JSC::B3::Air::isRotateLeft64Valid):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::testRotR):
(JSC::B3::testRotL):
(JSC::B3::testRotRWithImmShift):
(JSC::B3::testRotLWithImmShift):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.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="#trunkSourceJavaScriptCoreb3B3Commonh">trunk/Source/JavaScriptCore/b3/B3Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valueh">trunk/Source/JavaScriptCore/b3/B3Const32Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valueh">trunk/Source/JavaScriptCore/b3/B3Const64Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.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="#trunkSourceJavaScriptCoreb3airAirInstInlinesh">trunk/Source/JavaScriptCore/b3/air/AirInstInlines.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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -1,3 +1,92 @@
</span><ins>+2016-11-17  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        Add support for rotate in B3 and the relevant assemblers
+        https://bugs.webkit.org/show_bug.cgi?id=164869
+
+        Reviewed by Geoffrey Garen.
+
+        This patch runs RotR and RotL (rotate right and left respectively)
+        through B3 and B3's assemblers. One thing of note is that ARM64 does
+        not support rotate left instead it allows negative right rotations.
+
+        This patch also fixes a theoretical bug in the assembler where
+        on X86 doing someShiftOp(reg, edx) would instead shift the shift
+        amount by the value. Additionally, this patch refactors some
+        of the X86 assembler to use templates when deciding how to format
+        the appropriate shift instruction.
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::rotateRight32):
+        (JSC::MacroAssemblerARM64::rotateRight64):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::rotateRight32):
+        (JSC::MacroAssemblerX86Common::rotateLeft32):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::lshift64):
+        (JSC::MacroAssemblerX86_64::rshift64):
+        (JSC::MacroAssemblerX86_64::urshift64):
+        (JSC::MacroAssemblerX86_64::rotateRight64):
+        (JSC::MacroAssemblerX86_64::rotateLeft64):
+        (JSC::MacroAssemblerX86_64::or64):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::xorq_rm):
+        (JSC::X86Assembler::shiftInstruction32):
+        (JSC::X86Assembler::sarl_i8r):
+        (JSC::X86Assembler::shrl_i8r):
+        (JSC::X86Assembler::shll_i8r):
+        (JSC::X86Assembler::rorl_i8r):
+        (JSC::X86Assembler::rorl_CLr):
+        (JSC::X86Assembler::roll_i8r):
+        (JSC::X86Assembler::roll_CLr):
+        (JSC::X86Assembler::shiftInstruction64):
+        (JSC::X86Assembler::sarq_CLr):
+        (JSC::X86Assembler::sarq_i8r):
+        (JSC::X86Assembler::shrq_i8r):
+        (JSC::X86Assembler::shlq_i8r):
+        (JSC::X86Assembler::rorq_i8r):
+        (JSC::X86Assembler::rorq_CLr):
+        (JSC::X86Assembler::rolq_i8r):
+        (JSC::X86Assembler::rolq_CLr):
+        * b3/B3Common.h:
+        (JSC::B3::rotateRight):
+        (JSC::B3::rotateLeft):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::rotRConstant):
+        (JSC::B3::Const32Value::rotLConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::rotRConstant):
+        (JSC::B3::Const64Value::rotLConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3Opcode.cpp:
+        (WTF::printInternal):
+        * b3/B3Opcode.h:
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::rotRConstant):
+        (JSC::B3::Value::rotLConstant):
+        (JSC::B3::Value::effects):
+        (JSC::B3::Value::key):
+        (JSC::B3::Value::typeFor):
+        * b3/B3Value.h:
+        * b3/B3ValueKey.cpp:
+        (JSC::B3::ValueKey::materialize):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::isRotateRight32Valid):
+        (JSC::B3::Air::isRotateLeft32Valid):
+        (JSC::B3::Air::isRotateRight64Valid):
+        (JSC::B3::Air::isRotateLeft64Valid):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::testRotR):
+        (JSC::B3::testRotL):
+        (JSC::B3::testRotRWithImmShift):
+        (JSC::B3::testRotLWithImmShift):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2016-11-17  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove async/await compile time flag and enable tests
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -664,11 +664,36 @@
</span><span class="cx">         m_assembler.orr&lt;64&gt;(dest, dest, dataTempRegister);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void rotateRight32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.ror&lt;32&gt;(dest, src, imm.m_value &amp; 31);
+    }
+
+    void rotateRight32(TrustedImm32 imm, RegisterID srcDst)
+    {
+        rotateRight32(srcDst, imm, srcDst);
+    }
+
+    void rotateRight32(RegisterID src, RegisterID shiftAmmount, RegisterID dest)
+    {
+        m_assembler.ror&lt;32&gt;(dest, src, shiftAmmount);
+    }
+
+    void rotateRight64(RegisterID src, TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.ror&lt;64&gt;(dest, src, imm.m_value &amp; 63);
+    }
+
</ins><span class="cx">     void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
</span><span class="cx">     {
</span><del>-        m_assembler.ror&lt;64&gt;(srcDst, srcDst, imm.m_value &amp; 63);
</del><ins>+        rotateRight64(srcDst, imm, srcDst);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void rotateRight64(RegisterID src, RegisterID shiftAmmount, RegisterID dest)
+    {
+        m_assembler.ror&lt;64&gt;(dest, src, shiftAmmount);
+    }
+
</ins><span class="cx">     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.asr&lt;32&gt;(dest, src, shiftAmount);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -566,7 +566,45 @@
</span><span class="cx">         move32IfNeeded(src, dest);
</span><span class="cx">         urshift32(imm, dest);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    void rotateRight32(TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.rorl_i8r(imm.m_value, dest);
+    }
+
+    void rotateRight32(RegisterID src, RegisterID dest)
+    {
+        if (src == X86Registers::ecx)
+            m_assembler.rorl_CLr(dest);
+        else {
+            ASSERT(src != dest);
+
+            // Can only rotate by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.rorl_CLr(dest == X86Registers::ecx ? src : dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
+    void rotateLeft32(TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.roll_i8r(imm.m_value, dest);
+    }
+
+    void rotateLeft32(RegisterID src, RegisterID dest)
+    {
+        if (src == X86Registers::ecx)
+            m_assembler.roll_CLr(dest);
+        else {
+            ASSERT(src != dest);
+
+            // Can only rotate by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.roll_CLr(dest == X86Registers::ecx ? src : dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
</ins><span class="cx">     void sub32(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.subl_rr(src, dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -402,10 +402,10 @@
</span><span class="cx">             m_assembler.shlq_CLr(dest);
</span><span class="cx">         else {
</span><span class="cx">             ASSERT(src != dest);
</span><del>-            
</del><ins>+
</ins><span class="cx">             // Can only shift by ecx, so we do some swapping if we see anything else.
</span><span class="cx">             swap(src, X86Registers::ecx);
</span><del>-            m_assembler.shlq_CLr(dest);
</del><ins>+            m_assembler.shlq_CLr(dest == X86Registers::ecx ? src : dest);
</ins><span class="cx">             swap(src, X86Registers::ecx);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -424,7 +424,7 @@
</span><span class="cx">             
</span><span class="cx">             // Can only shift by ecx, so we do some swapping if we see anything else.
</span><span class="cx">             swap(src, X86Registers::ecx);
</span><del>-            m_assembler.sarq_CLr(dest);
</del><ins>+            m_assembler.sarq_CLr(dest == X86Registers::ecx ? src : dest);
</ins><span class="cx">             swap(src, X86Registers::ecx);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -443,11 +443,49 @@
</span><span class="cx">             
</span><span class="cx">             // Can only shift by ecx, so we do some swapping if we see anything else.
</span><span class="cx">             swap(src, X86Registers::ecx);
</span><del>-            m_assembler.shrq_CLr(dest);
</del><ins>+            m_assembler.shrq_CLr(dest == X86Registers::ecx ? src : dest);
</ins><span class="cx">             swap(src, X86Registers::ecx);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void rotateRight64(TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.rorq_i8r(imm.m_value, dest);
+    }
+
+    void rotateRight64(RegisterID src, RegisterID dest)
+    {
+        if (src == X86Registers::ecx)
+            m_assembler.rorq_CLr(dest);
+        else {
+            ASSERT(src != dest);
+
+            // Can only rotate by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.rorq_CLr(dest == X86Registers::ecx ? src : dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
+    void rotateLeft64(TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.rolq_i8r(imm.m_value, dest);
+    }
+
+    void rotateLeft64(RegisterID src, RegisterID dest)
+    {
+        if (src == X86Registers::ecx)
+            m_assembler.rolq_CLr(dest);
+        else {
+            ASSERT(src != dest);
+
+            // Can only rotate by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.rolq_CLr(dest == X86Registers::ecx ? src : dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
</ins><span class="cx">     void mul64(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.imulq_rr(src, dest);
</span><span class="lines">@@ -542,11 +580,6 @@
</span><span class="cx">         move(src, dest);
</span><span class="cx">         or64(imm, dest);
</span><span class="cx">     }
</span><del>-    
-    void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
-    {
-        m_assembler.rorq_i8r(imm.m_value, srcDst);
-    }
</del><span class="cx"> 
</span><span class="cx">     void sub64(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -967,16 +967,6 @@
</span><span class="cx">     {
</span><span class="cx">         m_formatter.oneByteOp64(OP_XOR_EvGv, src, base, offset);
</span><span class="cx">     }
</span><del>-    
-    void rorq_i8r(int imm, RegisterID dst)
-    {
-        if (imm == 1)
-            m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_ROR, dst);
-        else {
-            m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_ROR, dst);
-            m_formatter.immediate8(imm);
-        }
-    }
</del><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -1028,16 +1018,24 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    void sarl_i8r(int imm, RegisterID dst)
</del><ins>+private:
+    template&lt;GroupOpcodeID op&gt;
+    void shiftInstruction32(int imm, RegisterID dst)
</ins><span class="cx">     {
</span><span class="cx">         if (imm == 1)
</span><del>-            m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
</del><ins>+            m_formatter.oneByteOp(OP_GROUP2_Ev1, op, dst);
</ins><span class="cx">         else {
</span><del>-            m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
</del><ins>+            m_formatter.oneByteOp(OP_GROUP2_EvIb, op, dst);
</ins><span class="cx">             m_formatter.immediate8(imm);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+public:
</ins><span class="cx"> 
</span><ins>+    void sarl_i8r(int imm, RegisterID dst)
+    {
+        shiftInstruction32&lt;GROUP2_OP_SAR&gt;(imm, dst);
+    }
+
</ins><span class="cx">     void sarl_CLr(RegisterID dst)
</span><span class="cx">     {
</span><span class="cx">         m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
</span><span class="lines">@@ -1045,12 +1043,7 @@
</span><span class="cx">     
</span><span class="cx">     void shrl_i8r(int imm, RegisterID dst)
</span><span class="cx">     {
</span><del>-        if (imm == 1)
-            m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
-        else {
-            m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
-            m_formatter.immediate8(imm);
-        }
</del><ins>+        shiftInstruction32&lt;GROUP2_OP_SHR&gt;(imm, dst);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void shrl_CLr(RegisterID dst)
</span><span class="lines">@@ -1060,12 +1053,7 @@
</span><span class="cx"> 
</span><span class="cx">     void shll_i8r(int imm, RegisterID dst)
</span><span class="cx">     {
</span><del>-        if (imm == 1)
-            m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
-        else {
-            m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
-            m_formatter.immediate8(imm);
-        }
</del><ins>+        shiftInstruction32&lt;GROUP2_OP_SHL&gt;(imm, dst);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void shll_CLr(RegisterID dst)
</span><span class="lines">@@ -1073,30 +1061,52 @@
</span><span class="cx">         m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-#if CPU(X86_64)
-    void sarq_CLr(RegisterID dst)
</del><ins>+    void rorl_i8r(int imm, RegisterID dst)
</ins><span class="cx">     {
</span><del>-        m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
</del><ins>+        shiftInstruction32&lt;GROUP2_OP_ROR&gt;(imm, dst);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void sarq_i8r(int imm, RegisterID dst)
</del><ins>+    void rorl_CLr(RegisterID dst)
</ins><span class="cx">     {
</span><ins>+        m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_ROR, dst);
+    }
+
+    void roll_i8r(int imm, RegisterID dst)
+    {
+        shiftInstruction32&lt;GROUP2_OP_ROL&gt;(imm, dst);
+    }
+
+    void roll_CLr(RegisterID dst)
+    {
+        m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_ROL, dst);
+    }
+
+#if CPU(X86_64)
+private:
+    template&lt;GroupOpcodeID op&gt;
+    void shiftInstruction64(int imm, RegisterID dst)
+    {
</ins><span class="cx">         if (imm == 1)
</span><del>-            m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
</del><ins>+            m_formatter.oneByteOp64(OP_GROUP2_Ev1, op, dst);
</ins><span class="cx">         else {
</span><del>-            m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
</del><ins>+            m_formatter.oneByteOp64(OP_GROUP2_EvIb, op, dst);
</ins><span class="cx">             m_formatter.immediate8(imm);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+public:
+    void sarq_CLr(RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+    }
</ins><span class="cx"> 
</span><ins>+    void sarq_i8r(int imm, RegisterID dst)
+    {
+        shiftInstruction64&lt;GROUP2_OP_SAR&gt;(imm, dst);
+    }
+
</ins><span class="cx">     void shrq_i8r(int imm, RegisterID dst)
</span><span class="cx">     {
</span><del>-        if (imm == 1)
-            m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
-        else {
-            m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
-            m_formatter.immediate8(imm);
-        }
</del><ins>+        shiftInstruction64&lt;GROUP2_OP_SHR&gt;(imm, dst);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void shrq_CLr(RegisterID dst)
</span><span class="lines">@@ -1106,12 +1116,7 @@
</span><span class="cx"> 
</span><span class="cx">     void shlq_i8r(int imm, RegisterID dst)
</span><span class="cx">     {
</span><del>-        if (imm == 1)
-            m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
-        else {
-            m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
-            m_formatter.immediate8(imm);
-        }
</del><ins>+        shiftInstruction64&lt;GROUP2_OP_SHL&gt;(imm, dst);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void shlq_CLr(RegisterID dst)
</span><span class="lines">@@ -1118,6 +1123,26 @@
</span><span class="cx">     {
</span><span class="cx">         m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
</span><span class="cx">     }
</span><ins>+
+    void rorq_i8r(int imm, RegisterID dst)
+    {
+        shiftInstruction64&lt;GROUP2_OP_ROR&gt;(imm, dst);
+    }
+
+    void rorq_CLr(RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_ROR, dst);
+    }
+
+    void rolq_i8r(int imm, RegisterID dst)
+    {
+        shiftInstruction64&lt;GROUP2_OP_ROL&gt;(imm, dst);
+    }
+
+    void rolq_CLr(RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_ROL, dst);
+    }
</ins><span class="cx"> #endif // CPU(X86_64)
</span><span class="cx"> 
</span><span class="cx">     void imull_rr(RegisterID src, RegisterID dst)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Common.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Common.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Common.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -148,6 +148,28 @@
</span><span class="cx">     return unsignedNumerator % unsignedDenominator;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename IntType&gt;
+static IntType rotateRight(IntType value, int32_t shift)
+{
+    typedef typename std::make_unsigned&lt;IntType&gt;::type UnsignedIntType;
+    UnsignedIntType uValue = static_cast&lt;UnsignedIntType&gt;(value);
+    int32_t bits = sizeof(IntType) * 8;
+    int32_t mask = bits - 1;
+    shift &amp;= mask;
+    return (uValue &gt;&gt; shift) | (uValue &lt;&lt; ((bits - shift) &amp; mask));
+}
+
+template&lt;typename IntType&gt;
+static IntType rotateLeft(IntType value, int32_t shift)
+{
+    typedef typename std::make_unsigned&lt;IntType&gt;::type UnsignedIntType;
+    UnsignedIntType uValue = static_cast&lt;UnsignedIntType&gt;(value);
+    int32_t bits = sizeof(IntType) * 8;
+    int32_t mask = bits - 1;
+    shift &amp;= mask;
+    return (uValue &lt;&lt; shift) | (uValue &gt;&gt; ((bits - shift) &amp; mask));
+}
+
</ins><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(B3_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -175,6 +175,20 @@
</span><span class="cx">     return proc.add&lt;Const32Value&gt;(origin(), static_cast&lt;int32_t&gt;(static_cast&lt;uint32_t&gt;(m_value) &gt;&gt; (other-&gt;asInt32() &amp; 31)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const32Value::rotRConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt32())
+        return nullptr;
+    return proc.add&lt;Const32Value&gt;(origin(), rotateRight(m_value, other-&gt;asInt32()));
+}
+
+Value* Const32Value::rotLConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt32())
+        return nullptr;
+    return proc.add&lt;Const32Value&gt;(origin(), rotateLeft(m_value, other-&gt;asInt32()));
+}
+
</ins><span class="cx"> Value* Const32Value::bitwiseCastConstant(Procedure&amp; proc) const
</span><span class="cx"> {
</span><span class="cx">     return proc.add&lt;ConstFloatValue&gt;(origin(), bitwise_cast&lt;float&gt;(m_value));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -58,6 +58,8 @@
</span><span class="cx">     Value* shlConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* sShrConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* zShrConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* rotRConstant(Procedure&amp;, const Value* other) const override;
+    Value* rotLConstant(Procedure&amp;, const Value* other) const override;
</ins><span class="cx">     Value* bitwiseCastConstant(Procedure&amp;) const override;
</span><span class="cx">     Value* iToDConstant(Procedure&amp;) const override;
</span><span class="cx">     Value* iToFConstant(Procedure&amp;) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -175,6 +175,20 @@
</span><span class="cx">     return proc.add&lt;Const64Value&gt;(origin(), static_cast&lt;int64_t&gt;(static_cast&lt;uint64_t&gt;(m_value) &gt;&gt; (other-&gt;asInt32() &amp; 63)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const64Value::rotRConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt32())
+        return nullptr;
+    return proc.add&lt;Const64Value&gt;(origin(), rotateRight(m_value, other-&gt;asInt32()));
+}
+
+Value* Const64Value::rotLConstant(Procedure&amp; proc, const Value* other) const
+{
+    if (!other-&gt;hasInt32())
+        return nullptr;
+    return proc.add&lt;Const64Value&gt;(origin(), rotateLeft(m_value, other-&gt;asInt32()));
+}
+
</ins><span class="cx"> Value* Const64Value::bitwiseCastConstant(Procedure&amp; proc) const
</span><span class="cx"> {
</span><span class="cx">     return proc.add&lt;ConstDoubleValue&gt;(origin(), bitwise_cast&lt;double&gt;(m_value));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -58,6 +58,8 @@
</span><span class="cx">     Value* shlConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* sShrConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* zShrConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* rotRConstant(Procedure&amp;, const Value* other) const override;
+    Value* rotLConstant(Procedure&amp;, const Value* other) const override;
</ins><span class="cx">     Value* bitwiseCastConstant(Procedure&amp;) const override;
</span><span class="cx">     Value* iToDConstant(Procedure&amp;) const override;
</span><span class="cx">     Value* iToFConstant(Procedure&amp;) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -2191,6 +2191,16 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case RotR: {
+            appendShift&lt;RotateRight32, RotateRight64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
+        }
+
+        case RotL: {
+            appendShift&lt;RotateLeft32, RotateLeft64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
+        }
+
</ins><span class="cx">         case Clz: {
</span><span class="cx">             appendUnOp&lt;CountLeadingZeros32, CountLeadingZeros64&gt;(m_value-&gt;child(0));
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -152,6 +152,12 @@
</span><span class="cx">     case ZShr:
</span><span class="cx">         out.print(&quot;ZShr&quot;);
</span><span class="cx">         return;
</span><ins>+    case RotR:
+        out.print(&quot;RotR&quot;);
+        return;
+    case RotL:
+        out.print(&quot;RotL&quot;);
+        return;
</ins><span class="cx">     case Clz:
</span><span class="cx">         out.print(&quot;Clz&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 (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -95,6 +95,8 @@
</span><span class="cx">     Shl,
</span><span class="cx">     SShr, // Arithmetic Shift.
</span><span class="cx">     ZShr, // Logical Shift.
</span><ins>+    RotR, // Rotate Right.
+    RotL, // Rotate Left.
</ins><span class="cx">     Clz, // Count leading zeros.
</span><span class="cx"> 
</span><span class="cx">     // Floating point math.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -1069,9 +1069,7 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (handleShiftAmount())
-                break;
-
</del><ins>+            handleShiftAmount();
</ins><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case SShr:
</span><span class="lines">@@ -1131,9 +1129,7 @@
</span><span class="cx">                     break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (handleShiftAmount())
-                break;
-
</del><ins>+            handleShiftAmount();
</ins><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case ZShr:
</span><span class="lines">@@ -1144,11 +1140,41 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (handleShiftAmount())
</del><ins>+            handleShiftAmount();
+            break;
+
+        case RotR:
+            // Turn this: RotR(constant1, constant2)
+            // Into this: (constant1 &gt;&gt; constant2) | (constant1 &lt;&lt; sizeof(constant1) * 8 - constant2)
+            if (Value* constant = m_value-&gt;child(0)-&gt;rotRConstant(m_proc, m_value-&gt;child(1))) {
+                replaceWithNewValue(constant);
</ins><span class="cx">                 break;
</span><ins>+            }
</ins><span class="cx"> 
</span><ins>+            handleShiftAmount();
</ins><span class="cx">             break;
</span><span class="cx"> 
</span><ins>+        case RotL:
+            // Turn this: RotL(constant1, constant2)
+            // Into this: (constant1 &lt;&lt; constant2) | (constant1 &gt;&gt; sizeof(constant1) * 8 - constant2)
+            if (Value* constant = m_value-&gt;child(0)-&gt;rotLConstant(m_proc, m_value-&gt;child(1))) {
+                replaceWithNewValue(constant);
+                break;
+            }
+
+            // ARM64 only has rotate right.
+            // Turn this: RotL(value, shift)
+            // Into this: RotR(value, Neg(shift))
+            if (isARM64()) {
+                Value* newShift = m_insertionSet.insert&lt;Value&gt;(m_index, Neg, m_value-&gt;origin(), m_value-&gt;child(1));
+                Value* rotate = m_insertionSet.insert&lt;Value&gt;(m_index, RotR, m_value-&gt;origin(), m_value-&gt;child(0), newShift);
+                replaceWithIdentity(rotate);
+                break;
+            }
+
+            handleShiftAmount();
+            break;
+
</ins><span class="cx">         case Abs:
</span><span class="cx">             // Turn this: Abs(constant)
</span><span class="cx">             // Into this: fabs&lt;value-&gt;type()&gt;(constant)
</span><span class="lines">@@ -2184,12 +2210,12 @@
</span><span class="cx">         m_changed = true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool handleShiftAmount()
</del><ins>+    void handleShiftAmount()
</ins><span class="cx">     {
</span><span class="cx">         // Shift anything by zero is identity.
</span><span class="cx">         if (m_value-&gt;child(1)-&gt;isInt32(0)) {
</span><span class="cx">             replaceWithIdentity(m_value-&gt;child(0));
</span><del>-            return true;
</del><ins>+            return;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // The shift already masks its shift amount. If the shift amount is being masked by a
</span><span class="lines">@@ -2202,11 +2228,7 @@
</span><span class="cx">             &amp;&amp; (m_value-&gt;child(1)-&gt;child(1)-&gt;asInt32() &amp; mask) == mask) {
</span><span class="cx">             m_value-&gt;child(1) = m_value-&gt;child(1)-&gt;child(0);
</span><span class="cx">             m_changed = true;
</span><del>-            // Don't need to return true, since we're still the same shift, and we can still cascade
-            // through other optimizations.
</del><span class="cx">         }
</span><del>-        
-        return false;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void replaceIfRedundant()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -229,6 +229,8 @@
</span><span class="cx">             case Shl:
</span><span class="cx">             case SShr:
</span><span class="cx">             case ZShr:
</span><ins>+            case RotR:
+                case RotL:
</ins><span class="cx">                 VALIDATE(!value-&gt;kind().hasExtraBits(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 2, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == value-&gt;child(0)-&gt;type(), (&quot;At &quot;, *value));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -343,6 +343,16 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Value::rotRConstant(Procedure&amp;, const Value*) const
+{
+    return nullptr;
+}
+
+Value* Value::rotLConstant(Procedure&amp;, const Value*) const
+{
+    return nullptr;
+}
+
</ins><span class="cx"> Value* Value::bitwiseCastConstant(Procedure&amp;) const
</span><span class="cx"> {
</span><span class="cx">     return nullptr;
</span><span class="lines">@@ -550,6 +560,8 @@
</span><span class="cx">     case Shl:
</span><span class="cx">     case SShr:
</span><span class="cx">     case ZShr:
</span><ins>+    case RotR:
+    case RotL:
</ins><span class="cx">     case Clz:
</span><span class="cx">     case Abs:
</span><span class="cx">     case Ceil:
</span><span class="lines">@@ -696,6 +708,8 @@
</span><span class="cx">     case Shl:
</span><span class="cx">     case SShr:
</span><span class="cx">     case ZShr:
</span><ins>+    case RotR:
+    case RotL:
</ins><span class="cx">     case Equal:
</span><span class="cx">     case NotEqual:
</span><span class="cx">     case LessThan:
</span><span class="lines">@@ -777,6 +791,8 @@
</span><span class="cx">     case Shl:
</span><span class="cx">     case SShr:
</span><span class="cx">     case ZShr:
</span><ins>+    case RotR:
+    case RotL:
</ins><span class="cx">     case Clz:
</span><span class="cx">     case Abs:
</span><span class="cx">     case Ceil:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -175,6 +175,8 @@
</span><span class="cx">     virtual Value* shlConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* sShrConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* zShrConstant(Procedure&amp;, const Value* other) const;
</span><ins>+    virtual Value* rotRConstant(Procedure&amp;, const Value* other) const;
+    virtual Value* rotLConstant(Procedure&amp;, const Value* other) const;
</ins><span class="cx">     virtual Value* bitwiseCastConstant(Procedure&amp;) const;
</span><span class="cx">     virtual Value* iToDConstant(Procedure&amp;) const;
</span><span class="cx">     virtual Value* iToFConstant(Procedure&amp;) const;
</span><span class="lines">@@ -333,6 +335,8 @@
</span><span class="cx">         case Shl:
</span><span class="cx">         case SShr:
</span><span class="cx">         case ZShr:
</span><ins>+        case RotR:
+        case RotL:
</ins><span class="cx">         case Equal:
</span><span class="cx">         case NotEqual:
</span><span class="cx">         case LessThan:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueKeycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/B3ValueKey.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -86,6 +86,8 @@
</span><span class="cx">     case Shl:
</span><span class="cx">     case SShr:
</span><span class="cx">     case ZShr:
</span><ins>+    case RotR:
+    case RotL:
</ins><span class="cx">     case Equal:
</span><span class="cx">     case NotEqual:
</span><span class="cx">     case LessThan:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInstInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -214,6 +214,26 @@
</span><span class="cx">     return isShiftValid(inst);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isRotateRight32Valid(const Inst&amp; inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isRotateLeft32Valid(const Inst&amp; inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isRotateRight64Valid(const Inst&amp; inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isRotateLeft64Valid(const Inst&amp; inst)
+{
+    return isShiftValid(inst);
+}
+
</ins><span class="cx"> inline bool isX86DivHelperValid(const Inst&amp; inst)
</span><span class="cx"> {
</span><span class="cx"> #if CPU(X86) || CPU(X86_64)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -373,7 +373,7 @@
</span><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-arm64: Lshift64 U:G:64, U:G:64, ZD:G:64
</del><ins>+arm64: Lshift64 U:G:64, U:G:64, D:G:64
</ins><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx">     Tmp, Imm, Tmp
</span><span class="cx"> 
</span><span class="lines">@@ -389,7 +389,7 @@
</span><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-arm64: Rshift64 U:G:64, U:G:64, ZD:G:64
</del><ins>+arm64: Rshift64 U:G:64, U:G:64, D:G:64
</ins><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx">     Tmp, Imm, Tmp
</span><span class="cx"> 
</span><span class="lines">@@ -405,7 +405,7 @@
</span><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-arm64: Urshift64 U:G:64, U:G:64, ZD:G:64
</del><ins>+arm64: Urshift64 U:G:64, U:G:64, D:G:64
</ins><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx">     Tmp, Imm, Tmp
</span><span class="cx"> 
</span><span class="lines">@@ -413,6 +413,30 @@
</span><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><ins>+x86_64: RotateRight32 U:G:32, UZD:G:32
+    Tmp*, Tmp
+    Imm, Tmp
+
+arm64: RotateRight32 U:G:32, U:G:32, ZD:G:32
+    Tmp, Tmp, Tmp
+    Tmp, Imm, Tmp
+
+x86_64: RotateRight64 U:G:64, UD:G:64
+    Tmp*, Tmp
+    Imm, Tmp
+
+arm64: RotateRight64 U:G:64, U:G:64, D:G:64
+    Tmp, Tmp, Tmp
+    Tmp, Imm, Tmp
+
+x86_64: RotateLeft32 U:G:32, UZD:G:32
+    Tmp*, Tmp
+    Imm, Tmp
+
+x86_64: RotateLeft64 U:G:64, UD:G:64
+    Tmp*, Tmp
+    Imm, Tmp
+
</ins><span class="cx"> Or32 U:G:32, U:G:32, ZD:G:32
</span><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx">     arm64: BitImm, Tmp, Tmp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (208847 => 208848)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-11-17 17:52:03 UTC (rev 208848)
</span><span class="lines">@@ -11959,6 +11959,76 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T&gt;
</span><ins>+void testRotR(T valueInt, int32_t shift)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    if (sizeof(T) == 4)
+        value = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(), value);
+
+    Value* ammount = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    root-&gt;appendNewControlValue(proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, RotR, Origin(), value, ammount));
+
+    CHECK_EQ(compileAndRun&lt;T&gt;(proc, valueInt, shift), rotateRight(valueInt, shift));
+}
+
+template&lt;typename T&gt;
+void testRotL(T valueInt, int32_t shift)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    if (sizeof(T) == 4)
+        value = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(), value);
+
+    Value* ammount = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    root-&gt;appendNewControlValue(proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, RotL, Origin(), value, ammount));
+
+    CHECK_EQ(compileAndRun&lt;T&gt;(proc, valueInt, shift), rotateLeft(valueInt, shift));
+}
+
+template&lt;typename T&gt;
+void testRotRWithImmShift(T valueInt, int32_t shift)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    if (sizeof(T) == 4)
+        value = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(), value);
+
+    Value* ammount = root-&gt;appendIntConstant(proc, Origin(), Int32, shift);
+    root-&gt;appendNewControlValue(proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, RotR, Origin(), value, ammount));
+
+    CHECK_EQ(compileAndRun&lt;T&gt;(proc, valueInt, shift), rotateRight(valueInt, shift));
+}
+
+template&lt;typename T&gt;
+void testRotLWithImmShift(T valueInt, int32_t shift)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    if (sizeof(T) == 4)
+        value = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(), value);
+
+    Value* ammount = root-&gt;appendIntConstant(proc, Origin(), Int32, shift);
+    root-&gt;appendNewControlValue(proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, RotL, Origin(), value, ammount));
+
+    CHECK_EQ(compileAndRun&lt;T&gt;(proc, valueInt, shift), rotateLeft(valueInt, shift));
+}
+
+template&lt;typename T&gt;
</ins><span class="cx"> void testComputeDivisionMagic(T value, T magicMultiplier, unsigned shift)
</span><span class="cx"> {
</span><span class="cx">     DivisionMagic&lt;T&gt; magic = computeDivisionMagic(value);
</span><span class="lines">@@ -15293,6 +15363,16 @@
</span><span class="cx"> 
</span><span class="cx">     RUN(testCheckMul64SShr());
</span><span class="cx"> 
</span><ins>+    RUN_BINARY(testRotR, int32Operands(), int32Operands());
+    RUN_BINARY(testRotR, int64Operands(), int32Operands());
+    RUN_BINARY(testRotL, int32Operands(), int32Operands());
+    RUN_BINARY(testRotL, int64Operands(), int32Operands());
+
+    RUN_BINARY(testRotRWithImmShift, int32Operands(), int32Operands());
+    RUN_BINARY(testRotRWithImmShift, int64Operands(), int32Operands());
+    RUN_BINARY(testRotLWithImmShift, int32Operands(), int32Operands());
+    RUN_BINARY(testRotLWithImmShift, int64Operands(), int32Operands());
+
</ins><span class="cx">     RUN(testComputeDivisionMagic&lt;int32_t&gt;(2, -2147483647, 0));
</span><span class="cx">     RUN(testTrivialInfiniteLoop());
</span><span class="cx">     RUN(testFoldPathEqual());
</span></span></pre>
</div>
</div>

</body>
</html>