Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (279849 => 279850)
--- trunk/Source/_javascript_Core/ChangeLog 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-07-12 20:51:11 UTC (rev 279850)
@@ -1,3 +1,135 @@
+2021-07-12 Yijia Huang <yijia_hu...@apple.com>
+
+ Add SMNEGL, UMNEGL, UMADDL, and UMSUBL for ARM64 and select this instruction in Air
+ https://bugs.webkit.org/show_bug.cgi?id=227857
+
+ Reviewed by Robin Morisset.
+
+ The previous patches have already added MNEG, MADD, MSUB, SMADDL, and SMSUBL.
+ This patch completes the corresponding signed or unsigned variants (SMNEGL,
+ UMNEGL, UMADDL, and UMSUBL) of them. In addition, this patch refactors
+ the implementation and the associative test cases of MADD, MSUB, and MNEG
+ to be more readable and maintainable w.r.t their variants.
+
+ ------------------------------
+ ### SMNEGL/UMNEGL Xd Wn Wm ###
+ ------------------------------
+ Signed/Unsigned Multiply-Negate Long multiplies two 32-bit register values,
+ negates the product, and writes the result to the 64-bit destination register.
+ The equivalent patterns are
+
+ d = -(SExt32(n) * SExt32(m)) and d = -(ZExt32(n) * ZExt32(m)) respectively.
+
+ Given B3 IR:
+ Int @0 = S/ZExt32(Trunc(ArgumentReg(%x0)))
+ Int @1 = S/ZExt32(Trunc(ArgumentReg(%x1)))
+ Int @2 = Mul(@0, @1)
+ Int @3 = Neg(@2)
+ Void@4 = Return(@3, Terminal)
+
+ // Old optimized AIR
+ Move32 %x0, %x0, @0
+ Move32 %x1, %x1, @1
+ MultiplyNeg %x0, %x1, %x0, @3
+ Ret %x0, @4
+
+ // New optimized AIR
+ MultiplyNegSign/ZeroExtend %x0, %x1, %x0, @3
+ Ret %x0, @4
+
+ --------------------------
+ ### UMADDL Xd Wn Wm Xa ###
+ --------------------------
+ Unsigned Multiply-Add Long multiplies two 32-bit register values, adds a 64-bit
+ register value, and writes the result to the 64-bit destination register. The
+ equivalent patterns are
+
+ d = ZExt32(n) * ZExt32(m) + a or d = a + ZExt32(n) * ZExt32(m)
+
+ Given B3 IR:
+ Int @0 = ZExt32(Trunc(ArgumentReg(%x0)))
+ Int @1 = ZExt32(Trunc(ArgumentReg(%x1)))
+ Int @2 = ArgumentReg(%x2)
+ Int @3 = Mul(@0, @1)
+ Int @4 = Add(@3, @2)
+ Void@5 = Return(@4, Terminal)
+
+ // Old optimized AIR
+ Move32 %x0, %x0, @1
+ Move32 %x1, %x1, @2
+ MultiplyAdd %x0, %x1, %x2, %x0, @4
+ Ret64 %x0, @5
+
+ // New optimized AIR
+ MultiplyAddZeroExtend %x0, %x1, %x2, %x0, @8
+ Ret %x0, @9
+
+ --------------------------
+ ### UMSUBL Xd Wn Wm Xa ###
+ --------------------------
+ Unsigned Multiply-Subtract Long multiplies two 32-bit register values, subtracts
+ the product from a 64-bit register value, and writes the result to the 64-bit
+ destination register. The equivalent patterns are
+
+ d = a - ZExt32(n) * ZExt32(m)
+
+ Given B3 IR:
+ Int @0 = ZExt32(Trunc(ArgumentReg(%x0)))
+ Int @1 = ZExt32(Trunc(ArgumentReg(%x1)))
+ Int @2 = ArgumentReg(%x2)
+ Int @3 = Mul(@0, @1)
+ Int @4 = Sub(@2, @3)
+ Void@5 = Return(@4, Terminal)
+
+ // Old optimized AIR
+ Move32 %x0, %x0, @1
+ Move32 %x1, %x1, @2
+ MultiplySub %x0, %x1, %x2, %x0, @4
+ Ret64 %x0, @5
+
+ // New optimized AIR
+ MultiplySubZeroExtend %x0, %x1, %x2, %x0, @8
+ Ret %x0, @9
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::multiplyNeg32):
+ (JSC::MacroAssemblerARM64::multiplyAddZeroExtend32):
+ (JSC::MacroAssemblerARM64::multiplySubZeroExtend32):
+ (JSC::MacroAssemblerARM64::multiplyNeg64):
+ (JSC::MacroAssemblerARM64::multiplyNegSignExtend32):
+ (JSC::MacroAssemblerARM64::multiplyNegZeroExtend32):
+ * assembler/testmasm.cpp:
+ (JSC::testMultiplyAddSignExtend32):
+ (JSC::testMultiplyAddZeroExtend32):
+ (JSC::testMultiplySubSignExtend32):
+ (JSC::testMultiplySubZeroExtend32):
+ (JSC::testMultiplyNegSignExtend32):
+ (JSC::testMultiplyNegZeroExtend32):
+ (JSC::testMultiplyAddSignExtend32Left): Deleted.
+ (JSC::testMultiplyAddSignExtend32Right): Deleted.
+ * b3/B3LowerToAir.cpp:
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.h:
+ * b3/testb3_2.cpp:
+ (testMulAddArgsLeft):
+ (testMulAddArgsRight):
+ (testMulAddSignExtend32ArgsLeft):
+ (testMulAddZeroExtend32ArgsLeft):
+ (testMulAddZeroExtend32ArgsRight):
+ (testMulSubArgsLeft):
+ (testMulSubArgsRight):
+ (testMulSubArgsRight32):
+ (testMulSubSignExtend32):
+ (testMulSubZeroExtend32):
+ (testMulNegArgArg):
+ (testMulNegArgs):
+ (testMulNegArgs32):
+ (testMulNegSignExtend32):
+ (testMulNegZeroExtend32):
+ (testMulSubSignExtend32Args): Deleted.
+ * b3/testb3_3.cpp:
+ (addArgTests):
+
2021-07-12 Yusuke Suzuki <ysuz...@apple.com>
[JSC] JITCage already includes guard pages
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (279849 => 279850)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-07-12 20:51:11 UTC (rev 279850)
@@ -770,7 +770,7 @@
void multiplyNeg32(RegisterID mulLeft, RegisterID mulRight, RegisterID dest)
{
- m_assembler.msub<32>(dest, mulLeft, mulRight, ARM64Registers::zr);
+ m_assembler.mneg<32>(dest, mulLeft, mulRight);
}
void multiplyAdd64(RegisterID mulLeft, RegisterID mulRight, RegisterID summand, RegisterID dest)
@@ -783,6 +783,11 @@
m_assembler.smaddl(dest, mulLeft, mulRight, summand);
}
+ void multiplyAddZeroExtend32(RegisterID mulLeft, RegisterID mulRight, RegisterID summand, RegisterID dest)
+ {
+ m_assembler.umaddl(dest, mulLeft, mulRight, summand);
+ }
+
void multiplySub64(RegisterID mulLeft, RegisterID mulRight, RegisterID minuend, RegisterID dest)
{
m_assembler.msub<64>(dest, mulLeft, mulRight, minuend);
@@ -793,11 +798,26 @@
m_assembler.smsubl(dest, mulLeft, mulRight, minuend);
}
+ void multiplySubZeroExtend32(RegisterID mulLeft, RegisterID mulRight, RegisterID minuend, RegisterID dest)
+ {
+ m_assembler.umsubl(dest, mulLeft, mulRight, minuend);
+ }
+
void multiplyNeg64(RegisterID mulLeft, RegisterID mulRight, RegisterID dest)
{
- m_assembler.msub<64>(dest, mulLeft, mulRight, ARM64Registers::zr);
+ m_assembler.mneg<64>(dest, mulLeft, mulRight);
}
+ void multiplyNegSignExtend32(RegisterID mulLeft, RegisterID mulRight, RegisterID dest)
+ {
+ m_assembler.smnegl(dest, mulLeft, mulRight);
+ }
+
+ void multiplyNegZeroExtend32(RegisterID mulLeft, RegisterID mulRight, RegisterID dest)
+ {
+ m_assembler.umnegl(dest, mulLeft, mulRight);
+ }
+
void multiplySignExtend32(RegisterID left, RegisterID right, RegisterID dest)
{
m_assembler.smull(dest, left, right);
Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (279849 => 279850)
--- trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-07-12 20:51:11 UTC (rev 279850)
@@ -921,7 +921,7 @@
}
}
-void testMultiplyAddSignExtend32Left()
+void testMultiplyAddSignExtend32()
{
// d = SExt32(n) * SExt32(m) + a
auto add = compile([=] (CCallHelpers& jit) {
@@ -944,15 +944,15 @@
}
}
-void testMultiplyAddSignExtend32Right()
+void testMultiplyAddZeroExtend32()
{
- // d = a + SExt32(n) * SExt32(m)
+ // d = ZExt32(n) * ZExt32(m) + a
auto add = compile([=] (CCallHelpers& jit) {
emitFunctionPrologue(jit);
- jit.multiplyAddSignExtend32(GPRInfo::argumentGPR1,
+ jit.multiplyAddZeroExtend32(GPRInfo::argumentGPR0,
+ GPRInfo::argumentGPR1,
GPRInfo::argumentGPR2,
- GPRInfo::argumentGPR0,
GPRInfo::returnValueGPR);
emitFunctionEpilogue(jit);
@@ -959,10 +959,13 @@
jit.ret();
});
- for (auto a : int64Operands()) {
- for (auto n : int32Operands()) {
- for (auto m : int32Operands())
- CHECK_EQ(invoke<int64_t>(add, a, n, m), a + static_cast<int64_t>(n) * static_cast<int64_t>(m));
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ for (auto a : int64Operands()) {
+ uint32_t un = n;
+ uint32_t um = m;
+ CHECK_EQ(invoke<int64_t>(add, n, m, a), static_cast<int64_t>(un) * static_cast<int64_t>(um) + a);
+ }
}
}
}
@@ -1091,7 +1094,7 @@
void testMultiplySubSignExtend32()
{
- // d = a - SExt32(n) * SExt32(m)
+ // d = a - SExt32(n) * SExt32(m)
auto sub = compile([=] (CCallHelpers& jit) {
emitFunctionPrologue(jit);
@@ -1112,6 +1115,71 @@
}
}
+void testMultiplySubZeroExtend32()
+{
+ // d = a - (ZExt32(n) * ZExt32(m))
+ auto sub = compile([=] (CCallHelpers& jit) {
+ emitFunctionPrologue(jit);
+
+ jit.multiplySubZeroExtend32(GPRInfo::argumentGPR1,
+ GPRInfo::argumentGPR2,
+ GPRInfo::argumentGPR0,
+ GPRInfo::returnValueGPR);
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ });
+
+ for (auto a : int64Operands()) {
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ uint32_t un = n;
+ uint32_t um = m;
+ CHECK_EQ(invoke<int64_t>(sub, a, n, m), a - static_cast<int64_t>(un) * static_cast<int64_t>(um));
+ }
+ }
+ }
+}
+
+void testMultiplyNegSignExtend32()
+{
+ // d = - (SExt32(n) * SExt32(m))
+ auto neg = compile([=] (CCallHelpers& jit) {
+ emitFunctionPrologue(jit);
+
+ jit.multiplyNegSignExtend32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ });
+
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands())
+ CHECK_EQ(invoke<int64_t>(neg, n, m), -(static_cast<int64_t>(n) * static_cast<int64_t>(m)));
+ }
+}
+
+void testMultiplyNegZeroExtend32()
+{
+ // d = - ZExt32(n) * ZExt32(m)
+ auto neg = compile([=] (CCallHelpers& jit) {
+ emitFunctionPrologue(jit);
+
+ jit.multiplyNegZeroExtend32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ });
+
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ uint32_t un = n;
+ uint32_t um = m;
+ CHECK_EQ(invoke<uint64_t>(neg, n, m), -(static_cast<uint64_t>(un) * static_cast<uint64_t>(um)));
+ }
+ }
+}
+
void testExtractUnsignedBitfield32()
{
uint32_t src = ""
@@ -4164,9 +4232,12 @@
RUN(testSub64Imm64());
RUN(testSub64ArgImm64());
- RUN(testMultiplyAddSignExtend32Left());
- RUN(testMultiplyAddSignExtend32Right());
+ RUN(testMultiplyAddSignExtend32());
+ RUN(testMultiplyAddZeroExtend32());
RUN(testMultiplySubSignExtend32());
+ RUN(testMultiplySubZeroExtend32());
+ RUN(testMultiplyNegSignExtend32());
+ RUN(testMultiplyNegZeroExtend32());
RUN(testExtractUnsignedBitfield32());
RUN(testExtractUnsignedBitfield64());
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (279849 => 279850)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-07-12 20:51:11 UTC (rev 279850)
@@ -2485,6 +2485,15 @@
void lower()
{
using namespace Air;
+
+ auto isMergeableB3Opcode = [&] (Value* v, B3::Opcode b3Opcode) -> bool {
+ if (v->opcode() != b3Opcode || !canBeInternal(v))
+ return false;
+ if (m_locked.contains(v->child(0)))
+ return false;
+ return true;
+ };
+
switch (m_value->opcode()) {
case B3::Nop: {
// Yes, we will totally see Nop's because some phases will replaceWithNop() instead of
@@ -2567,72 +2576,71 @@
case Add: {
if (tryAppendLea())
return;
-
Value* left = m_value->child(0);
Value* right = m_value->child(1);
- ASSERT(isValidForm(MultiplyAdd64, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)
- == isValidForm(MultiplyAddSignExtend32, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp));
- Air::Opcode multiplyAddOpcode = tryOpcodeForType(MultiplyAdd32, MultiplyAdd64, m_value->type());
- if (isValidForm(multiplyAddOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
- if (!imm(right) || m_valueToTmp[right]) {
- 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;
- };
+ auto tryMultiplyAdd = [&] () -> bool {
+ if (imm(right) && !m_valueToTmp[right])
+ return false;
- auto trySExt32 = [&] (Value* v) -> bool {
- return v->opcode() == SExt32 && canBeInternal(v);
+ // MADD: d = n * m + a
+ auto tryAppendMultiplyAdd = [&] (Value* left, Value* right) -> bool {
+ if (left->opcode() != Mul || !canBeInternal(left) || m_locked.contains(right))
+ return false;
+ Value* multiplyLeft = left->child(0);
+ Value* multiplyRight = left->child(1);
+ Air::Opcode airOpcode = tryOpcodeForType(MultiplyAdd32, MultiplyAdd64, m_value->type());
+ auto tryNewAirOpcode = [&] () -> Air::Opcode {
+ if (airOpcode != MultiplyAdd64)
+ return Air::Oops;
+ // SMADDL: d = SExt32(n) * SExt32(m) + a
+ if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32))
+ return MultiplyAddSignExtend32;
+ // UMADDL: d = ZExt32(n) * ZExt32(m) + a
+ if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32))
+ return MultiplyAddZeroExtend32;
+ return Air::Oops;
};
- // MADD: d = n * m + a
- auto tryAppendMultiplyAdd = [&] (Value* left, Value* right) -> bool {
- if (!tryMultiply(left))
- return false;
- Value* multiplyLeft = left->child(0);
- Value* multiplyRight = left->child(1);
-
- // SMADDL: d = SExt32(n) * SExt32(m) + a
- if (multiplyAddOpcode == MultiplyAdd64 && trySExt32(multiplyLeft) && trySExt32(multiplyRight)) {
- append(MultiplyAddSignExtend32,
- tmp(multiplyLeft->child(0)),
- tmp(multiplyRight->child(0)),
- tmp(right),
- tmp(m_value));
- commitInternal(multiplyLeft);
- commitInternal(multiplyRight);
- commitInternal(left);
- return true;
- }
-
- append(multiplyAddOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(right), tmp(m_value));
+ 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;
- };
+ }
- if (tryAppendMultiplyAdd(left, right) || tryAppendMultiplyAdd(right, left))
- return;
- }
- }
+ if (!isValidForm(airOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp))
+ return false;
+ if (m_locked.contains(multiplyLeft) || m_locked.contains(multiplyRight))
+ return false;
+ append(airOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(right), tmp(m_value));
+ commitInternal(left);
+ return true;
+ };
- // add-with-shift Pattern: n + (m ShiftType amount)
- auto tryOpcode = [&] (JSC::B3::Opcode opcode) -> Air::Opcode {
- switch (opcode) {
- case Shl:
- return tryOpcodeForType(AddLeftShift32, AddLeftShift64, m_value->type());
- case SShr:
- return tryOpcodeForType(AddRightShift32, AddRightShift64, m_value->type());
- case ZShr:
- return tryOpcodeForType(AddUnsignedRightShift32, AddUnsignedRightShift64, m_value->type());
- default:
- return Air::Oops;
- }
+ return tryAppendMultiplyAdd(left, right) || tryAppendMultiplyAdd(right, left);
};
- auto tryAppendAddAndShift = [&] (Value* left, Value* right) -> bool {
+ if (tryMultiplyAdd())
+ return;
+
+ // add-with-shift Pattern: n + (m ShiftType amount)
+ auto tryAppendAddWithShift = [&] (Value* left, Value* right) -> bool {
+ auto tryOpcode = [&] (B3::Opcode opcode) -> Air::Opcode {
+ switch (opcode) {
+ case Shl:
+ return tryOpcodeForType(AddLeftShift32, AddLeftShift64, m_value->type());
+ case SShr:
+ return tryOpcodeForType(AddRightShift32, AddRightShift64, m_value->type());
+ case ZShr:
+ return tryOpcodeForType(AddUnsignedRightShift32, AddUnsignedRightShift64, m_value->type());
+ default:
+ return Air::Oops;
+ }
+ };
+
Air::Opcode opcode = tryOpcode(right->opcode());
if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
return false;
@@ -2649,7 +2657,7 @@
return true;
};
- if (tryAppendAddAndShift(left, right) || tryAppendAddAndShift(right, left))
+ if (tryAppendAddWithShift(left, right) || tryAppendAddWithShift(right, left))
return;
appendBinOp<Add32, Add64, AddDouble, AddFloat, Commutative>(left, right);
@@ -2660,72 +2668,64 @@
Value* left = m_value->child(0);
Value* right = m_value->child(1);
- Air::Opcode multiplySubOpcode = tryOpcodeForType(MultiplySub32, MultiplySub64, m_value->type());
- if (multiplySubOpcode != Air::Oops
- && isValidForm(multiplySubOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
- 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;
- };
+ auto tryAppendMultiplySub = [&] () -> bool {
+ if (imm(right) && !m_valueToTmp[right])
+ 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);
-
+ if (m_locked.contains(left) || right->opcode() != Mul || !canBeInternal(right))
+ return false;
+ Value* multiplyLeft = right->child(0);
+ Value* multiplyRight = right->child(1);
+ Air::Opcode airOpcode = tryOpcodeForType(MultiplySub32, MultiplySub64, m_value->type());
+ auto tryNewAirOpcode = [&] () -> Air::Opcode {
+ if (airOpcode != MultiplySub64)
+ return Air::Oops;
// 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;
- };
+ if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32))
+ return MultiplySubSignExtend32;
+ // UMSUBL: d = a - ZExt32(n) * ZExt32(m)
+ if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32))
+ return MultiplySubZeroExtend32;
+ return Air::Oops;
+ };
- 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 (tryAppendMultiplySubSignExtend32())
- return;
- }
-
- append(multiplySubOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(left), tmp(m_value));
+ 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;
+ return true;
}
- }
- // sub-with-shift Pattern: n - (m ShiftType amount)
- auto tryOpcode = [&] (JSC::B3::Opcode opcode) -> Air::Opcode {
- switch (opcode) {
- case Shl:
- return tryOpcodeForType(SubLeftShift32, SubLeftShift64, m_value->type());
- case SShr:
- return tryOpcodeForType(SubRightShift32, SubRightShift64, m_value->type());
- case ZShr:
- return tryOpcodeForType(SubUnsignedRightShift32, SubUnsignedRightShift64, m_value->type());
- default:
- return Air::Oops;
- }
+ if (!isValidForm(airOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp, Arg::Tmp))
+ return false;
+ if (m_locked.contains(multiplyLeft) || m_locked.contains(multiplyRight))
+ return false;
+ append(airOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(left), tmp(m_value));
+ commitInternal(right);
+ return true;
};
+ if (tryAppendMultiplySub())
+ return;
+
+ // sub-with-shift Pattern: n - (m ShiftType amount)
auto tryAppendSubAndShift = [&] () -> bool {
+ auto tryOpcode = [&] (B3::Opcode opcode) -> Air::Opcode {
+ switch (opcode) {
+ case Shl:
+ return tryOpcodeForType(SubLeftShift32, SubLeftShift64, m_value->type());
+ case SShr:
+ return tryOpcodeForType(SubRightShift32, SubRightShift64, m_value->type());
+ case ZShr:
+ return tryOpcodeForType(SubUnsignedRightShift32, SubUnsignedRightShift64, m_value->type());
+ default:
+ return Air::Oops;
+ }
+ };
+
Air::Opcode opcode = tryOpcode(right->opcode());
if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
return false;
@@ -2750,21 +2750,46 @@
}
case Neg: {
- Air::Opcode multiplyNegOpcode = tryOpcodeForType(MultiplyNeg32, MultiplyNeg64, m_value->type());
- if (multiplyNegOpcode != Air::Oops
- && isValidForm(multiplyNegOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)
- && m_value->child(0)->opcode() == Mul
- && canBeInternal(m_value->child(0))) {
- Value* multiplyOperation = m_value->child(0);
- Value* multiplyLeft = multiplyOperation->child(0);
- Value* multiplyRight = multiplyOperation->child(1);
- if (!m_locked.contains(multiplyLeft) && !m_locked.contains(multiplyRight)) {
- append(multiplyNegOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(m_value));
- commitInternal(multiplyOperation);
- return;
+ auto tryAppendMultiplyNeg = [&] () -> bool {
+ // MNEG : d = -(n * m)
+ if (m_value->child(0)->opcode() != Mul || !canBeInternal(m_value->child(0)))
+ return false;
+ Value* multiplyLeft = m_value->child(0)->child(0);
+ Value* multiplyRight = m_value->child(0)->child(1);
+ Air::Opcode airOpcode = tryOpcodeForType(MultiplyNeg32, MultiplyNeg64, m_value->type());
+ auto tryNewAirOpcode = [&] () -> Air::Opcode {
+ if (airOpcode != MultiplyNeg64)
+ return Air::Oops;
+ // SMNEGL: d = -(SExt32(n) * SExt32(m))
+ if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32))
+ return MultiplyNegSignExtend32;
+ // UMNEGL: d = -(ZExt32(n) * ZExt32(m))
+ if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32))
+ return MultiplyNegZeroExtend32;
+ return Air::Oops;
+ };
+
+ 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;
}
- }
+ if (!isValidForm(airOpcode, Arg::Tmp, Arg::Tmp, Arg::Tmp))
+ return false;
+ if (m_locked.contains(multiplyLeft) || m_locked.contains(multiplyRight))
+ return false;
+ append(airOpcode, tmp(multiplyLeft), tmp(multiplyRight), tmp(m_value));
+ commitInternal(m_value->child(0));
+ return true;
+ };
+
+ if (tryAppendMultiplyNeg())
+ return;
+
appendUnOp<Neg32, Neg64, NegateDouble, NegateFloat>(m_value->child(0));
return;
}
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (279849 => 279850)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-07-12 20:51:11 UTC (rev 279850)
@@ -254,6 +254,9 @@
arm64: MultiplyAddSignExtend32 U:G:32, U:G:32, U:G:64, D:G:64
Tmp, Tmp, Tmp, Tmp
+arm64: MultiplyAddZeroExtend32 U:G:32, U:G:32, U:G:64, D:G:64
+ Tmp, Tmp, Tmp, Tmp
+
arm64: MultiplySub32 U:G:32, U:G:32, U:G:32, ZD:G:32
Tmp, Tmp, Tmp, Tmp
@@ -263,6 +266,9 @@
arm64: MultiplySubSignExtend32 U:G:32, U:G:32, U:G:64, D:G:64
Tmp, Tmp, Tmp, Tmp
+arm64: MultiplySubZeroExtend32 U:G:32, U:G:32, U:G:64, D:G:64
+ Tmp, Tmp, Tmp, Tmp
+
arm64: MultiplyNeg32 U:G:32, U:G:32, ZD:G:32
Tmp, Tmp, Tmp
@@ -269,9 +275,15 @@
arm64: MultiplyNeg64 U:G:64, U:G:64, ZD:G:64
Tmp, Tmp, Tmp
-arm64: MultiplySignExtend32 U:G:32, U:G:32, ZD:G:64
+arm64: MultiplyNegSignExtend32 U:G:32, U:G:32, D:G:64
Tmp, Tmp, Tmp
+arm64: MultiplyNegZeroExtend32 U:G:32, U:G:32, D:G:64
+ Tmp, Tmp, Tmp
+
+arm64: MultiplySignExtend32 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 (279849 => 279850)
--- trunk/Source/_javascript_Core/b3/testb3.h 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/b3/testb3.h 2021-07-12 20:51:11 UTC (rev 279850)
@@ -913,13 +913,18 @@
void testMulAddArgsRight32();
void testMulAddSignExtend32ArgsLeft();
void testMulAddSignExtend32ArgsRight();
+void testMulAddZeroExtend32ArgsLeft();
+void testMulAddZeroExtend32ArgsRight();
void testMulSubArgsLeft();
void testMulSubArgsRight();
void testMulSubArgsLeft32();
void testMulSubArgsRight32();
-void testMulSubSignExtend32Args();
+void testMulSubSignExtend32();
+void testMulSubZeroExtend32();
void testMulNegArgs();
void testMulNegArgs32();
+void testMulNegSignExtend32();
+void testMulNegZeroExtend32();
void testMulArgDouble(double);
void testMulArgsDouble(double, double);
void testCallSimpleDouble(double, double);
Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (279849 => 279850)
--- trunk/Source/_javascript_Core/b3/testb3_2.cpp 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp 2021-07-12 20:51:11 UTC (rev 279850)
@@ -874,19 +874,6 @@
CHECK(compileAndRun<int>(proc, a, b) == a * (-b));
}
-void testMulNegArgArg(int a, int b)
-{
- Procedure proc;
- BasicBlock* root = proc.addBlock();
- Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
- Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
- Value* negA = root->appendNew<Value>(proc, Neg, Origin(), argA);
- Value* result = root->appendNew<Value>(proc, Mul, Origin(), negA, argB);
- root->appendNew<Value>(proc, Return, Origin(), result);
-
- CHECK(compileAndRun<int>(proc, a, b) == (-a) * b);
-}
-
void testMulArgImm(int64_t a, int64_t b)
{
Procedure proc;
@@ -1014,7 +1001,7 @@
for (auto a : testValues) {
for (auto b : testValues) {
for (auto c : testValues)
- CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value * b.value + c.value);
+ CHECK_EQ(invoke<int64_t>(*code, a.value, b.value, c.value), a.value * b.value + c.value);
}
}
}
@@ -1039,7 +1026,7 @@
for (auto a : testValues) {
for (auto b : testValues) {
for (auto c : testValues)
- CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value + b.value * c.value);
+ CHECK_EQ(invoke<int64_t>(*code, a.value, b.value, c.value), a.value + b.value * c.value);
}
}
}
@@ -1046,7 +1033,7 @@
void testMulAddSignExtend32ArgsLeft()
{
- // d = SExt32(n) * SExt32(m) + a
+ // d = SExt32(n) * SExt32(m) + a
Procedure proc;
BasicBlock* root = proc.addBlock();
@@ -1118,6 +1105,84 @@
}
}
+void testMulAddZeroExtend32ArgsLeft()
+{
+ // d = ZExt32(n) * ZExt32(m) + a
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* nValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+ Value* mValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+ Value* aValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+
+ Value* mulValue = root->appendNew<Value>(proc, Mul, Origin(), nValue, mValue);
+ Value* addValue = root->appendNew<Value>(proc, Add, Origin(), mulValue, aValue);
+ root->appendNewControlValue(proc, Return, Origin(), addValue);
+
+ auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "umaddl");
+
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ for (auto a : int64Operands()) {
+ uint32_t un = n.value;
+ uint32_t um = m.value;
+ int64_t lhs = invoke<int64_t>(*code, un, um, a.value);
+ int64_t rhs = static_cast<int64_t>(un) * static_cast<int64_t>(um) + a.value;
+ CHECK(lhs == rhs);
+ }
+ }
+ }
+}
+
+void testMulAddZeroExtend32ArgsRight()
+{
+ // d = a + ZExt32(n) * ZExt32(m)
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* aValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* nValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+ Value* mValue = root->appendNew<Value>(
+ proc, ZExt32, 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* addValue = root->appendNew<Value>(proc, Add, Origin(), aValue, mulValue);
+ root->appendNewControlValue(proc, Return, Origin(), addValue);
+
+ auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "umaddl");
+
+ for (auto a : int64Operands()) {
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ uint32_t un = n.value;
+ uint32_t um = m.value;
+ int64_t lhs = invoke<int64_t>(*code, a.value, un, um);
+ int64_t rhs = a.value + static_cast<int64_t>(un) * static_cast<int64_t>(um);
+ CHECK(lhs == rhs);
+ }
+ }
+ }
+}
+
void testMulAddArgsLeft32()
{
Procedure proc;
@@ -1194,7 +1259,7 @@
for (auto a : testValues) {
for (auto b : testValues) {
for (auto c : testValues)
- CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value * b.value - c.value);
+ CHECK_EQ(invoke<int64_t>(*code, a.value, b.value, c.value), a.value * b.value - c.value);
}
}
}
@@ -1219,7 +1284,7 @@
for (auto a : testValues) {
for (auto b : testValues) {
for (auto c : testValues)
- CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
+ CHECK_EQ(invoke<int64_t>(*code, a.value, b.value, c.value), a.value - b.value * c.value);
}
}
}
@@ -1275,12 +1340,12 @@
for (auto a : testValues) {
for (auto b : testValues) {
for (auto c : testValues)
- CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
+ CHECK_EQ(invoke<int32_t>(*code, a.value, b.value, c.value), a.value - b.value * c.value);
}
}
}
-void testMulSubSignExtend32Args()
+void testMulSubSignExtend32()
{
// d = a - SExt32(n) * SExt32(m)
Procedure proc;
@@ -1317,6 +1382,62 @@
}
}
+void testMulSubZeroExtend32()
+{
+ // d = a - ZExt32(n) * ZExt32(m)
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* aValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* nValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+ Value* mValue = root->appendNew<Value>(
+ proc, ZExt32, 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, "umsubl");
+
+ for (auto a : int64Operands()) {
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ uint32_t un = n.value;
+ uint32_t um = m.value;
+ int64_t lhs = invoke<int64_t>(*code, a.value, un, um);
+ int64_t rhs = a.value - static_cast<int64_t>(un) * static_cast<int64_t>(um);
+ CHECK(lhs == rhs);
+ }
+ }
+ }
+}
+
+void testMulNegArgArg(int32_t a, int32_t b)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ Value* negA = root->appendNew<Value>(proc, Neg, Origin(), argA);
+ Value* result = root->appendNew<Value>(proc, Mul, Origin(), negA, argB);
+ root->appendNew<Value>(proc, Return, Origin(), result);
+
+ auto code = compileProc(proc);
+ if (isARM64() && JSC::Options::defaultB3OptLevel() > 1)
+ checkUsesInstruction(*code, "mneg");
+ CHECK_EQ(invoke<int32_t>(*code, a, b), (-a) * b);
+}
+
void testMulNegArgs()
{
Procedure proc;
@@ -1330,11 +1451,13 @@
root->appendNewControlValue(proc, Return, Origin(), added);
auto code = compileProc(proc);
+ if (isARM64() && JSC::Options::defaultB3OptLevel() > 1)
+ checkUsesInstruction(*code, "mneg");
auto testValues = int64Operands();
for (auto a : testValues) {
for (auto b : testValues) {
- CHECK(invoke<int64_t>(*code, a.value, b.value) == -(a.value * b.value));
+ CHECK_EQ(invoke<int64_t>(*code, a.value, b.value), -(a.value * b.value));
}
}
}
@@ -1354,15 +1477,86 @@
root->appendNewControlValue(proc, Return, Origin(), added);
auto code = compileProc(proc);
+ if (isARM64() && JSC::Options::defaultB3OptLevel() > 1)
+ checkUsesInstruction(*code, "mneg");
auto testValues = int32Operands();
for (auto a : testValues) {
- for (auto b : testValues) {
- CHECK(invoke<int32_t>(*code, a.value, b.value) == -(a.value * b.value));
+ for (auto b : testValues)
+ CHECK_EQ(invoke<int32_t>(*code, a.value, b.value), -(a.value * b.value));
+ }
+}
+
+void testMulNegSignExtend32()
+{
+ // d = - (SExt32(n) * SExt32(m))
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* nValue = root->appendNew<Value>(
+ proc, SExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+ Value* mValue = root->appendNew<Value>(
+ proc, SExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+ Value* mulValue = root->appendNew<Value>(proc, Mul, Origin(), nValue, mValue);
+ Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mulValue);
+ root->appendNewControlValue(proc, Return, Origin(), negValue);
+
+ auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "smnegl");
+
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ int64_t lhs = invoke<int64_t>(*code, n.value, m.value);
+ int64_t rhs = -(static_cast<int64_t>(n.value) * static_cast<int64_t>(m.value));
+ CHECK(lhs == rhs);
}
}
}
+void testMulNegZeroExtend32()
+{
+ // d = - (ZExt32(n) * ZExt32(m))
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* nValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+ Value* mValue = root->appendNew<Value>(
+ proc, ZExt32, Origin(),
+ root->appendNew<Value>(
+ proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+ Value* mulValue = root->appendNew<Value>(proc, Mul, Origin(), nValue, mValue);
+ Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mulValue);
+ root->appendNewControlValue(proc, Return, Origin(), negValue);
+
+ auto code = compileProc(proc);
+ if (isARM64())
+ checkUsesInstruction(*code, "umnegl");
+
+ for (auto n : int32Operands()) {
+ for (auto m : int32Operands()) {
+ uint32_t un = n.value;
+ uint32_t um = m.value;
+ int64_t lhs = invoke<int64_t>(*code, un, um);
+ int64_t rhs = -(static_cast<int64_t>(un) * static_cast<int64_t>(um));
+ CHECK(lhs == rhs);
+ }
+ }
+}
+
void testMulArgDouble(double a)
{
Procedure proc;
Modified: trunk/Source/_javascript_Core/b3/testb3_3.cpp (279849 => 279850)
--- trunk/Source/_javascript_Core/b3/testb3_3.cpp 2021-07-12 20:46:41 UTC (rev 279849)
+++ trunk/Source/_javascript_Core/b3/testb3_3.cpp 2021-07-12 20:51:11 UTC (rev 279850)
@@ -3370,13 +3370,18 @@
RUN(testMulAddArgsRight32());
RUN(testMulAddSignExtend32ArgsLeft());
RUN(testMulAddSignExtend32ArgsRight());
+ RUN(testMulAddZeroExtend32ArgsLeft());
+ RUN(testMulAddZeroExtend32ArgsRight());
RUN(testMulSubArgsLeft());
RUN(testMulSubArgsRight());
RUN(testMulSubArgsLeft32());
RUN(testMulSubArgsRight32());
- RUN(testMulSubSignExtend32Args());
+ RUN(testMulSubSignExtend32());
+ RUN(testMulSubZeroExtend32());
RUN(testMulNegArgs());
RUN(testMulNegArgs32());
+ RUN(testMulNegSignExtend32());
+ RUN(testMulNegZeroExtend32());
RUN_BINARY(testMulArgNegArg, int64Operands(), int64Operands())
RUN_BINARY(testMulNegArgArg, int64Operands(), int64Operands())