<!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>[286020] 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/286020">286020</a></dd>
<dt>Author</dt> <dd>ysuzuki@apple.com</dd>
<dt>Date</dt> <dd>2021-11-18 12:04:48 -0800 (Thu, 18 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Add branchTest16 operation
https://bugs.webkit.org/show_bug.cgi?id=233275

Reviewed by Mark Lam.

This patch adds branchTest16 to all macro assemblers. And it also fixes the existing bug of
edge case of branchTest8: when we cannot represent the imm as ARM logical value, then we are
failing to emit the right instructions. Probably this bug does not appear since we are not using
such a value as an imm for branchTest8. We added tests to testmasm so that these code is stressed
now.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::branchTest16):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::load16SignedExtendTo32):
(JSC::MacroAssemblerARM64::branchTest32):
(JSC::MacroAssemblerARM64::branchTest8):
(JSC::MacroAssemblerARM64::branchTest16):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::branchTest16):
(JSC::MacroAssemblerARMv7::test32):
(JSC::MacroAssemblerARMv7::test8):
* assembler/MacroAssemblerHelpers.h:
(JSC::MacroAssemblerHelpers::mask16OnCondition):
(JSC::MacroAssemblerHelpers::load16OnCondition):
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::load16):
(JSC::MacroAssemblerMIPS::load16SignedExtendTo32):
(JSC::MacroAssemblerMIPS::mask16OnTest):
(JSC::MacroAssemblerMIPS::branchTest16):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::branchTest16):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::branchTest16):
* assembler/X86Assembler.h:
(JSC::X86Assembler::cmpw_im):
(JSC::X86Assembler::testw_im):
* assembler/testmasm.cpp:
(JSC::testBranchTest8):
(JSC::testBranchTest16):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerHelpersh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerMIPSh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.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="#trunkSourceJavaScriptCoreassemblertestmasmcpp">trunk/Source/JavaScriptCore/assembler/testmasm.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/ChangeLog       2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -1,3 +1,46 @@
</span><ins>+2021-11-18  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Add branchTest16 operation
+        https://bugs.webkit.org/show_bug.cgi?id=233275
+
+        Reviewed by Mark Lam.
+
+        This patch adds branchTest16 to all macro assemblers. And it also fixes the existing bug of
+        edge case of branchTest8: when we cannot represent the imm as ARM logical value, then we are
+        failing to emit the right instructions. Probably this bug does not appear since we are not using
+        such a value as an imm for branchTest8. We added tests to testmasm so that these code is stressed
+        now.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::branchTest16):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::load16SignedExtendTo32):
+        (JSC::MacroAssemblerARM64::branchTest32):
+        (JSC::MacroAssemblerARM64::branchTest8):
+        (JSC::MacroAssemblerARM64::branchTest16):
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::branchTest16):
+        (JSC::MacroAssemblerARMv7::test32):
+        (JSC::MacroAssemblerARMv7::test8):
+        * assembler/MacroAssemblerHelpers.h:
+        (JSC::MacroAssemblerHelpers::mask16OnCondition):
+        (JSC::MacroAssemblerHelpers::load16OnCondition):
+        * assembler/MacroAssemblerMIPS.h:
+        (JSC::MacroAssemblerMIPS::load16):
+        (JSC::MacroAssemblerMIPS::load16SignedExtendTo32):
+        (JSC::MacroAssemblerMIPS::mask16OnTest):
+        (JSC::MacroAssemblerMIPS::branchTest16):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::branchTest16):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::branchTest16):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::cmpw_im):
+        (JSC::X86Assembler::testw_im):
+        * assembler/testmasm.cpp:
+        (JSC::testBranchTest8):
+        (JSC::testBranchTest16):
+
</ins><span class="cx"> 2021-11-18  David Kilzer  <ddkilzer@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add missing dependencies for <wtf/Platform.h> when generating derived sources
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h   2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h      2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -880,6 +880,12 @@
</span><span class="cx">         return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    using MacroAssemblerBase::branchTest16;
+    Jump branchTest16(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        return MacroAssemblerBase::branchTest16(cond, Address(address.base, address.offset), mask);
+    }
+
</ins><span class="cx"> #else // !CPU(ADDRESS64)
</span><span class="cx"> 
</span><span class="cx">     void addPtr(RegisterID src, RegisterID dest)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h      2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h 2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -1805,6 +1805,14 @@
</span><span class="cx">         m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void load16SignedExtendTo32(const void* address, RegisterID dest)
+    {
+        moveToCachedReg(TrustedImmPtr(address), cachedMemoryTempRegister());
+        m_assembler.ldrsh<32>(dest, memoryTempRegister, ARM64Registers::zr);
+        if (dest == memoryTempRegister)
+            cachedMemoryTempRegister().invalidate();
+    }
+
</ins><span class="cx">     void zeroExtend16To32(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.uxth<32>(dest, src);
</span><span class="lines">@@ -3410,6 +3418,7 @@
</span><span class="cx">                 return Jump(makeBranch(cond));
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            ASSERT(reg != dataTempRegister);
</ins><span class="cx">             move(mask, getCachedDataTempRegisterIDAndInvalidate());
</span><span class="cx">             m_assembler.tst<32>(reg, dataTempRegister);
</span><span class="cx">         }
</span><span class="lines">@@ -3514,37 +3523,71 @@
</span><span class="cx">     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><del>-        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, getCachedDataTempRegisterIDAndInvalidate());
-        return branchTest32(cond, dataTempRegister, mask8);
</del><ins>+        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask8);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><del>-        MacroAssemblerHelpers::load8OnCondition(*this, cond, address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
-        return branchTest32(cond, dataTempRegister, mask8);
</del><ins>+        MacroAssemblerHelpers::load8OnCondition(*this, cond, address.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask8);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><del>-        move(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), getCachedDataTempRegisterIDAndInvalidate());
</del><ins>+        move(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), getCachedMemoryTempRegisterIDAndInvalidate());
</ins><span class="cx"> 
</span><span class="cx">         if (MacroAssemblerHelpers::isUnsigned<MacroAssemblerARM64>(cond))
</span><del>-            m_assembler.ldrb(dataTempRegister, address.base, dataTempRegister);
</del><ins>+            m_assembler.ldrb(memoryTempRegister, address.base, memoryTempRegister);
</ins><span class="cx">         else
</span><del>-            m_assembler.ldrsb<32>(dataTempRegister, address.base, dataTempRegister);
</del><ins>+            m_assembler.ldrsb<32>(memoryTempRegister, address.base, memoryTempRegister);
</ins><span class="cx"> 
</span><del>-        return branchTest32(cond, dataTempRegister, mask8);
</del><ins>+        return branchTest32(cond, memoryTempRegister, mask8);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><del>-        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, getCachedDataTempRegisterIDAndInvalidate());
-        return branchTest32(cond, dataTempRegister, mask8);
</del><ins>+        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask8);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Jump branchTest16(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        move(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), getCachedMemoryTempRegisterIDAndInvalidate());
+
+        if (MacroAssemblerHelpers::isUnsigned<MacroAssemblerARM64>(cond))
+            m_assembler.ldrh(memoryTempRegister, address.base, memoryTempRegister);
+        else
+            m_assembler.ldrsh<32>(memoryTempRegister, address.base, memoryTempRegister);
+
+        return branchTest32(cond, memoryTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, getCachedMemoryTempRegisterIDAndInvalidate());
+        return branchTest32(cond, memoryTempRegister, mask16);
+    }
+
</ins><span class="cx">     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
</span><span class="cx">     {
</span><span class="cx">         return branch32(cond, left, right);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h      2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h 2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -1772,7 +1772,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><del>-        // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
</del><ins>+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
</ins><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><span class="cx">         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, addressTempRegister);
</span><span class="cx">         return branchTest32(cond, addressTempRegister, mask8);
</span><span class="lines">@@ -1780,7 +1780,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><del>-        // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
</del><ins>+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
</ins><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><span class="cx">         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, addressTempRegister);
</span><span class="cx">         return branchTest32(cond, addressTempRegister, mask8);
</span><span class="lines">@@ -1788,7 +1788,7 @@
</span><span class="cx"> 
</span><span class="cx">     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
</span><span class="cx">     {
</span><del>-        // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
</del><ins>+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
</ins><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><span class="cx">         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
</span><span class="cx">         MacroAssemblerHelpers::load8OnCondition(*this, cond, Address(addressTempRegister), addressTempRegister);
</span><span class="lines">@@ -1795,6 +1795,31 @@
</span><span class="cx">         return branchTest32(cond, addressTempRegister, mask8);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Jump branchTest16(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, addressTempRegister);
+        return branchTest32(cond, addressTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, addressTempRegister);
+        return branchTest32(cond, addressTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
+        TrustedImm32 mask16 = MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+        move(TrustedImmPtr(address.m_ptr), addressTempRegister);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, Address(addressTempRegister), addressTempRegister);
+        return branchTest32(cond, addressTempRegister, mask16);
+    }
+
</ins><span class="cx">     void farJump(RegisterID target, PtrTag)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.bx(target);
</span><span class="lines">@@ -2041,8 +2066,8 @@
</span><span class="cx">     // asm ops like test, or pseudo ops like pop().
</span><span class="cx">     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
</span><span class="cx">     {
</span><del>-        load32(address, dataTempRegister);
-        test32(dataTempRegister, mask);
</del><ins>+        load32(address, addressTempRegister);
+        test32(addressTempRegister, mask);
</ins><span class="cx">         m_assembler.it(armV7Condition(cond), false);
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
</span><span class="lines">@@ -2051,8 +2076,8 @@
</span><span class="cx">     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
</span><del>-        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, dataTempRegister);
-        test32(dataTempRegister, mask8);
</del><ins>+        MacroAssemblerHelpers::load8OnCondition(*this, cond, address, addressTempRegister);
+        test32(addressTempRegister, mask8);
</ins><span class="cx">         m_assembler.it(armV7Condition(cond), false);
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
</span><span class="cx">         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerHelpers.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerHelpers.h    2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerHelpers.h       2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -126,6 +126,30 @@
</span><span class="cx">     return typename MacroAssemblerType::TrustedImm32(static_cast<int8_t>(value.m_value));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template<typename MacroAssemblerType>
+inline typename MacroAssemblerType::TrustedImm32 mask16OnCondition(MacroAssemblerType&, typename MacroAssemblerType::RelationalCondition cond, typename MacroAssemblerType::TrustedImm32 value)
+{
+    if (isUnsigned<MacroAssemblerType>(cond))
+        return typename MacroAssemblerType::TrustedImm32(static_cast<uint16_t>(value.m_value));
+    return typename MacroAssemblerType::TrustedImm32(static_cast<int16_t>(value.m_value));
+}
+
+template<typename MacroAssemblerType>
+inline typename MacroAssemblerType::TrustedImm32 mask16OnCondition(MacroAssemblerType&, typename MacroAssemblerType::ResultCondition cond, typename MacroAssemblerType::TrustedImm32 value)
+{
+    // If condition is Zero or NonZero, upper bits are unrelated.
+    // Since branchTest32 handles -1 in an optimized manner, we keep -1 as is instead of converting it to 0xffff.
+    if (cond == MacroAssemblerType::Zero || cond == MacroAssemblerType::NonZero) {
+        if (value.m_value == -1)
+            return value;
+    }
+    if (isUnsigned<MacroAssemblerType>(cond))
+        return typename MacroAssemblerType::TrustedImm32(static_cast<uint16_t>(value.m_value));
+    ASSERT_WITH_MESSAGE(cond != MacroAssemblerType::Overflow, "Overflow is not used for 16bit test operations.");
+    ASSERT(isSigned<MacroAssemblerType>(cond));
+    return typename MacroAssemblerType::TrustedImm32(static_cast<int16_t>(value.m_value));
+}
+
</ins><span class="cx"> template<typename MacroAssemblerType, typename Condition, typename ...Args>
</span><span class="cx"> void load8OnCondition(MacroAssemblerType& jit, Condition cond, Args... args)
</span><span class="cx"> {
</span><span class="lines">@@ -134,4 +158,12 @@
</span><span class="cx">     return jit.load8SignedExtendTo32(std::forward<Args>(args)...);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template<typename MacroAssemblerType, typename Condition, typename ...Args>
+void load16OnCondition(MacroAssemblerType& jit, Condition cond, Args... args)
+{
+    if (isUnsigned<MacroAssemblerType>(cond))
+        return jit.load16(std::forward<Args>(args)...);
+    return jit.load16SignedExtendTo32(std::forward<Args>(args)...);
+}
+
</ins><span class="cx"> } } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerMIPSh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h       2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h  2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -1272,6 +1272,29 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void load16(AbsoluteAddress address, RegisterID dest)
+    {
+        load16(address.m_ptr, dest);
+    }
+
+    /* Need to use zero-extened load half-word for load16.  */
+    void load16SignedExtendTo32(Address address, RegisterID dest)
+    {
+        if (address.offset >= -32768 && address.offset <= 32767
+            && !m_fixedWidth)
+            m_assembler.lh(dest, address.base, address.offset);
+        else {
+            /*
+                lui     addrTemp, (offset + 0x8000) >> 16
+                addu    addrTemp, addrTemp, base
+                lh      dest, (offset & 0xffff)(addrTemp)
+              */
+            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
+            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+            m_assembler.lh(dest, addrTempRegister, address.offset);
+        }
+    }
+
</ins><span class="cx">     void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         if (!m_fixedWidth) {
</span><span class="lines">@@ -1293,6 +1316,28 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void load16SignedExtendTo32(AbsoluteAddress address, RegisterID dest)
+    {
+        load16SignedExtendTo32(address.m_ptr, dest);
+    }
+
+    void load16SignedExtendTo32(const void* address, RegisterID dest)
+    {
+        if (m_fixedWidth) {
+            /*
+                li  addrTemp, address
+                lh dest, 0(addrTemp)
+            */
+            move(TrustedImmPtr(address), addrTempRegister);
+            m_assembler.lh(dest, addrTempRegister, 0);
+        } else {
+            uintptr_t adr = reinterpret_cast<uintptr_t>(address);
+            m_assembler.lui(addrTempRegister, (adr + 0x8000) >> 16);
+            m_assembler.lh(dest, addrTempRegister, adr & 0xffff);
+        }
+    }
+
+
</ins><span class="cx">     void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
</span><span class="cx">     {
</span><span class="cx">         loadPair32(src, TrustedImm32(0), dest1, dest2);
</span><span class="lines">@@ -2043,6 +2088,34 @@
</span><span class="cx">         return branchTest32(cond, dataTempRegister, mask8);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    TrustedImm32 mask16OnTest(ResultCondition cond, TrustedImm32 mask)
+    {
+        if (mask.m_value == -1 && !m_fixedWidth)
+            return TrustedImm32(-1);
+        return MacroAssemblerHelpers::mask16OnCondition(*this, cond, mask);
+    }
+
+    Jump branchTest16(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = mask16OnTest(cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, dataTempRegister);
+        return branchTest32(cond, dataTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = mask16OnTest(cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, dataTempRegister);
+        return branchTest32(cond, dataTempRegister, mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16 = mask16OnTest(cond, mask);
+        MacroAssemblerHelpers::load16OnCondition(*this, cond, address, dataTempRegister);
+        return branchTest32(cond, dataTempRegister, mask16);
+    }
+
</ins><span class="cx">     Jump jump()
</span><span class="cx">     {
</span><span class="cx">         return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h  2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h     2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -2759,6 +2759,26 @@
</span><span class="cx">         return Jump(m_assembler.jCC(x86Condition(cond)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Jump branchTest16(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16(static_cast<int16_t>(mask.m_value));
+        if (mask16.m_value == -1)
+            m_assembler.cmpw_im(0, address.offset, address.base);
+        else
+            m_assembler.testw_im(mask16.m_value, address.offset, address.base);
+        return Jump(m_assembler.jCC(x86Condition(cond)));
+    }
+
+    Jump branchTest16(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16(static_cast<int16_t>(mask.m_value));
+        if (mask16.m_value == -1)
+            m_assembler.cmpw_im(0, address.offset, address.base, address.index, address.scale);
+        else
+            m_assembler.testw_im(mask16.m_value, address.offset, address.base, address.index, address.scale);
+        return Jump(m_assembler.jCC(x86Condition(cond)));
+    }
+
</ins><span class="cx">     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 right8(static_cast<int8_t>(right.m_value));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h     2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -1563,7 +1563,23 @@
</span><span class="cx">         MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister());
</span><span class="cx">         return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister()), mask8);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    using MacroAssemblerX86Common::branchTest16;
+    Jump branchTest16(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16(static_cast<int16_t>(mask.m_value));
+        TrustedImmPtr addr(reinterpret_cast<void*>(address.offset));
+        MacroAssemblerX86Common::move(addr, scratchRegister());
+        return MacroAssemblerX86Common::branchTest16(cond, BaseIndex(scratchRegister(), address.base, TimesOne), mask16);
+    }
+
+    Jump branchTest16(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+    {
+        TrustedImm32 mask16(static_cast<int16_t>(mask.m_value));
+        MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister());
+        return MacroAssemblerX86Common::branchTest16(cond, Address(scratchRegister()), mask16);
+    }
+
</ins><span class="cx">     void xchg64(RegisterID reg, Address address)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.xchgq_rm(reg, address.offset, address.base);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h     2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -2049,6 +2049,19 @@
</span><span class="cx">         m_formatter.oneByteOp(OP_CMP_EvGv, src, base, index, scale, offset);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void cmpw_im(int imm, int offset, RegisterID base)
+    {
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.prefix(PRE_OPERAND_SIZE);
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset);
+            m_formatter.immediate8(imm);
+        } else {
+            m_formatter.prefix(PRE_OPERAND_SIZE);
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset);
+            m_formatter.immediate16(imm);
+        }
+    }
+
</ins><span class="cx">     void cmpw_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
</span><span class="cx">     {
</span><span class="cx">         if (CAN_SIGN_EXTEND_8_32(imm)) {
</span><span class="lines">@@ -2151,7 +2164,21 @@
</span><span class="cx">         m_formatter.prefix(PRE_OPERAND_SIZE);
</span><span class="cx">         m_formatter.oneByteOp(OP_TEST_EvGv, src, dst);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    void testw_im(int imm, int offset, RegisterID base)
+    {
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset);
+        m_formatter.immediate16(imm);
+    }
+
+    void testw_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+    {
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset);
+        m_formatter.immediate16(imm);
+    }
+
</ins><span class="cx">     void testb_i8r(int imm, RegisterID dst)
</span><span class="cx">     {
</span><span class="cx">         if (dst == X86Registers::eax)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblertestmasmcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/testmasm.cpp (286019 => 286020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/testmasm.cpp       2021-11-18 19:38:01 UTC (rev 286019)
+++ trunk/Source/JavaScriptCore/assembler/testmasm.cpp  2021-11-18 20:04:48 UTC (rev 286020)
</span><span class="lines">@@ -326,6 +326,98 @@
</span><span class="cx">     }), expected);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testBranchTest8()
+{
+    for (auto value : int32Operands()) {
+        for (auto value2 : int32Operands()) {
+            auto test1 = compile([=] (CCallHelpers& jit) {
+                emitFunctionPrologue(jit);
+
+                auto branch = jit.branchTest8(MacroAssembler::NonZero, CCallHelpers::Address(GPRInfo::argumentGPR0, 1), CCallHelpers::TrustedImm32(value2));
+                jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+                auto done = jit.jump();
+                branch.link(&jit);
+                jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+                done.link(&jit);
+
+                emitFunctionEpilogue(jit);
+                jit.ret();
+            });
+
+            auto test2 = compile([=] (CCallHelpers& jit) {
+                emitFunctionPrologue(jit);
+
+                auto branch = jit.branchTest8(MacroAssembler::NonZero, CCallHelpers::BaseIndex(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, CCallHelpers::TimesOne), CCallHelpers::TrustedImm32(value2));
+                jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+                auto done = jit.jump();
+                branch.link(&jit);
+                jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+                done.link(&jit);
+
+                emitFunctionEpilogue(jit);
+                jit.ret();
+            });
+
+            int result = 0;
+            if (static_cast<uint8_t>(value) & static_cast<uint8_t>(value2))
+                result = 1;
+
+            uint8_t array[] = {
+                0,
+                static_cast<uint8_t>(value)
+            };
+            CHECK_EQ(invoke<int>(test1, array), result);
+            CHECK_EQ(invoke<int>(test2, array, 1), result);
+        }
+    }
+}
+
+void testBranchTest16()
+{
+    for (auto value : int32Operands()) {
+        for (auto value2 : int32Operands()) {
+            auto test1 = compile([=] (CCallHelpers& jit) {
+                emitFunctionPrologue(jit);
+
+                auto branch = jit.branchTest16(MacroAssembler::NonZero, CCallHelpers::Address(GPRInfo::argumentGPR0, 2), CCallHelpers::TrustedImm32(value2));
+                jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+                auto done = jit.jump();
+                branch.link(&jit);
+                jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+                done.link(&jit);
+
+                emitFunctionEpilogue(jit);
+                jit.ret();
+            });
+
+            auto test2 = compile([=] (CCallHelpers& jit) {
+                emitFunctionPrologue(jit);
+
+                auto branch = jit.branchTest16(MacroAssembler::NonZero, CCallHelpers::BaseIndex(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, CCallHelpers::TimesTwo), CCallHelpers::TrustedImm32(value2));
+                jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+                auto done = jit.jump();
+                branch.link(&jit);
+                jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+                done.link(&jit);
+
+                emitFunctionEpilogue(jit);
+                jit.ret();
+            });
+
+            int result = 0;
+            if (static_cast<uint16_t>(value) & static_cast<uint16_t>(value2))
+                result = 1;
+
+            uint16_t array[] = {
+                0,
+                static_cast<uint16_t>(value)
+            };
+            CHECK_EQ(invoke<int>(test1, array), result);
+            CHECK_EQ(invoke<int>(test2, array, 1), result);
+        }
+    }
+}
+
</ins><span class="cx"> #if CPU(X86_64)
</span><span class="cx"> void testBranchTestBit32RegReg()
</span><span class="cx"> {
</span><span class="lines">@@ -5649,6 +5741,9 @@
</span><span class="cx">     RUN(testLoadStorePair32());
</span><span class="cx">     RUN(testSub32ArgImm());
</span><span class="cx"> 
</span><ins>+    RUN(testBranchTest8());
+    RUN(testBranchTest16());
+
</ins><span class="cx"> #if CPU(X86_64)
</span><span class="cx">     RUN(testBranchTestBit32RegReg());
</span><span class="cx">     RUN(testBranchTestBit32RegImm());
</span></span></pre>
</div>
</div>

</body>
</html>