<!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>[288372] 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/288372">288372</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2022-01-21 13:13:52 -0800 (Fri, 21 Jan 2022)</dd>
</dl>

<h3>Log Message</h3>
<pre>[RISCV64] Add MacroAssemblerRISCV64 operations for bitfield, zero-counting, byte-swapping operations
https://bugs.webkit.org/show_bug.cgi?id=235439

Patch by Zan Dobersek <zdobersek@igalia.com> on 2022-01-21
Reviewed by Yusuke Suzuki.

Add MacroAssemblerRISCV64 implementations that cover unsigned bitfield,
leading-zero, trailing-zero and byte-swapping operations. All these
operations are not supported in base RISC-V specifications. There are
extensions currently being ratified that will introduce more useful
instructions, but until then more verbose implementations will have
to be used.

For the unsigned bitfield operations, the desired result is achieved
through shifting and masking. Scratch registers are only needed in
case of the mask immediate being too large, but that will be properly
handled by the higher-level JITs. For other operations covered in this
patch  we have to use scratch registers and custom loops to implement
the necessary behavior.

* assembler/MacroAssemblerRISCV64.h:
(JSC::MacroAssemblerRISCV64::extractUnsignedBitfield32):
(JSC::MacroAssemblerRISCV64::extractUnsignedBitfield64):
(JSC::MacroAssemblerRISCV64::insertUnsignedBitfieldInZero32):
(JSC::MacroAssemblerRISCV64::insertUnsignedBitfieldInZero64):
(JSC::MacroAssemblerRISCV64::countLeadingZeros32):
(JSC::MacroAssemblerRISCV64::countLeadingZeros64):
(JSC::MacroAssemblerRISCV64::countTrailingZeros32):
(JSC::MacroAssemblerRISCV64::countTrailingZeros64):
(JSC::MacroAssemblerRISCV64::byteSwap16):
(JSC::MacroAssemblerRISCV64::byteSwap32):
(JSC::MacroAssemblerRISCV64::byteSwap64):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerRISCV64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerRISCV64.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (288371 => 288372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2022-01-21 21:07:04 UTC (rev 288371)
+++ trunk/Source/JavaScriptCore/ChangeLog       2022-01-21 21:13:52 UTC (rev 288372)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2022-01-21  Zan Dobersek  <zdobersek@igalia.com>
+
+        [RISCV64] Add MacroAssemblerRISCV64 operations for bitfield, zero-counting, byte-swapping operations
+        https://bugs.webkit.org/show_bug.cgi?id=235439
+
+        Reviewed by Yusuke Suzuki.
+
+        Add MacroAssemblerRISCV64 implementations that cover unsigned bitfield,
+        leading-zero, trailing-zero and byte-swapping operations. All these
+        operations are not supported in base RISC-V specifications. There are
+        extensions currently being ratified that will introduce more useful
+        instructions, but until then more verbose implementations will have
+        to be used.
+
+        For the unsigned bitfield operations, the desired result is achieved
+        through shifting and masking. Scratch registers are only needed in
+        case of the mask immediate being too large, but that will be properly
+        handled by the higher-level JITs. For other operations covered in this
+        patch  we have to use scratch registers and custom loops to implement
+        the necessary behavior.
+
+        * assembler/MacroAssemblerRISCV64.h:
+        (JSC::MacroAssemblerRISCV64::extractUnsignedBitfield32):
+        (JSC::MacroAssemblerRISCV64::extractUnsignedBitfield64):
+        (JSC::MacroAssemblerRISCV64::insertUnsignedBitfieldInZero32):
+        (JSC::MacroAssemblerRISCV64::insertUnsignedBitfieldInZero64):
+        (JSC::MacroAssemblerRISCV64::countLeadingZeros32):
+        (JSC::MacroAssemblerRISCV64::countLeadingZeros64):
+        (JSC::MacroAssemblerRISCV64::countTrailingZeros32):
+        (JSC::MacroAssemblerRISCV64::countTrailingZeros64):
+        (JSC::MacroAssemblerRISCV64::byteSwap16):
+        (JSC::MacroAssemblerRISCV64::byteSwap32):
+        (JSC::MacroAssemblerRISCV64::byteSwap64):
+
</ins><span class="cx"> 2022-01-21  Alex Christensen  <achristensen@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Fix build when using Visual Studio 2022
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerRISCV64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerRISCV64.h (288371 => 288372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerRISCV64.h    2022-01-21 21:07:04 UTC (rev 288371)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerRISCV64.h       2022-01-21 21:13:52 UTC (rev 288372)
</span><span class="lines">@@ -471,20 +471,164 @@
</span><span class="cx">         m_assembler.mulInsn(dest, lhs, rhs);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(extractUnsignedBitfield32);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(extractUnsignedBitfield64);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(insertUnsignedBitfieldInZero32);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(insertUnsignedBitfieldInZero64);
</del><ins>+    void extractUnsignedBitfield32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
+    {
+        m_assembler.srliInsn(dest, src, std::clamp<int32_t>(lsb.m_value, 0, 31));
+        if (!Imm::isValid<Imm::IType>(width.m_value)) {
+            auto temp = temps<Data>();
+            loadImmediate(width, temp.data());
+            m_assembler.andInsn(dest, dest, temp.data());
+        } else
+            m_assembler.andiInsn(dest, dest, Imm::I(width.m_value));
+    }
</ins><span class="cx"> 
</span><del>-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(countLeadingZeros32);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(countLeadingZeros64);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(countTrailingZeros32);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(countTrailingZeros64);
</del><ins>+    void extractUnsignedBitfield64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
+    {
+        m_assembler.srliInsn(dest, src, std::clamp<int32_t>(lsb.m_value, 0, 63));
+        if (!Imm::isValid<Imm::IType>(width.m_value)) {
+            auto temp = temps<Data>();
+            loadImmediate(width, temp.data());
+            m_assembler.andInsn(dest, dest, temp.data());
+        } else
+            m_assembler.andiInsn(dest, dest, Imm::I(width.m_value));
+    }
</ins><span class="cx"> 
</span><del>-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(byteSwap16);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(byteSwap32);
-    MACRO_ASSEMBLER_RISCV64_TEMPLATED_NOOP_METHOD(byteSwap64);
</del><ins>+    void insertUnsignedBitfieldInZero32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
+    {
+        if (!Imm::isValid<Imm::IType>(width.m_value)) {
+            auto temp = temps<Data>();
+            loadImmediate(width, temp.data());
+            m_assembler.andInsn(dest, src, temp.data());
+        } else
+            m_assembler.andiInsn(dest, src, Imm::I(width.m_value));
+        m_assembler.slliInsn(dest, dest, std::clamp<int32_t>(lsb.m_value, 0, 63));
+    }
</ins><span class="cx"> 
</span><ins>+    void insertUnsignedBitfieldInZero64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
+    {
+        if (!Imm::isValid<Imm::IType>(width.m_value)) {
+            auto temp = temps<Data>();
+            loadImmediate(width, temp.data());
+            m_assembler.andInsn(dest, src, temp.data());
+        } else
+            m_assembler.andiInsn(dest, src, Imm::I(width.m_value));
+        m_assembler.slliInsn(dest, dest, std::clamp<int32_t>(lsb.m_value, 0, 63));
+    }
+
+    void countLeadingZeros32(RegisterID src, RegisterID dest)
+    {
+        auto temp = temps<Data>();
+        m_assembler.zeroExtend<32>(temp.data(), src);
+        m_assembler.addiInsn(dest, RISCV64Registers::zero, Imm::I<32>());
+
+        JumpList zero(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+
+        Label loop = label();
+        m_assembler.srliInsn<1>(temp.data(), temp.data());
+        m_assembler.addiInsn(dest, dest, Imm::I<-1>());
+        zero.append(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+        jump().linkTo(loop, this);
+
+        zero.link(this);
+    }
+
+    void countLeadingZeros64(RegisterID src, RegisterID dest)
+    {
+        auto temp = temps<Data>();
+        m_assembler.addiInsn(temp.data(), src, Imm::I<0>());
+        m_assembler.addiInsn(dest, RISCV64Registers::zero, Imm::I<64>());
+
+        JumpList zero(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+
+        Label loop = label();
+        m_assembler.srliInsn<1>(temp.data(), temp.data());
+        m_assembler.addiInsn(dest, dest, Imm::I<-1>());
+        zero.append(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+        jump().linkTo(loop, this);
+
+        zero.link(this);
+    }
+
+    void countTrailingZeros32(RegisterID src, RegisterID dest)
+    {
+        auto temp = temps<Data>();
+        m_assembler.addiInsn(dest, RISCV64Registers::zero, Imm::I<32>());
+        m_assembler.zeroExtend<32>(temp.data(), src);
+
+        JumpList zero(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+
+        Label loop = label();
+        m_assembler.slliInsn<1>(temp.data(), temp.data());
+        m_assembler.addiInsn(dest, dest, Imm::I<-1>());
+        zero.append(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+        jump().linkTo(loop, this);
+
+        zero.link(this);
+    }
+
+    void countTrailingZeros64(RegisterID src, RegisterID dest)
+    {
+        auto temp = temps<Data>();
+        m_assembler.addiInsn(dest, RISCV64Registers::zero, Imm::I<64>());
+        m_assembler.addiInsn(temp.data(), src, Imm::I<0>());
+
+        JumpList zero(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+
+        Label loop = label();
+        m_assembler.slliInsn<1>(temp.data(), temp.data());
+        m_assembler.addiInsn(dest, dest, Imm::I<-1>());
+        zero.append(makeBranch(Equal, temp.data(), RISCV64Registers::zero));
+        jump().linkTo(loop, this);
+
+        zero.link(this);
+    }
+
+    void byteSwap16(RegisterID reg)
+    {
+        auto temp = temps<Data>();
+        m_assembler.andiInsn(temp.data(), reg, Imm::I<0xff>());
+        m_assembler.slliInsn<8>(temp.data(), temp.data());
+        m_assembler.slliInsn<48>(reg, reg);
+        m_assembler.srliInsn<56>(reg, reg);
+        m_assembler.orInsn(reg, reg, temp.data());
+    }
+
+    void byteSwap32(RegisterID reg)
+    {
+        auto temp = temps<Data, Memory>();
+        m_assembler.andiInsn(temp.data(), reg, Imm::I<0xff>());
+        m_assembler.slliInsn<8>(temp.data(), temp.data());
+        m_assembler.srliInsn<8>(reg, reg);
+
+        for (unsigned i = 0; i < 2; ++i) {
+            m_assembler.andiInsn(temp.memory(), reg, Imm::I<0xff>());
+            m_assembler.orInsn(temp.data(), temp.data(), temp.memory());
+            m_assembler.slliInsn<8>(temp.data(), temp.data());
+            m_assembler.srliInsn<8>(reg, reg);
+        }
+
+        m_assembler.andiInsn(temp.memory(), reg, Imm::I<0xff>());
+        m_assembler.orInsn(reg, temp.data(), temp.memory());
+    }
+
+    void byteSwap64(RegisterID reg)
+    {
+        auto temp = temps<Data, Memory>();
+        m_assembler.andiInsn(temp.data(), reg, Imm::I<0xff>());
+        m_assembler.slliInsn<8>(temp.data(), temp.data());
+        m_assembler.srliInsn<8>(reg, reg);
+
+        for (unsigned i = 0; i < 6; ++i) {
+            m_assembler.andiInsn(temp.memory(), reg, Imm::I<0xff>());
+            m_assembler.orInsn(temp.data(), temp.data(), temp.memory());
+            m_assembler.slliInsn<8>(temp.data(), temp.data());
+            m_assembler.srliInsn<8>(reg, reg);
+        }
+
+        m_assembler.andiInsn(temp.memory(), reg, Imm::I<0xff>());
+        m_assembler.orInsn(reg, temp.data(), temp.memory());
+    }
+
</ins><span class="cx">     void lshift32(RegisterID shiftAmount, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         lshift32(dest, shiftAmount, dest);
</span></span></pre>
</div>
</div>

</body>
</html>