Modified: trunk/Source/_javascript_Core/ChangeLog (279074 => 279075)
--- trunk/Source/_javascript_Core/ChangeLog 2021-06-21 18:50:08 UTC (rev 279074)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-06-21 18:55:59 UTC (rev 279075)
@@ -1,3 +1,58 @@
+2021-06-21 Yijia Huang <yijia_hu...@apple.com>
+
+ Add a new pattern to instruction selector to utilize SMSUBL supported by ARM64
+ https://bugs.webkit.org/show_bug.cgi?id=227195
+
+ Reviewed by Keith Miller.
+
+ Signed Multiply-Subtract Long(SMSUBL), supported by ARM64, multiplies two
+ 32-bit register values, subtracts the product from a 64-bit register value,
+ and writes the result 64-bit destination register. The instruction selector
+ can utilize this to lowering certain patterns in B3 IR before further Air
+ optimization. Given the operation:
+
+ smsubl d, n, m, a
+
+ The equivalent pattern would be:
+
+ d = a - SExt32(n) * SExt32(m)
+
+ Given B3 IR:
+ Int @0 = ArgumentReg(%x0)
+ Int @1 = SExt32(Trunc(ArgumentReg(%x1)))
+ Int @2 = SExt32(Trunc(ArgumentReg(%x2)))
+ Int @3 = Mul(@1, @2)
+ Int @4 = Sub(@0, @3)
+ Void@5 = Return(@4, Terminal)
+
+ Before Adding SMSUBL:
+ // Old optimized AIR
+ SignExtend32ToPtr %x1, %x1, @1
+ SignExtend32ToPtr %x2, %x2, @2
+ MultiplySub64 %x1, %x2, %x0, %x0, @4
+ Ret64 %x0, @5
+
+ After Adding SMSUBL:
+ // New optimized AIR
+ MultiplySubSignExtend32 %x1, %x2, %x0, %x0, @4
+ Ret64 %x0, @5
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::multiplySubSignExtend32):
+ * assembler/testmasm.cpp:
+ (JSC::testMulSubSignExtend32):
+ * b3/B3LowerToAir.cpp:
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.h:
+ * b3/testb3_2.cpp:
+ (testMulSubArgsLeft):
+ (testMulSubArgsRight):
+ (testMulSubArgsLeft32):
+ (testMulSubArgsRight32):
+ (testMulSubSignExtend32Args):
+ * b3/testb3_3.cpp:
+ (addArgTests):
+
2021-06-21 Kimmo Kinnunen <kkinnu...@apple.com>
makeUnique cannot be used to instantiate function-local classes
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (279074 => 279075)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-06-21 18:50:08 UTC (rev 279074)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-06-21 18:55:59 UTC (rev 279075)
@@ -2583,24 +2583,51 @@
&& isValidForm(multiplySubOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
Value* left = m_value->child(0);
Value* right = m_value->child(1);
- if (!imm(right) || m_valueToTmp[right]) {
- auto tryAppendMultiplySub = [&] () -> bool {
- if (right->opcode() != Mul || !canBeInternal(right))
- return false;
+ auto tryMultiply = [&] (Value* v) -> bool {
+ if (v->opcode() != Mul || !canBeInternal(v))
+ return false;
+ if (m_locked.contains(v->child(0)) || m_locked.contains(v->child(1)))
+ return false;
+ return true;
+ };
- Value* multiplyLeft = right->child(0);
- Value* multiplyRight = right->child(1);
- if (m_locked.contains(multiplyLeft) || m_locked.contains(multiplyRight))
- return false;
+ // MSUB: d = a - n * m
+ if ((!imm(right) || m_valueToTmp[right]) && tryMultiply(right)) {
+ Value* multiplyLeft = right->child(0);
+ Value* multiplyRight = right->child(1);
- append(multiplySubOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(left), tmp(m_value));
- commitInternal(right);
+ // SMSUBL: d = a - SExt32(n) * SExt32(m)
+ if (multiplySubOpcode == MultiplySub64
+ && isValidForm(MultiplySubSignExtend32, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
+ auto trySExt32 = [&] (Value* v) {
+ if (v->opcode() != SExt32 || !canBeInternal(v))
+ return false;
+ if (m_locked.contains(v->child(0)))
+ return false;
+ return true;
+ };
- return true;
- };
+ auto tryAppendMultiplySubSignExtend32 = [&] () -> bool {
+ if (!trySExt32(multiplyLeft) || !trySExt32(multiplyRight))
+ return false;
+ append(MultiplySubSignExtend32,
+ tmp(multiplyLeft->child(0)),
+ tmp(multiplyRight->child(0)),
+ tmp(left),
+ tmp(m_value));
+ commitInternal(right);
+ commitInternal(multiplyLeft);
+ commitInternal(multiplyRight);
+ return true;
+ };
- if (tryAppendMultiplySub())
- return;
+ if (tryAppendMultiplySubSignExtend32())
+ return;
+ }
+
+ append(multiplySubOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(left), tmp(m_value));
+ commitInternal(right);
+ return;
}
}
Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (279074 => 279075)
--- trunk/Source/_javascript_Core/b3/testb3_2.cpp 2021-06-21 18:50:08 UTC (rev 279074)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp 2021-06-21 18:55:59 UTC (rev 279075)
@@ -1102,17 +1102,18 @@
Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
- Value* added = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
- root->appendNewControlValue(proc, Return, Origin(), added);
+ Value* subtracted = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
+ root->appendNewControlValue(proc, Return, Origin(), subtracted);
auto code = compileProc(proc);
+ if (isARM64())
+ checkDoesNotUseInstruction(*code, "msub");
auto testValues = int64Operands();
for (auto a : testValues) {
for (auto b : testValues) {
- for (auto c : testValues) {
+ for (auto c : testValues)
CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value * b.value - c.value);
- }
}
}
}
@@ -1126,17 +1127,18 @@
Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
- Value* added = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
- root->appendNewControlValue(proc, Return, Origin(), added);
+ Value* subtracted = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
+ root->appendNewControlValue(proc, Return, Origin(), subtracted);
auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "msub");
auto testValues = int64Operands();
for (auto a : testValues) {
for (auto b : testValues) {
- for (auto c : testValues) {
+ for (auto c : testValues)
CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
- }
}
}
}
@@ -1153,17 +1155,18 @@
Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
- Value* added = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
- root->appendNewControlValue(proc, Return, Origin(), added);
+ Value* subtracted = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
+ root->appendNewControlValue(proc, Return, Origin(), subtracted);
auto code = compileProc(proc);
+ if (isARM64())
+ checkDoesNotUseInstruction(*code, "msub");
auto testValues = int32Operands();
for (auto a : testValues) {
for (auto b : testValues) {
- for (auto c : testValues) {
+ for (auto c : testValues)
CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value * b.value - c.value);
- }
}
}
}
@@ -1180,16 +1183,54 @@
Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
- Value* added = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
- root->appendNewControlValue(proc, Return, Origin(), added);
+ Value* subtracted = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
+ root->appendNewControlValue(proc, Return, Origin(), subtracted);
auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "msub");
auto testValues = int32Operands();
for (auto a : testValues) {
for (auto b : testValues) {
- for (auto c : testValues) {
+ for (auto c : testValues)
CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
+ }
+ }
+}
+
+void testMulSubSignExtend32Args()
+{
+ // d = a - SExt32(n) * SExt32(m)
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* aValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* nValue = root->appendNew<Value>(
+ proc, SExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+ Value* mValue = root->appendNew<Value>(
+ proc, SExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+ Value* mulValue = root->appendNew<Value>(proc, Mul, Origin(), nValue, mValue);
+ Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), aValue, mulValue);
+ root->appendNewControlValue(proc, Return, Origin(), subValue);
+
+ auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "smsubl");
+
+ for (auto a : int64Operands()) {
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ int64_t lhs = invoke<int64_t>(*code, a.value, n.value, m.value);
+ int64_t rhs = a.value - static_cast<int64_t>(n.value) * static_cast<int64_t>(m.value);
+ CHECK(lhs == rhs);
}
}
}