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
- trunk/Source/_javascript_Core/ChangeLog
- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h
- trunk/Source/_javascript_Core/assembler/testmasm.cpp
- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp
- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes
- trunk/Source/_javascript_Core/b3/testb3.h
- trunk/Source/_javascript_Core/b3/testb3_2.cpp
- trunk/Source/_javascript_Core/b3/testb3_3.cpp
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
