Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (287159 => 287160)
--- trunk/Source/_javascript_Core/ChangeLog 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-12-16 23:30:22 UTC (rev 287160)
@@ -1,3 +1,63 @@
+2021-12-16 Saam Barati <sbar...@apple.com>
+
+ Use arm64's fmax/fmin instructions in Wasm
+ https://bugs.webkit.org/show_bug.cgi?id=234367
+
+ Reviewed by Keith Miller.
+
+ This patch adds support in B3 for FMax and FMin. We use this for Wasm's f32/64
+ min/max operations. On arm64, we select the arm64 fmin/fmax instructions
+ for these B3 opcodes. On x86, we lower these to control flow to calculate the
+ result inside of lower macros.
+
+ This speeds up Wasm programs that make heavy usage of min/max.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::floatMax):
+ (JSC::MacroAssemblerARM64::floatMin):
+ (JSC::MacroAssemblerARM64::doubleMax):
+ (JSC::MacroAssemblerARM64::doubleMin):
+ * b3/B3Common.h:
+ (JSC::B3::fMax):
+ (JSC::B3::fMin):
+ * b3/B3ConstDoubleValue.cpp:
+ (JSC::B3::ConstDoubleValue::fMinConstant const):
+ (JSC::B3::ConstDoubleValue::fMaxConstant const):
+ * b3/B3ConstDoubleValue.h:
+ * b3/B3ConstFloatValue.cpp:
+ (JSC::B3::ConstFloatValue::fMinConstant const):
+ (JSC::B3::ConstFloatValue::fMaxConstant const):
+ * b3/B3ConstFloatValue.h:
+ * b3/B3LowerMacros.cpp:
+ * b3/B3LowerToAir.cpp:
+ * b3/B3Opcode.cpp:
+ (WTF::printInternal):
+ * b3/B3Opcode.h:
+ * b3/B3ReduceStrength.cpp:
+ * b3/B3Validate.cpp:
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::fMinConstant const):
+ (JSC::B3::Value::fMaxConstant const):
+ (JSC::B3::Value::effects const):
+ (JSC::B3::Value::key const):
+ (JSC::B3::Value::typeFor):
+ * b3/B3Value.h:
+ * b3/B3ValueInlines.h:
+ * b3/B3ValueKey.cpp:
+ (JSC::B3::ValueKey::materialize const):
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.h:
+ * b3/testb3_1.cpp:
+ (run):
+ * b3/testb3_7.cpp:
+ (testFMaxMin):
+ (testFloatMaxMin):
+ (testDoubleMaxMin):
+ * wasm/WasmAirIRGenerator.cpp:
+ (JSC::Wasm::AirIRGenerator::addFloatingPointMinOrMax):
+ (JSC::Wasm::AirIRGenerator::addOp<OpType::F32Min>):
+ * wasm/wasm.json:
+
2021-12-16 Caitlin Potter <ca...@igalia.com>
[JSC] only emit pointer validation for ARM64E
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (287159 => 287160)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -2706,6 +2706,26 @@
orDouble(op1, op2, dest);
}
+ void floatMax(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmax<32>(dest, op1, op2);
+ }
+
+ void floatMin(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmin<32>(dest, op1, op2);
+ }
+
+ void doubleMax(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmax<64>(dest, op1, op2);
+ }
+
+ void doubleMin(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmin<64>(dest, op1, op2);
+ }
+
void negateDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fneg<64>(dest, src);
Modified: trunk/Source/_javascript_Core/b3/B3Common.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Common.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Common.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -156,6 +156,26 @@
return unsignedNumerator % unsignedDenominator;
}
+template<typename FloatType>
+static FloatType fMax(FloatType a, FloatType b)
+{
+ if (std::isnan(a) || std::isnan(b))
+ return a + b;
+ if (a == static_cast<FloatType>(0.0) && b == static_cast<FloatType>(0.0) && std::signbit(a) != std::signbit(b))
+ return static_cast<FloatType>(0.0);
+ return std::max(a, b);
+}
+
+template<typename FloatType>
+static FloatType fMin(FloatType a, FloatType b)
+{
+ if (std::isnan(a) || std::isnan(b))
+ return a + b;
+ if (a == static_cast<FloatType>(0.0) && b == static_cast<FloatType>(0.0) && std::signbit(a) != std::signbit(b))
+ return static_cast<FloatType>(-0.0);
+ return std::min(a, b);
+}
+
template<typename IntType>
static IntType rotateRight(IntType value, int32_t shift)
{
Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -138,6 +138,20 @@
return proc.add<ConstDoubleValue>(origin(), fmod(m_value, other->asDouble()));
}
+Value* ConstDoubleValue::fMinConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasDouble())
+ return nullptr;
+ return proc.add<ConstDoubleValue>(origin(), fMin(m_value, other->asDouble()));
+}
+
+Value* ConstDoubleValue::fMaxConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasDouble())
+ return nullptr;
+ return proc.add<ConstDoubleValue>(origin(), fMax(m_value, other->asDouble()));
+}
+
TriState ConstDoubleValue::equalConstant(const Value* other) const
{
if (!other->hasDouble())
Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -55,6 +55,8 @@
Value* ceilConstant(Procedure&) const final;
Value* floorConstant(Procedure&) const final;
Value* sqrtConstant(Procedure&) const final;
+ Value* fMinConstant(Procedure&, const Value* other) const final;
+ Value* fMaxConstant(Procedure&, const Value* other) const final;
TriState equalConstant(const Value* other) const final;
TriState notEqualConstant(const Value* other) const final;
Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -130,6 +130,20 @@
return proc.add<ConstFloatValue>(origin(), m_value / other->asFloat());
}
+Value* ConstFloatValue::fMinConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasFloat())
+ return nullptr;
+ return proc.add<ConstFloatValue>(origin(), fMin(m_value, other->asFloat()));
+}
+
+Value* ConstFloatValue::fMaxConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasFloat())
+ return nullptr;
+ return proc.add<ConstFloatValue>(origin(), fMax(m_value, other->asFloat()));
+}
+
TriState ConstFloatValue::equalConstant(const Value* other) const
{
if (!other->hasFloat())
Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -54,6 +54,8 @@
Value* ceilConstant(Procedure&) const final;
Value* floorConstant(Procedure&) const final;
Value* sqrtConstant(Procedure&) const final;
+ Value* fMinConstant(Procedure&, const Value* other) const final;
+ Value* fMaxConstant(Procedure&, const Value* other) const final;
TriState equalConstant(const Value* other) const final;
TriState notEqualConstant(const Value* other) const final;
Modified: trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -169,6 +169,71 @@
break;
}
+ case FMax:
+ case FMin: {
+ if (isX86()) {
+ bool isMax = m_value->opcode() == FMax;
+
+ Value* a = m_value->child(0);
+ Value* b = m_value->child(1);
+
+ Value* isEqualValue = m_insertionSet.insert<Value>(
+ m_index, Equal, m_origin, a, b);
+
+ BasicBlock* before = m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
+
+ BasicBlock* isEqual = m_blockInsertionSet.insertBefore(m_block);
+ BasicBlock* notEqual = m_blockInsertionSet.insertBefore(m_block);
+ BasicBlock* isLessThan = m_blockInsertionSet.insertBefore(m_block);
+ BasicBlock* notLessThan = m_blockInsertionSet.insertBefore(m_block);
+ BasicBlock* isGreaterThan = m_blockInsertionSet.insertBefore(m_block);
+ BasicBlock* isNaN = m_blockInsertionSet.insertBefore(m_block);
+
+ before->replaceLastWithNew<Value>(m_proc, Branch, m_origin, isEqualValue);
+ before->setSuccessors(FrequentedBlock(isEqual), FrequentedBlock(notEqual));
+
+ Value* lessThanValue = notEqual->appendNew<Value>(m_proc, LessThan, m_origin, a, b);
+ notEqual->appendNew<Value>(m_proc, Branch, m_origin, lessThanValue);
+ notEqual->setSuccessors(FrequentedBlock(isLessThan), FrequentedBlock(notLessThan));
+
+ Value* greaterThanValue = notLessThan->appendNew<Value>(m_proc, GreaterThan, m_origin, a, b);
+ notLessThan->appendNew<Value>(m_proc, Branch, m_origin, greaterThanValue);
+ notLessThan->setSuccessors(FrequentedBlock(isGreaterThan), FrequentedBlock(isNaN));
+
+ UpsilonValue* isLessThanResult = isLessThan->appendNew<UpsilonValue>(
+ m_proc, m_origin, isMax ? b : a);
+ isLessThan->appendNew<Value>(m_proc, Jump, m_origin);
+ isLessThan->setSuccessors(FrequentedBlock(m_block));
+
+ UpsilonValue* isGreaterThanResult = isGreaterThan->appendNew<UpsilonValue>(
+ m_proc, m_origin, isMax ? a : b);
+ isGreaterThan->appendNew<Value>(m_proc, Jump, m_origin);
+ isGreaterThan->setSuccessors(FrequentedBlock(m_block));
+
+ UpsilonValue* isEqualResult = isEqual->appendNew<UpsilonValue>(
+ m_proc, m_origin, isEqual->appendNew<Value>(m_proc, isMax ? BitAnd : BitOr, m_origin, a, b));
+ isEqual->appendNew<Value>(m_proc, Jump, m_origin);
+ isEqual->setSuccessors(FrequentedBlock(m_block));
+
+ UpsilonValue* isNaNResult = isNaN->appendNew<UpsilonValue>(
+ m_proc, m_origin, isNaN->appendNew<Value>(m_proc, Add, m_origin, a, b));
+ isNaN->appendNew<Value>(m_proc, Jump, m_origin);
+ isNaN->setSuccessors(FrequentedBlock(m_block));
+
+ Value* phi = m_insertionSet.insert<Value>(
+ m_index, Phi, m_value->type(), m_origin);
+ isLessThanResult->setPhi(phi);
+ isGreaterThanResult->setPhi(phi);
+ isEqualResult->setPhi(phi);
+ isNaNResult->setPhi(phi);
+
+ m_value->replaceWithIdentity(phi);
+ before->updatePredecessorsAfter();
+ m_changed = true;
+ }
+ break;
+ }
+
case Div: {
if (m_value->isChill())
makeDivisionChill(Div);
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -2911,6 +2911,18 @@
return;
}
+ case FMin: {
+ RELEASE_ASSERT(isARM64());
+ append(m_value->type() == Float ? FloatMin : DoubleMin, tmp(m_value->child(0)), tmp(m_value->child(1)), tmp(m_value));
+ return;
+ }
+
+ case FMax: {
+ RELEASE_ASSERT(isARM64());
+ append(m_value->type() == Float ? FloatMax : DoubleMax, tmp(m_value->child(0)), tmp(m_value->child(1)), tmp(m_value));
+ return;
+ }
+
case BitAnd: {
Value* left = m_value->child(0);
Value* right = m_value->child(1);
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -159,6 +159,12 @@
case UMod:
out.print("UMod");
return;
+ case FMin:
+ out.print("FMin");
+ return;
+ case FMax:
+ out.print("FMax");
+ return;
case Neg:
out.print("Neg");
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Opcode.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -111,6 +111,8 @@
Ceil,
Floor,
Sqrt,
+ FMax,
+ FMin,
// Casts and such.
// Bitwise Cast of Double->Int64 or Int64->Double
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -974,7 +974,7 @@
case Mod:
// Turn this: Mod(constant1, constant2)
- // Into this: constant1 / constant2
+ // Into this: constant1 % constant2
// Note that this uses Mod<Chill> semantics.
if (replaceWithNewValue(m_value->child(0)->modConstant(m_proc, m_value->child(1))))
break;
@@ -1034,12 +1034,20 @@
case UMod:
// Turn this: UMod(constant1, constant2)
- // Into this: constant1 / constant2
+ // Into this: constant1 % constant2
replaceWithNewValue(m_value->child(0)->uModConstant(m_proc, m_value->child(1)));
// FIXME: We should do what we do for Mod since the same principle applies here.
// https://bugs.webkit.org/show_bug.cgi?id=164809
break;
+ case FMax:
+ replaceWithNewValue(m_value->child(0)->fMaxConstant(m_proc, m_value->child(1)));
+ break;
+
+ case FMin:
+ replaceWithNewValue(m_value->child(0)->fMinConstant(m_proc, m_value->child(1)));
+ break;
+
case BitAnd:
handleCommutativity();
Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Validate.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -227,6 +227,13 @@
VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
VALIDATE(value->type().isNumeric(), ("At ", *value));
break;
+ case FMax:
+ case FMin:
+ VALIDATE(value->numChildren() == 2, ("At ", *value));
+ VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
+ VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
+ VALIDATE(value->type() == Float || value->type() == Double, ("At ", *value));
+ break;
case Neg:
VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
VALIDATE(value->numChildren() == 1, ("At ", *value));
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -289,6 +289,16 @@
return nullptr;
}
+Value* Value::fMinConstant(Procedure&, const Value*) const
+{
+ return nullptr;
+}
+
+Value* Value::fMaxConstant(Procedure&, const Value*) const
+{
+ return nullptr;
+}
+
Value* Value::bitAndConstant(Procedure&, const Value*) const
{
return nullptr;
@@ -523,7 +533,7 @@
Effects Value::effects() const
{
- Effects result;
+ Effects result = Effects::none();
switch (opcode()) {
case Nop:
case Identity:
@@ -577,6 +587,8 @@
case Select:
case Depend:
case Extract:
+ case FMin:
+ case FMax:
break;
case Div:
case UDiv:
@@ -717,6 +729,8 @@
case UDiv:
case Mod:
case UMod:
+ case FMax:
+ case FMin:
case BitAnd:
case BitOr:
case BitXor:
@@ -815,6 +829,8 @@
case UDiv:
case Mod:
case UMod:
+ case FMax:
+ case FMin:
case Neg:
case BitAnd:
case BitOr:
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -218,6 +218,8 @@
virtual Value* uDivConstant(Procedure&, const Value* other) const;
virtual Value* modConstant(Procedure&, const Value* other) const; // This chooses Mod<Chill> semantics.
virtual Value* uModConstant(Procedure&, const Value* other) const;
+ virtual Value* fMinConstant(Procedure&, const Value* other) const;
+ virtual Value* fMaxConstant(Procedure&, const Value* other) const;
virtual Value* bitAndConstant(Procedure&, const Value* other) const;
virtual Value* bitOrConstant(Procedure&, const Value* other) const;
virtual Value* bitXorConstant(Procedure&, const Value* other) const;
@@ -436,6 +438,8 @@
case UDiv:
case Mod:
case UMod:
+ case FMin:
+ case FMax:
case BitAnd:
case BitOr:
case BitXor:
@@ -601,6 +605,8 @@
case UDiv:
case Mod:
case UMod:
+ case FMin:
+ case FMax:
case BitAnd:
case BitOr:
case BitXor:
Modified: trunk/Source/_javascript_Core/b3/B3ValueInlines.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ValueInlines.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ValueInlines.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -89,6 +89,8 @@
case UDiv: \
case Mod: \
case UMod: \
+ case FMax: \
+ case FMin: \
case BitAnd: \
case BitOr: \
case BitXor: \
Modified: trunk/Source/_javascript_Core/b3/B3ValueKey.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -88,6 +88,8 @@
case UDiv:
case Mod:
case UMod:
+ case FMax:
+ case FMin:
case BitAnd:
case BitOr:
case BitXor:
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-12-16 23:30:22 UTC (rev 287160)
@@ -1012,6 +1012,18 @@
arm64: OrUnsignedRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
Tmp, Tmp, Imm, Tmp
+arm64: FloatMax U:F:32, U:F:32, D:F:32
+ Tmp, Tmp, Tmp
+
+arm64: FloatMin U:F:32, U:F:32, D:F:32
+ Tmp, Tmp, Tmp
+
+arm64: DoubleMax U:F:64, U:F:64, D:F:64
+ Tmp, Tmp, Tmp
+
+arm64: DoubleMin U:F:64, U:F:64, D:F:64
+ Tmp, Tmp, Tmp
+
# The first operand is rax.
# FIXME: This formulation means that the boolean result cannot be put in eax, even though all users
# of this would be OK with that.
Modified: trunk/Source/_javascript_Core/b3/testb3.h (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/testb3.h 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/testb3.h 2021-12-16 23:30:22 UTC (rev 287160)
@@ -1173,4 +1173,7 @@
void testStorePostIndex32();
void testStorePostIndex64();
+void testFloatMaxMin();
+void testDoubleMaxMin();
+
#endif // ENABLE(B3_JIT)
Modified: trunk/Source/_javascript_Core/b3/testb3_1.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/testb3_1.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/testb3_1.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -828,6 +828,9 @@
RUN(testInfiniteLoopDoesntCauseBadHoisting());
+ RUN(testFloatMaxMin());
+ RUN(testDoubleMaxMin());
+
if (isX86()) {
RUN(testBranchBitAndImmFusion(Identity, Int64, 1, Air::BranchTest32, Air::Arg::Tmp));
RUN(testBranchBitAndImmFusion(Identity, Int64, 0xff, Air::BranchTest32, Air::Arg::Tmp));
Modified: trunk/Source/_javascript_Core/b3/testb3_7.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/b3/testb3_7.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/b3/testb3_7.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -1888,4 +1888,112 @@
RUN_BINARY(tupleNestedLoop<false>, int32Operands(), int64Operands());
}
+template <typename FloatType>
+static void testFMaxMin()
+{
+ auto checkResult = [&] (FloatType result, FloatType expected) {
+ CHECK_EQ(std::isnan(result), std::isnan(expected));
+ if (!std::isnan(expected)) {
+ CHECK_EQ(result, expected);
+ CHECK_EQ(std::signbit(result), std::signbit(expected));
+ }
+ };
+
+ auto runArgTest = [&] (bool max, FloatType arg1, FloatType arg2) {
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* a = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+ Value* b = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+ if (std::is_same_v<FloatType, float>) {
+ a = root->appendNew<Value>(proc, Trunc, Origin(), a);
+ b = root->appendNew<Value>(proc, Trunc, Origin(), b);
+ }
+ Value* result = root->appendNew<Value>(proc, max ? FMax : FMin, Origin(), a, b);
+ root->appendNewControlValue(proc, Return, Origin(), result);
+ auto code = compileProc(proc);
+ return invoke<FloatType>(*code, arg1, arg2);
+ };
+
+ auto runConstTest = [&] (bool max, FloatType arg1, FloatType arg2) {
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* a;
+ Value* b;
+ if (std::is_same_v<FloatType, float>) {
+ a = root->appendNew<ConstFloatValue>(proc, Origin(), arg1);
+ b = root->appendNew<ConstFloatValue>(proc, Origin(), arg2);
+ } else {
+ a = root->appendNew<ConstDoubleValue>(proc, Origin(), arg1);
+ b = root->appendNew<ConstDoubleValue>(proc, Origin(), arg2);
+ }
+ Value* result = root->appendNew<Value>(proc, max ? FMax : FMin, Origin(), a, b);
+ root->appendNewControlValue(proc, Return, Origin(), result);
+ auto code = compileProc(proc);
+ return invoke<FloatType>(*code, arg1, arg2);
+ };
+
+ auto runMinTest = [&] (FloatType a, FloatType b, FloatType expected) {
+ checkResult(runArgTest(false, a, b), expected);
+ checkResult(runArgTest(false, b, a), expected);
+ checkResult(runConstTest(false, a, b), expected);
+ checkResult(runConstTest(false, b, a), expected);
+ };
+
+ auto runMaxTest = [&] (FloatType a, FloatType b, FloatType expected) {
+ checkResult(runArgTest(true, a, b), expected);
+ checkResult(runConstTest(true, a, b), expected);
+ checkResult(runArgTest(true, b, a), expected);
+ checkResult(runConstTest(true, b, a), expected);
+ };
+
+ auto inf = std::numeric_limits<FloatType>::infinity();
+
+ runMinTest(10.0, 0.0, 0.0);
+ runMinTest(-10.0, 4.0, -10.0);
+ runMinTest(4.1, 4.2, 4.1);
+ runMinTest(-4.1, -4.2, -4.2);
+ runMinTest(0.0, -0.0, -0.0);
+ runMinTest(-0.0, -0.0, -0.0);
+ runMinTest(0.0, 0.0, 0.0);
+ runMinTest(-inf, 0, -inf);
+ runMinTest(-inf, inf, -inf);
+ runMinTest(inf, 42.0, 42.0);
+ if constexpr (std::is_same_v<FloatType, float>) {
+ runMinTest(0.0, std::nanf(""), std::nanf(""));
+ runMinTest(std::nanf(""), 42.0, std::nanf(""));
+ } else if constexpr (std::is_same_v<FloatType, double>) {
+ runMinTest(0.0, std::nan(""), std::nan(""));
+ runMinTest(std::nan(""), 42.0, std::nan(""));
+ }
+
+
+ runMaxTest(0.0, 10.0, 10.0);
+ runMaxTest(-10.0, 4.0, 4.0);
+ runMaxTest(4.1, 4.2, 4.2);
+ runMaxTest(-4.1, -4.2, -4.1);
+ runMaxTest(0.0, -0.0, 0.0);
+ runMaxTest(-0.0, -0.0, -0.0);
+ runMaxTest(0.0, 0.0, 0.0);
+ runMaxTest(-inf, 0, 0);
+ runMaxTest(-inf, inf, inf);
+ runMaxTest(inf, 42.0, inf);
+ if constexpr (std::is_same_v<FloatType, float>) {
+ runMaxTest(0.0, std::nanf(""), std::nanf(""));
+ runMaxTest(std::nanf(""), 42.0, std::nanf(""));
+ } else if constexpr (std::is_same_v<FloatType, double>) {
+ runMaxTest(0.0, std::nan(""), std::nan(""));
+ runMaxTest(std::nan(""), 42.0, std::nan(""));
+ }
+}
+
+void testFloatMaxMin()
+{
+ testFMaxMin<float>();
+}
+
+void testDoubleMaxMin()
+{
+ testFMaxMin<double>();
+}
+
#endif // ENABLE(B3_JIT)
Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (287159 => 287160)
--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp 2021-12-16 23:30:22 UTC (rev 287160)
@@ -4401,11 +4401,6 @@
return { };
}
-template<> auto AirIRGenerator::addOp<OpType::F32Min>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
-{
- return addFloatingPointMinOrMax(Types::F32, MinOrMax::Min, arg0, arg1, result);
-}
-
template<> auto AirIRGenerator::addOp<OpType::F64Ne>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
{
result = g32();
@@ -4425,6 +4420,14 @@
ASSERT(floatType.isF32() || floatType.isF64());
result = tmpForType(floatType);
+ if (isARM64()) {
+ if (floatType.isF32())
+ append(m_currentBlock, minOrMax == MinOrMax::Max ? FloatMax : FloatMin, arg0, arg1, result);
+ else
+ append(m_currentBlock, minOrMax == MinOrMax::Max ? DoubleMax : DoubleMin, arg0, arg1, result);
+ return { };
+ }
+
BasicBlock* isEqual = m_code.addBlock();
BasicBlock* notEqual = m_code.addBlock();
BasicBlock* isLessThan = m_code.addBlock();
@@ -4469,11 +4472,26 @@
return { };
}
+template<> auto AirIRGenerator::addOp<OpType::F32Min>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
+{
+ return addFloatingPointMinOrMax(Types::F32, MinOrMax::Min, arg0, arg1, result);
+}
+
template<> auto AirIRGenerator::addOp<OpType::F32Max>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
{
return addFloatingPointMinOrMax(Types::F32, MinOrMax::Max, arg0, arg1, result);
}
+template<> auto AirIRGenerator::addOp<OpType::F64Min>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
+{
+ return addFloatingPointMinOrMax(Types::F64, MinOrMax::Min, arg0, arg1, result);
+}
+
+template<> auto AirIRGenerator::addOp<OpType::F64Max>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
+{
+ return addFloatingPointMinOrMax(Types::F64, MinOrMax::Max, arg0, arg1, result);
+}
+
template<> auto AirIRGenerator::addOp<OpType::F64Mul>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
{
return addFloatingPointBinOp(Types::F64, MulDouble, arg0, arg1, result);
@@ -4829,11 +4847,6 @@
return addFloatingPointAbs(AbsFloat, arg0, result);
}
-template<> auto AirIRGenerator::addOp<OpType::F64Min>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
-{
- return addFloatingPointMinOrMax(Types::F64, MinOrMax::Min, arg0, arg1, result);
-}
-
template<> auto AirIRGenerator::addOp<OpType::F32Mul>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
{
result = f32();
@@ -5144,11 +5157,6 @@
return { };
}
-template<> auto AirIRGenerator::addOp<OpType::F64Max>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
-{
- return addFloatingPointMinOrMax(Types::F64, MinOrMax::Max, arg0, arg1, result);
-}
-
template<> auto AirIRGenerator::addOp<OpType::I64LeU>(ExpressionType arg0, ExpressionType arg1, ExpressionType& result) -> PartialResult
{
result = g32();
Modified: trunk/Source/_javascript_Core/wasm/wasm.json (287159 => 287160)
--- trunk/Source/_javascript_Core/wasm/wasm.json 2021-12-16 22:37:47 UTC (rev 287159)
+++ trunk/Source/_javascript_Core/wasm/wasm.json 2021-12-16 23:30:22 UTC (rev 287160)
@@ -183,8 +183,8 @@
"f32.sub": { "category": "arithmetic", "value": 147, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "Sub" },
"f32.mul": { "category": "arithmetic", "value": 148, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "Mul" },
"f32.div": { "category": "arithmetic", "value": 149, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "Div" },
- "f32.min": { "category": "arithmetic", "value": 150, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "Select(Equal(@0, @1), BitOr(@0, @1), Select(LessThan(@0, @1), @0, Select(GreaterThan(@0, @1), @1, Add(@0, @1))))" },
- "f32.max": { "category": "arithmetic", "value": 151, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "Select(Equal(@0, @1), BitAnd(@0, @1), Select(LessThan(@0, @1), @1, Select(GreaterThan(@0, @1), @0, Add(@0, @1))))" },
+ "f32.min": { "category": "arithmetic", "value": 150, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "FMin" },
+ "f32.max": { "category": "arithmetic", "value": 151, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "FMax" },
"f32.abs": { "category": "arithmetic", "value": 139, "return": ["f32"], "parameter": ["f32"], "immediate": [], "b3op": "Abs" },
"f32.neg": { "category": "arithmetic", "value": 140, "return": ["f32"], "parameter": ["f32"], "immediate": [], "b3op": "Neg" },
"f32.copysign": { "category": "arithmetic", "value": 152, "return": ["f32"], "parameter": ["f32", "f32"], "immediate": [], "b3op": "BitwiseCast(BitOr(BitAnd(BitwiseCast(@1), i32(0x80000000)), BitAnd(BitwiseCast(@0), i32(0x7fffffff))))" },
@@ -203,8 +203,8 @@
"f64.sub": { "category": "arithmetic", "value": 161, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "Sub" },
"f64.mul": { "category": "arithmetic", "value": 162, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "Mul" },
"f64.div": { "category": "arithmetic", "value": 163, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "Div" },
- "f64.min": { "category": "arithmetic", "value": 164, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "Select(Equal(@0, @1), BitOr(@0, @1), Select(LessThan(@0, @1), @0, Select(GreaterThan(@0, @1), @1, Add(@0, @1))))" },
- "f64.max": { "category": "arithmetic", "value": 165, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "Select(Equal(@0, @1), BitAnd(@0, @1), Select(LessThan(@0, @1), @1, Select(GreaterThan(@0, @1), @0, Add(@0, @1))))" },
+ "f64.min": { "category": "arithmetic", "value": 164, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "FMin" },
+ "f64.max": { "category": "arithmetic", "value": 165, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "FMax" },
"f64.abs": { "category": "arithmetic", "value": 153, "return": ["f64"], "parameter": ["f64"], "immediate": [], "b3op": "Abs" },
"f64.neg": { "category": "arithmetic", "value": 154, "return": ["f64"], "parameter": ["f64"], "immediate": [], "b3op": "Neg" },
"f64.copysign": { "category": "arithmetic", "value": 166, "return": ["f64"], "parameter": ["f64", "f64"], "immediate": [], "b3op": "BitwiseCast(BitOr(BitAnd(BitwiseCast(@1), i64(0x8000000000000000)), BitAnd(BitwiseCast(@0), i64(0x7fffffffffffffff))))" },