Title: [287160] trunk/Source/_javascript_Core
Revision
287160
Author
sbar...@apple.com
Date
2021-12-16 15:30:22 -0800 (Thu, 16 Dec 2021)

Log Message

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:

Modified Paths

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))))" },
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to