Title: [280583] trunk/Source/_javascript_Core
Revision
280583
Author
[email protected]
Date
2021-08-02 21:18:22 -0700 (Mon, 02 Aug 2021)

Log Message

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):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (280582 => 280583)


--- trunk/Source/_javascript_Core/ChangeLog	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-08-03 04:18:22 UTC (rev 280583)
@@ -1,5 +1,52 @@
 2021-08-02  Yijia Huang  <[email protected]>
 
+        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  <[email protected]>
+
         Add new patterns to instruction selector to utilize AND/EOR/ORR-with-shift supported by ARM64
         https://bugs.webkit.org/show_bug.cgi?id=228675
 

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (280582 => 280583)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-08-03 04:18:22 UTC (rev 280583)
@@ -953,6 +953,11 @@
         m_assembler.smull(dest, left, right);
     }
 
+    void multiplyZeroExtend32(RegisterID left, RegisterID right, RegisterID dest)
+    {
+        m_assembler.umull(dest, left, right);
+    }
+
     void div32(RegisterID dividend, RegisterID divisor, RegisterID dest)
     {
         m_assembler.sdiv<32>(dest, dividend, divisor);

Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (280582 => 280583)


--- trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-08-03 04:18:22 UTC (rev 280583)
@@ -921,6 +921,26 @@
     }
 }
 
+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));
+        }
+    }
+}
+
 void testMultiplyAddSignExtend32()
 {
     // d = SExt32(n) * SExt32(m) + a
@@ -5649,6 +5669,7 @@
     RUN(testLoadStorePair64Int64());
     RUN(testLoadStorePair64Double());
     RUN(testMultiplySignExtend32());
+    RUN(testMultiplyZeroExtend32());
 
     RUN(testSub32Args());
     RUN(testSub32Imm());

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (280582 => 280583)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-08-03 04:18:22 UTC (rev 280583)
@@ -499,7 +499,7 @@
         return true;
     }
 
-    bool isMergeableValue(Value* v, B3::Opcode b3Opcode, bool checkCanBeInternal)
+    bool isMergeableValue(Value* v, B3::Opcode b3Opcode, bool checkCanBeInternal = false)
     { 
         if (v->opcode() != b3Opcode)
             return false;
@@ -516,9 +516,9 @@
 #if CPU(ARM64)
         // Maybe, the ideal approach is to introduce a decorator (Index@EXT) to the Air operand 
         // to provide an extension opportunity for the specific form under the Air opcode.
-        if (isMergeableValue(index, ZExt32, false))
+        if (isMergeableValue(index, ZExt32))
             return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::ZExt32);
-        if (isMergeableValue(index, SExt32, false))
+        if (isMergeableValue(index, SExt32))
             return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::SExt32);
 #endif
         return Arg::index(base, tmp(index), scale, offset);
@@ -2689,10 +2689,10 @@
                         if (airOpcode != MultiplyAdd64)
                             return Air::Oops;
                         // SMADDL: d = SExt32(n) * SExt32(m) + a
-                        if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
+                        if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
                             return MultiplyAddSignExtend32;
                         // UMADDL: d = ZExt32(n) * ZExt32(m) + a
-                        if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
+                        if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
                             return MultiplyAddZeroExtend32;
                         return Air::Oops;
                     };
@@ -2700,8 +2700,6 @@
                     Air::Opcode newAirOpcode = tryNewAirOpcode();
                     if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
                         append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(right), tmp(m_value));
-                        commitInternal(multiplyLeft);
-                        commitInternal(multiplyRight);
                         commitInternal(left);
                         return true;
                     }
@@ -2755,10 +2753,10 @@
                     if (airOpcode != MultiplySub64)
                         return Air::Oops;
                     // SMSUBL: d = a - SExt32(n) * SExt32(m)
-                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
+                    if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
                         return MultiplySubSignExtend32;
                     // UMSUBL: d = a - ZExt32(n) * ZExt32(m)
-                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
+                    if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
                         return MultiplySubZeroExtend32;
                     return Air::Oops;
                 };
@@ -2766,8 +2764,6 @@
                 Air::Opcode newAirOpcode = tryNewAirOpcode();
                 if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
                     append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(left), tmp(m_value));
-                    commitInternal(multiplyLeft);
-                    commitInternal(multiplyRight);
                     commitInternal(right);
                     return true;
                 }
@@ -2808,10 +2804,10 @@
                     if (airOpcode != MultiplyNeg64)
                         return Air::Oops;
                     // SMNEGL: d = -(SExt32(n) * SExt32(m))
-                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
+                    if (isMergeableValue(multiplyLeft, SExt32) && isMergeableValue(multiplyRight, SExt32))
                         return MultiplyNegSignExtend32;
                     // UMNEGL: d = -(ZExt32(n) * ZExt32(m))
-                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
+                    if (isMergeableValue(multiplyLeft, ZExt32) && isMergeableValue(multiplyRight, ZExt32))
                         return MultiplyNegZeroExtend32;
                     return Air::Oops;
                 };
@@ -2819,8 +2815,6 @@
                 Air::Opcode newAirOpcode = tryNewAirOpcode();
                 if (isValidForm(newAirOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
                     append(newAirOpcode, tmp(multiplyLeft->child(0)), tmp(multiplyRight->child(0)), tmp(m_value));
-                    commitInternal(multiplyLeft);
-                    commitInternal(multiplyRight);
                     commitInternal(m_value->child(0));
                     return true;
                 }
@@ -2842,29 +2836,34 @@
         }
 
         case Mul: {
-            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;
+            Value* left = m_value->child(0);
+            Value* right = m_value->child(1);
 
-                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;
+            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;
                 }
+                return false;
+            };
 
-                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));
+            if (tryAppendMultiplyWithExtend())
+                return;
+
+            appendBinOp<Mul32, Mul64, MulDouble, MulFloat, Commutative>(left, right);
             return;
         }
 
@@ -3002,7 +3001,7 @@
             //        mask = (1 << lowWidth) - 1
             auto tryAppendEXTR = [&] (Value* left, Value* right) -> bool {
                 Air::Opcode opcode = opcodeForType(ExtractRegister32, ExtractRegister64, m_value->type());
-                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp)) 
+                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
                     return false;
                 if (left->opcode() != Shl || left->child(0)->opcode() != BitAnd || right->opcode() != ZShr)
                     return false;
@@ -3208,7 +3207,7 @@
                         XorNotLeftShift32, XorNotLeftShift64, 
                         XorNotRightShift32, XorNotRightShift64, 
                         XorNotUnsignedRightShift32, XorNotUnsignedRightShift64);
-                    if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp)) 
+                    if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
                         return false;
                     Value* mValue = shiftValue->child(0);
                     Value* amountValue = shiftValue->child(1);

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (280582 => 280583)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2021-08-03 04:18:22 UTC (rev 280583)
@@ -284,6 +284,9 @@
 arm64: MultiplySignExtend32 U:G:32, U:G:32, D:G:64
     Tmp, Tmp, Tmp
 
+arm64: MultiplyZeroExtend32 U:G:32, U:G:32, D:G:64
+    Tmp, Tmp, Tmp
+
 arm64: Div32 U:G:32, U:G:32, ZD:G:32
     Tmp, Tmp, Tmp
 

Modified: trunk/Source/_javascript_Core/b3/testb3.h (280582 => 280583)


--- trunk/Source/_javascript_Core/b3/testb3.h	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/b3/testb3.h	2021-08-03 04:18:22 UTC (rev 280583)
@@ -939,7 +939,8 @@
 void testMulArgImm(int64_t, int64_t);
 void testMulImmArg(int, int);
 void testMulArgs32(int, int);
-void testMulArgs32SignExtend(int, int);
+void testMulArgs32SignExtend();
+void testMulArgs32ZeroExtend();
 void testMulImm32SignExtend(const int, int);
 void testMulLoadTwice();
 void testMulAddArgsLeft();

Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (280582 => 280583)


--- trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-08-03 04:18:22 UTC (rev 280583)
@@ -1228,10 +1228,10 @@
     CHECK(compileAndRun<int>(proc, a, b) == a * b);
 }
 
-void testMulArgs32SignExtend(int a, int b)
+void testMulArgs32SignExtend()
 {
     Procedure proc;
-    if (proc.optLevel() < 1)
+    if (proc.optLevel() < 2)
         return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
@@ -1246,10 +1246,48 @@
     root->appendNewControlValue(proc, Return, Origin(), mul);
 
     auto code = compileProc(proc);
+    if (isARM64())
+        checkUsesInstruction(*code, "smull");
 
-    CHECK(invoke<long int>(*code, a, b) == ((long int) a) * ((long int) b));
+    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));
+        }
+    }
 }
 
+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));
+        }
+    }
+}
+
 void testMulImm32SignExtend(const int a, int b)
 {
     Procedure proc;

Modified: trunk/Source/_javascript_Core/b3/testb3_3.cpp (280582 => 280583)


--- trunk/Source/_javascript_Core/b3/testb3_3.cpp	2021-08-03 03:53:25 UTC (rev 280582)
+++ trunk/Source/_javascript_Core/b3/testb3_3.cpp	2021-08-03 04:18:22 UTC (rev 280583)
@@ -3730,10 +3730,8 @@
     RUN(testMulArgs32(1, 2));
     RUN(testMulArgs32(0xFFFFFFFF, 0xFFFFFFFF));
     RUN(testMulArgs32(0xFFFFFFFE, 0xFFFFFFFF));
-    RUN(testMulArgs32SignExtend(1, 1));
-    RUN(testMulArgs32SignExtend(1, 2));
-    RUN(testMulArgs32SignExtend(0xFFFFFFFF, 0xFFFFFFFF));
-    RUN(testMulArgs32SignExtend(0xFFFFFFFE, 0xFFFFFFFF));
+    RUN(testMulArgs32SignExtend());
+    RUN(testMulArgs32ZeroExtend());
     RUN(testMulLoadTwice());
     RUN(testMulAddArgsLeft());
     RUN(testMulAddArgsRight());
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to