<!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>[280583] 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/280583">280583</a></dd>
<dt>Author</dt> <dd>yijia_huang@apple.com</dd>
<dt>Date</dt> <dd>2021-08-02 21:18:22 -0700 (Mon, 02 Aug 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add a new pattern to instruction selector to utilize UMULL supported by ARM64
https://bugs.webkit.org/show_bug.cgi?id=228721

Reviewed by Saam Barati.

Unsigned Multiply Long (UMULL) multiplies two 32-bit register values, and writes the
result to the destination register. This instruction is an alias of the UMADDL instruction.

    umull xd wn wm

The equivalent pattern is: d = ZExt32(n) * ZExt32(m)

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = Trunc(@0)
Int @2 = ArgumentReg(%x1)
Int @3 = Trunc(@2)
Int @4 = ZExt32(@1)
Int @5 = ZExt32(@3)
Int @6 = Mul(@4, @5)
Void@7 = Return(@6, Terminal)

// Old optimized AIR
Move   %x0, %x0,      @4
Move   %x1, %x1,      @5
Mul    %x0, %x1, %x0, @6
Ret    %x0,           @7

// New optimized AIR
MultiplyZeroExtend %x0, %x1, %x0, @6
Ret                %x0,           @7

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::multiplyZeroExtend32):
* assembler/testmasm.cpp:
(JSC::testMultiplyZeroExtend32):
* b3/B3LowerToAir.cpp:
* b3/air/AirOpcode.opcodes:
* b3/testb3.h:
* b3/testb3_2.cpp:
(testMulArgs32SignExtend):
(testMulArgs32ZeroExtend):
* b3/testb3_3.cpp:
(addArgTests):</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="#trunkSourceJavaScriptCoreassemblertestmasmcpp">trunk/Source/JavaScriptCore/assembler/testmasm.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3h">trunk/Source/JavaScriptCore/b3/testb3.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3_2cpp">trunk/Source/JavaScriptCore/b3/testb3_2.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3_3cpp">trunk/Source/JavaScriptCore/b3/testb3_3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/ChangeLog       2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -1,5 +1,52 @@
</span><span class="cx"> 2021-08-02  Yijia Huang  <yijia_huang@apple.com>
</span><span class="cx"> 
</span><ins>+        Add a new pattern to instruction selector to utilize UMULL supported by ARM64
+        https://bugs.webkit.org/show_bug.cgi?id=228721
+
+        Reviewed by Saam Barati.
+
+        Unsigned Multiply Long (UMULL) multiplies two 32-bit register values, and writes the 
+        result to the destination register. This instruction is an alias of the UMADDL instruction.
+
+            umull xd wn wm
+
+        The equivalent pattern is: d = ZExt32(n) * ZExt32(m)
+
+        Given B3 IR:
+        Int @0 = ArgumentReg(%x0)
+        Int @1 = Trunc(@0)
+        Int @2 = ArgumentReg(%x1)
+        Int @3 = Trunc(@2)
+        Int @4 = ZExt32(@1)
+        Int @5 = ZExt32(@3)
+        Int @6 = Mul(@4, @5)
+        Void@7 = Return(@6, Terminal)
+
+        // Old optimized AIR
+        Move   %x0, %x0,      @4
+        Move   %x1, %x1,      @5
+        Mul    %x0, %x1, %x0, @6
+        Ret    %x0,           @7
+
+        // New optimized AIR
+        MultiplyZeroExtend %x0, %x1, %x0, @6
+        Ret                %x0,           @7
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::multiplyZeroExtend32):
+        * assembler/testmasm.cpp:
+        (JSC::testMultiplyZeroExtend32):
+        * b3/B3LowerToAir.cpp:
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.h:
+        * b3/testb3_2.cpp:
+        (testMulArgs32SignExtend):
+        (testMulArgs32ZeroExtend):
+        * b3/testb3_3.cpp:
+        (addArgTests):
+
+2021-08-02  Yijia Huang  <yijia_huang@apple.com>
+
</ins><span class="cx">         Add new patterns to instruction selector to utilize AND/EOR/ORR-with-shift supported by ARM64
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=228675
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h      2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h 2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -953,6 +953,11 @@
</span><span class="cx">         m_assembler.smull(dest, left, right);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void multiplyZeroExtend32(RegisterID left, RegisterID right, RegisterID dest)
+    {
+        m_assembler.umull(dest, left, right);
+    }
+
</ins><span class="cx">     void div32(RegisterID dividend, RegisterID divisor, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.sdiv<32>(dest, dividend, divisor);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblertestmasmcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/testmasm.cpp (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/testmasm.cpp       2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/assembler/testmasm.cpp  2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -921,6 +921,26 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testMultiplyZeroExtend32()
+{
+    for (auto nOperand : int32Operands()) {
+        auto mul = compile([=] (CCallHelpers& jit) {
+            emitFunctionPrologue(jit);
+
+            jit.multiplyZeroExtend32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
+
+            emitFunctionEpilogue(jit);
+            jit.ret();
+        });
+
+        for (auto mOperand : int32Operands()) {
+            uint32_t n = nOperand;
+            uint32_t m = mOperand;
+            CHECK_EQ(invoke<uint64_t>(mul, n, m), static_cast<uint64_t>(n) * static_cast<uint64_t>(m));
+        }
+    }
+}
+
</ins><span class="cx"> void testMultiplyAddSignExtend32()
</span><span class="cx"> {
</span><span class="cx">     // d = SExt32(n) * SExt32(m) + a
</span><span class="lines">@@ -5649,6 +5669,7 @@
</span><span class="cx">     RUN(testLoadStorePair64Int64());
</span><span class="cx">     RUN(testLoadStorePair64Double());
</span><span class="cx">     RUN(testMultiplySignExtend32());
</span><ins>+    RUN(testMultiplyZeroExtend32());
</ins><span class="cx"> 
</span><span class="cx">     RUN(testSub32Args());
</span><span class="cx">     RUN(testSub32Imm());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp  2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp     2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -499,7 +499,7 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool isMergeableValue(Value* v, B3::Opcode b3Opcode, bool checkCanBeInternal)
</del><ins>+    bool isMergeableValue(Value* v, B3::Opcode b3Opcode, bool checkCanBeInternal = false)
</ins><span class="cx">     { 
</span><span class="cx">         if (v->opcode() != b3Opcode)
</span><span class="cx">             return false;
</span><span class="lines">@@ -516,9 +516,9 @@
</span><span class="cx"> #if CPU(ARM64)
</span><span class="cx">         // Maybe, the ideal approach is to introduce a decorator (Index@EXT) to the Air operand 
</span><span class="cx">         // to provide an extension opportunity for the specific form under the Air opcode.
</span><del>-        if (isMergeableValue(index, ZExt32, false))
</del><ins>+        if (isMergeableValue(index, ZExt32))
</ins><span class="cx">             return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::ZExt32);
</span><del>-        if (isMergeableValue(index, SExt32, false))
</del><ins>+        if (isMergeableValue(index, SExt32))
</ins><span class="cx">             return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::SExt32);
</span><span class="cx"> #endif
</span><span class="cx">         return Arg::index(base, tmp(index), scale, offset);
</span><span class="lines">@@ -2689,10 +2689,10 @@
</span><span class="cx">                         if (airOpcode != MultiplyAdd64)
</span><span class="cx">                             return Air::Oops;
</span><span class="cx">                         // SMADDL: d = SExt32(n) * SExt32(m) + a
</span><del>-                        if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
</del><ins>+                        if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
</ins><span class="cx">                             return MultiplyAddSignExtend32;
</span><span class="cx">                         // UMADDL: d = ZExt32(n) * ZExt32(m) + a
</span><del>-                        if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
</del><ins>+                        if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
</ins><span class="cx">                             return MultiplyAddZeroExtend32;
</span><span class="cx">                         return Air::Oops;
</span><span class="cx">                     };
</span><span class="lines">@@ -2700,8 +2700,6 @@
</span><span class="cx">                     Air::Opcode newAirOpcode = tryNewAirOpcode();
</span><span class="cx">                     if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
</span><span class="cx">                         append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(right), tmp(m_value));
</span><del>-                        commitInternal(multiplyLeft);
-                        commitInternal(multiplyRight);
</del><span class="cx">                         commitInternal(left);
</span><span class="cx">                         return true;
</span><span class="cx">                     }
</span><span class="lines">@@ -2755,10 +2753,10 @@
</span><span class="cx">                     if (airOpcode != MultiplySub64)
</span><span class="cx">                         return Air::Oops;
</span><span class="cx">                     // SMSUBL: d = a - SExt32(n) * SExt32(m)
</span><del>-                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
</del><ins>+                    if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
</ins><span class="cx">                         return MultiplySubSignExtend32;
</span><span class="cx">                     // UMSUBL: d = a - ZExt32(n) * ZExt32(m)
</span><del>-                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
</del><ins>+                    if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
</ins><span class="cx">                         return MultiplySubZeroExtend32;
</span><span class="cx">                     return Air::Oops;
</span><span class="cx">                 };
</span><span class="lines">@@ -2766,8 +2764,6 @@
</span><span class="cx">                 Air::Opcode newAirOpcode = tryNewAirOpcode();
</span><span class="cx">                 if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
</span><span class="cx">                     append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(left), tmp(m_value));
</span><del>-                    commitInternal(multiplyLeft);
-                    commitInternal(multiplyRight);
</del><span class="cx">                     commitInternal(right);
</span><span class="cx">                     return true;
</span><span class="cx">                 }
</span><span class="lines">@@ -2808,10 +2804,10 @@
</span><span class="cx">                     if (airOpcode != MultiplyNeg64)
</span><span class="cx">                         return Air::Oops;
</span><span class="cx">                     // SMNEGL: d = -(SExt32(n) * SExt32(m))
</span><del>-                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
</del><ins>+                    if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
</ins><span class="cx">                         return MultiplyNegSignExtend32;
</span><span class="cx">                     // UMNEGL: d = -(ZExt32(n) * ZExt32(m))
</span><del>-                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
</del><ins>+                    if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
</ins><span class="cx">                         return MultiplyNegZeroExtend32;
</span><span class="cx">                     return Air::Oops;
</span><span class="cx">                 };
</span><span class="lines">@@ -2819,8 +2815,6 @@
</span><span class="cx">                 Air::Opcode newAirOpcode = tryNewAirOpcode();
</span><span class="cx">                 if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
</span><span class="cx">                     append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(m_value));
</span><del>-                    commitInternal(multiplyLeft);
-                    commitInternal(multiplyRight);
</del><span class="cx">                     commitInternal(m_value->child(0));
</span><span class="cx">                     return true;
</span><span class="cx">                 }
</span><span class="lines">@@ -2842,29 +2836,34 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case Mul: {
</span><del>-            if (m_value->type() == Int64
-                && isValidForm(MultiplySignExtend32, Arg::Tmp, Arg::Tmp, Arg::Tmp)
-                && m_value->child(0)->opcode() == SExt32
-                && !m_locked.contains(m_value->child(0))) {
-                Value* opLeft = m_value->child(0);
-                Value* left = opLeft->child(0);
-                Value* opRight = m_value->child(1);
-                Value* right = nullptr;
</del><ins>+            Value* left = m_value->child(0);
+            Value* right = m_value->child(1);
</ins><span class="cx"> 
</span><del>-                if (opRight->opcode() == SExt32 && !m_locked.contains(opRight->child(0))) {
-                    right = opRight->child(0);
-                } else if (m_value->child(1)->isRepresentableAs<int32_t>() && !m_locked.contains(m_value->child(1))) {
-                    // We just use the 64-bit const int as a 32 bit const int directly
-                    right = opRight;
</del><ins>+            auto tryAppendMultiplyWithExtend = [&] () -> bool {
+                auto tryAirOpcode = [&] () -> Air::Opcode {
+                    if (m_value->type() != Int64)
+                        return Air::Oops;
+                    // SMULL: d = SExt32(n) * SExt32(m)
+                    if (isMergeableValue(left, SExt32) && isMergeableValue(right, SExt32)) 
+                        return MultiplySignExtend32;
+                    // UMULL: d = ZExt32(n) * ZExt32(m)
+                    if (isMergeableValue(left, ZExt32) && isMergeableValue(right, ZExt32)) 
+                        return MultiplyZeroExtend32;
+                    return Air::Oops;
+                };
+
+                Air::Opcode opcode = tryAirOpcode();
+                if (isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
+                    append(opcode, tmp(left->child(0)), tmp(right->child(0)), tmp(m_value));
+                    return true;
</ins><span class="cx">                 }
</span><ins>+                return false;
+            };
</ins><span class="cx"> 
</span><del>-                if (right) {
-                    append(MultiplySignExtend32, tmp(left), tmp(right), tmp(m_value));
-                    return;
-                }
-            }
-            appendBinOp<Mul32, Mul64, MulDouble, MulFloat, Commutative>(
-                m_value->child(0), m_value->child(1));
</del><ins>+            if (tryAppendMultiplyWithExtend())
+                return;
+
+            appendBinOp<Mul32, Mul64, MulDouble, MulFloat, Commutative>(left, right);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3002,7 +3001,7 @@
</span><span class="cx">             //        mask = (1 << lowWidth) - 1
</span><span class="cx">             auto tryAppendEXTR = [&] (Value* left, Value* right) -> bool {
</span><span class="cx">                 Air::Opcode opcode = opcodeForType(ExtractRegister32, ExtractRegister64, m_value->type());
</span><del>-                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp)) 
</del><ins>+                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
</ins><span class="cx">                     return false;
</span><span class="cx">                 if (left->opcode() != Shl || left->child(0)->opcode() != BitAnd || right->opcode() != ZShr)
</span><span class="cx">                     return false;
</span><span class="lines">@@ -3208,7 +3207,7 @@
</span><span class="cx">                         XorNotLeftShift32, XorNotLeftShift64, 
</span><span class="cx">                         XorNotRightShift32, XorNotRightShift64, 
</span><span class="cx">                         XorNotUnsignedRightShift32, XorNotUnsignedRightShift64);
</span><del>-                    if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp)) 
</del><ins>+                    if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
</ins><span class="cx">                         return false;
</span><span class="cx">                     Value* mValue = shiftValue->child(0);
</span><span class="cx">                     Value* amountValue = shiftValue->child(1);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes     2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -284,6 +284,9 @@
</span><span class="cx"> arm64: MultiplySignExtend32 U:G:32, U:G:32, D:G:64
</span><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+arm64: MultiplyZeroExtend32 U:G:32, U:G:32, D:G:64
+    Tmp, Tmp, Tmp
+
</ins><span class="cx"> arm64: Div32 U:G:32, U:G:32, ZD:G:32
</span><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.h (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.h  2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/b3/testb3.h     2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -939,7 +939,8 @@
</span><span class="cx"> void testMulArgImm(int64_t, int64_t);
</span><span class="cx"> void testMulImmArg(int, int);
</span><span class="cx"> void testMulArgs32(int, int);
</span><del>-void testMulArgs32SignExtend(int, int);
</del><ins>+void testMulArgs32SignExtend();
+void testMulArgs32ZeroExtend();
</ins><span class="cx"> void testMulImm32SignExtend(const int, int);
</span><span class="cx"> void testMulLoadTwice();
</span><span class="cx"> void testMulAddArgsLeft();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3_2cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3_2.cpp (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3_2.cpp      2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/b3/testb3_2.cpp 2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -1228,10 +1228,10 @@
</span><span class="cx">     CHECK(compileAndRun<int>(proc, a, b) == a * b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void testMulArgs32SignExtend(int a, int b)
</del><ins>+void testMulArgs32SignExtend()
</ins><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><del>-    if (proc.optLevel() < 1)
</del><ins>+    if (proc.optLevel() < 2)
</ins><span class="cx">         return;
</span><span class="cx">     BasicBlock* root = proc.addBlock();
</span><span class="cx">     Value* arg1 = root->appendNew<Value>(
</span><span class="lines">@@ -1246,10 +1246,48 @@
</span><span class="cx">     root->appendNewControlValue(proc, Return, Origin(), mul);
</span><span class="cx"> 
</span><span class="cx">     auto code = compileProc(proc);
</span><ins>+    if (isARM64())
+        checkUsesInstruction(*code, "smull");
</ins><span class="cx"> 
</span><del>-    CHECK(invoke<long int>(*code, a, b) == ((long int) a) * ((long int) b));
</del><ins>+    for (auto nOperand : int32Operands()) {
+        for (auto mOperand : int32Operands()) {
+            int32_t n = nOperand.value;
+            int32_t m = mOperand.value;
+            CHECK_EQ(invoke<int64_t>(*code, n, m), static_cast<int64_t>(n) * static_cast<int64_t>(m));
+        }
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testMulArgs32ZeroExtend()
+{
+    Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* left = root->appendNew<Value>(proc, ZExt32, Origin(), arg1);
+    Value* right = root->appendNew<Value>(proc, ZExt32, Origin(), arg2);
+    Value* mul = root->appendNew<Value>(proc, Mul, Origin(), left, right);
+    root->appendNewControlValue(proc, Return, Origin(), mul);
+
+    auto code = compileProc(proc);
+    if (isARM64())
+        checkUsesInstruction(*code, "umull");
+
+    for (auto nOperand : int32Operands()) {
+        for (auto mOperand : int32Operands()) {
+            uint32_t n = nOperand.value;
+            uint32_t m = mOperand.value;
+            CHECK_EQ(invoke<uint64_t>(*code, n, m), static_cast<uint64_t>(n) * static_cast<uint64_t>(m));
+        }
+    }
+}
+
</ins><span class="cx"> void testMulImm32SignExtend(const int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3_3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3_3.cpp (280582 => 280583)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3_3.cpp      2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/JavaScriptCore/b3/testb3_3.cpp 2021-08-03 04:18:22 UTC (rev 280583)
</span><span class="lines">@@ -3730,10 +3730,8 @@
</span><span class="cx">     RUN(testMulArgs32(1, 2));
</span><span class="cx">     RUN(testMulArgs32(0xFFFFFFFF, 0xFFFFFFFF));
</span><span class="cx">     RUN(testMulArgs32(0xFFFFFFFE, 0xFFFFFFFF));
</span><del>-    RUN(testMulArgs32SignExtend(1, 1));
-    RUN(testMulArgs32SignExtend(1, 2));
-    RUN(testMulArgs32SignExtend(0xFFFFFFFF, 0xFFFFFFFF));
-    RUN(testMulArgs32SignExtend(0xFFFFFFFE, 0xFFFFFFFF));
</del><ins>+    RUN(testMulArgs32SignExtend());
+    RUN(testMulArgs32ZeroExtend());
</ins><span class="cx">     RUN(testMulLoadTwice());
</span><span class="cx">     RUN(testMulAddArgsLeft());
</span><span class="cx">     RUN(testMulAddArgsRight());
</span></span></pre>
</div>
</div>

</body>
</html>