[JSC] Add a Modulo operator to B3, and a chill variant
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Dec 2015 00:31:51 +0000 (00:31 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Dec 2015 00:31:51 +0000 (00:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=152110

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-12-10
Reviewed by Geoffrey Garen.

It is basically refactoring the Div and ChillDiv
code to be used by both opcodes.

* b3/B3Common.h:
(JSC::B3::chillDiv):
(JSC::B3::chillMod):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::modConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::modConstant):
* b3/B3Const64Value.h:
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::modConstant):
* b3/B3ConstDoubleValue.h:
* b3/B3LowerMacros.cpp:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
(JSC::B3::Air::LowerToAir::lowerX86Div):
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3ReduceStrength.cpp:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::modConstant):
(JSC::B3::Value::effects):
(JSC::B3::Value::key):
(JSC::B3::Value::typeFor):
* b3/B3Value.h:
* b3/testb3.cpp:
(JSC::B3::testModArgDouble):
(JSC::B3::testModArgsDouble):
(JSC::B3::testModArgImmDouble):
(JSC::B3::testModImmArgDouble):
(JSC::B3::testModImmsDouble):
(JSC::B3::testModArgFloat):
(JSC::B3::testModArgsFloat):
(JSC::B3::testModArgImmFloat):
(JSC::B3::testModImmArgFloat):
(JSC::B3::testModImmsFloat):
(JSC::B3::testModArg):
(JSC::B3::testModArgs):
(JSC::B3::testModImms):
(JSC::B3::testModArg32):
(JSC::B3::testModArgs32):
(JSC::B3::testModImms32):
(JSC::B3::testChillModArg):
(JSC::B3::testChillModArgs):
(JSC::B3::testChillModImms):
(JSC::B3::testChillModArg32):
(JSC::B3::testChillModArgs32):
(JSC::B3::testChillModImms32):
(JSC::B3::run):
* ftl/FTLB3Output.h:
(JSC::FTL::Output::mod):
(JSC::FTL::Output::chillMod):
(JSC::FTL::Output::doubleMod):
(JSC::FTL::Output::rem): Deleted.
(JSC::FTL::Output::doubleRem): Deleted.
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithMod):
* ftl/FTLOutput.cpp:
(JSC::FTL::Output::chillMod):
* ftl/FTLOutput.h:
(JSC::FTL::Output::mod):
(JSC::FTL::Output::doubleMod):
(JSC::FTL::Output::rem): Deleted.
(JSC::FTL::Output::doubleRem): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@193933 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/b3/B3Common.h
Source/JavaScriptCore/b3/B3Const32Value.cpp
Source/JavaScriptCore/b3/B3Const32Value.h
Source/JavaScriptCore/b3/B3Const64Value.cpp
Source/JavaScriptCore/b3/B3Const64Value.h
Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp
Source/JavaScriptCore/b3/B3ConstDoubleValue.h
Source/JavaScriptCore/b3/B3LowerMacros.cpp
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Source/JavaScriptCore/b3/B3Opcode.cpp
Source/JavaScriptCore/b3/B3Opcode.h
Source/JavaScriptCore/b3/B3ReduceStrength.cpp
Source/JavaScriptCore/b3/B3Validate.cpp
Source/JavaScriptCore/b3/B3Value.cpp
Source/JavaScriptCore/b3/B3Value.h
Source/JavaScriptCore/b3/testb3.cpp
Source/JavaScriptCore/ftl/FTLB3Output.h
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/ftl/FTLOutput.cpp
Source/JavaScriptCore/ftl/FTLOutput.h

index 2cf6c45..e2da7de 100644 (file)
@@ -1,3 +1,80 @@
+2015-12-10  Benjamin Poulain  <bpoulain@apple.com>
+
+        [JSC] Add a Modulo operator to B3, and a chill variant
+        https://bugs.webkit.org/show_bug.cgi?id=152110
+
+        Reviewed by Geoffrey Garen.
+
+        It is basically refactoring the Div and ChillDiv
+        code to be used by both opcodes.
+
+        * b3/B3Common.h:
+        (JSC::B3::chillDiv):
+        (JSC::B3::chillMod):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::modConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::modConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3ConstDoubleValue.cpp:
+        (JSC::B3::ConstDoubleValue::modConstant):
+        * b3/B3ConstDoubleValue.h:
+        * b3/B3LowerMacros.cpp:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        (JSC::B3::Air::LowerToAir::lowerX86Div):
+        * b3/B3Opcode.cpp:
+        (WTF::printInternal):
+        * b3/B3Opcode.h:
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::modConstant):
+        (JSC::B3::Value::effects):
+        (JSC::B3::Value::key):
+        (JSC::B3::Value::typeFor):
+        * b3/B3Value.h:
+        * b3/testb3.cpp:
+        (JSC::B3::testModArgDouble):
+        (JSC::B3::testModArgsDouble):
+        (JSC::B3::testModArgImmDouble):
+        (JSC::B3::testModImmArgDouble):
+        (JSC::B3::testModImmsDouble):
+        (JSC::B3::testModArgFloat):
+        (JSC::B3::testModArgsFloat):
+        (JSC::B3::testModArgImmFloat):
+        (JSC::B3::testModImmArgFloat):
+        (JSC::B3::testModImmsFloat):
+        (JSC::B3::testModArg):
+        (JSC::B3::testModArgs):
+        (JSC::B3::testModImms):
+        (JSC::B3::testModArg32):
+        (JSC::B3::testModArgs32):
+        (JSC::B3::testModImms32):
+        (JSC::B3::testChillModArg):
+        (JSC::B3::testChillModArgs):
+        (JSC::B3::testChillModImms):
+        (JSC::B3::testChillModArg32):
+        (JSC::B3::testChillModArgs32):
+        (JSC::B3::testChillModImms32):
+        (JSC::B3::run):
+        * ftl/FTLB3Output.h:
+        (JSC::FTL::Output::mod):
+        (JSC::FTL::Output::chillMod):
+        (JSC::FTL::Output::doubleMod):
+        (JSC::FTL::Output::rem): Deleted.
+        (JSC::FTL::Output::doubleRem): Deleted.
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileArithMod):
+        * ftl/FTLOutput.cpp:
+        (JSC::FTL::Output::chillMod):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::mod):
+        (JSC::FTL::Output::doubleMod):
+        (JSC::FTL::Output::rem): Deleted.
+        (JSC::FTL::Output::doubleRem): Deleted.
+
 2015-12-10  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         [B3] Add new files to the cmake build system
index 5066d73..9e7441f 100644 (file)
@@ -94,22 +94,24 @@ inline bool isRepresentableAs(double value)
     return isRepresentableAsImpl<ResultType, double, int64_t>(value);
 }
 
-inline int32_t chillDiv(int32_t num, int32_t den)
+template<typename IntType>
+static IntType chillDiv(IntType numerator, IntType denominator)
 {
-    if (!den)
+    if (!denominator)
         return 0;
-    if (den == -1 && num == std::numeric_limits<int32_t>::min())
-        return num;
-    return num / den;
+    if (denominator == -1 && numerator == std::numeric_limits<IntType>::min())
+        return std::numeric_limits<IntType>::min();
+    return numerator / denominator;
 }
 
-inline int64_t chillDiv(int64_t num, int64_t den)
+template<typename IntType>
+static IntType chillMod(IntType numerator, IntType denominator)
 {
-    if (!den)
+    if (!denominator)
         return 0;
-    if (den == -1 && num == std::numeric_limits<int64_t>::min())
-        return num;
-    return num / den;
+    if (denominator == -1 && numerator == std::numeric_limits<IntType>::min())
+        return 0;
+    return numerator % denominator;
 }
 
 } } // namespace JSC::B3
index 4204b47..827ae90 100644 (file)
@@ -112,6 +112,13 @@ Value* Const32Value::divConstant(Procedure& proc, const Value* other) const
     return proc.add<Const32Value>(origin(), chillDiv(m_value, other->asInt32()));
 }
 
+Value* Const32Value::modConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), chillMod(m_value, other->asInt32()));
+}
+
 Value* Const32Value::bitAndConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
index 4380391..47d16f7 100644 (file)
@@ -50,6 +50,7 @@ public:
     Value* checkMulConstant(Procedure&, const Value* other) const override;
     Value* checkNegConstant(Procedure&) const override;
     Value* divConstant(Procedure&, const Value* other) const override;
+    Value* modConstant(Procedure&, const Value* other) const override;
     Value* bitAndConstant(Procedure&, const Value* other) const override;
     Value* bitOrConstant(Procedure&, const Value* other) const override;
     Value* bitXorConstant(Procedure&, const Value* other) const override;
index 9e043ee..01dcc69 100644 (file)
@@ -112,6 +112,13 @@ Value* Const64Value::divConstant(Procedure& proc, const Value* other) const
     return proc.add<Const64Value>(origin(), chillDiv(m_value, other->asInt64()));
 }
 
+Value* Const64Value::modConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasInt64())
+        return nullptr;
+    return proc.add<Const64Value>(origin(), chillMod(m_value, other->asInt64()));
+}
+
 Value* Const64Value::bitAndConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
index 81f08fd..0c63aa0 100644 (file)
@@ -50,6 +50,7 @@ public:
     Value* checkMulConstant(Procedure&, const Value* other) const override;
     Value* checkNegConstant(Procedure&) const override;
     Value* divConstant(Procedure&, const Value* other) const override;
+    Value* modConstant(Procedure&, const Value* other) const override;
     Value* bitAndConstant(Procedure&, const Value* other) const override;
     Value* bitOrConstant(Procedure&, const Value* other) const override;
     Value* bitXorConstant(Procedure&, const Value* other) const override;
index 85042cc..79088f7 100644 (file)
@@ -91,6 +91,13 @@ Value* ConstDoubleValue::divConstant(Procedure& proc, const Value* other) const
     return proc.add<ConstDoubleValue>(origin(), m_value / other->asDouble());
 }
 
+Value* ConstDoubleValue::modConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasDouble())
+        return nullptr;
+    return proc.add<ConstDoubleValue>(origin(), fmod(m_value, other->asDouble()));
+}
+
 TriState ConstDoubleValue::equalConstant(const Value* other) const
 {
     if (!other->hasDouble())
index 2bfbe34..e3b79c2 100644 (file)
@@ -45,6 +45,7 @@ public:
     Value* addConstant(Procedure&, const Value* other) const override;
     Value* subConstant(Procedure&, const Value* other) const override;
     Value* divConstant(Procedure&, const Value* other) const override;
+    Value* modConstant(Procedure&, const Value* other) const override;
     Value* mulConstant(Procedure&, const Value* other) const override;
     Value* bitwiseCastConstant(Procedure&) const override;
     Value* doubleToFloatConstant(Procedure&) const override;
index b3dc61b..0e72a4a 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "B3BasicBlockInlines.h"
 #include "B3BlockInsertionSet.h"
+#include "B3CCallValue.h"
+#include "B3ConstPtrValue.h"
 #include "B3ControlValue.h"
 #include "B3InsertionSetInlines.h"
 #include "B3PhaseScope.h"
@@ -37,6 +39,7 @@
 #include "B3SwitchValue.h"
 #include "B3UpsilonValue.h"
 #include "B3ValueInlines.h"
+#include <cmath>
 
 namespace JSC { namespace B3 {
 
@@ -72,105 +75,36 @@ private:
             m_value = m_block->at(m_index);
             m_origin = m_value->origin();
             switch (m_value->opcode()) {
-            case ChillDiv: {
-                // ARM supports this instruction natively.
-                if (isARM64())
-                    break;
-
-                m_changed = true;
-
-                // We implement "res = ChillDiv(num, den)" as follows:
-                //
-                //     if (den + 1 <=_unsigned 1) {
-                //         if (!den) {
-                //             res = 0;
-                //             goto done;
-                //         }
-                //         if (num == -2147483648) {
-                //             res = num;
-                //             goto done;
-                //         }
-                //     }
-                //     res = num / dev;
-                // done:
-
-                Value* num = m_value->child(0);
-                Value* den = m_value->child(1);
-
-                Value* one =
-                    m_insertionSet.insertIntConstant(m_index, m_value, 1);
-                Value* isDenOK = m_insertionSet.insert<Value>(
-                    m_index, Above, m_origin,
-                    m_insertionSet.insert<Value>(m_index, Add, m_origin, den, one),
-                    one);
-
-                BasicBlock* before =
-                    m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
-
-                BasicBlock* normalDivCase = m_blockInsertionSet.insertBefore(m_block);
-                BasicBlock* shadyDenCase = m_blockInsertionSet.insertBefore(m_block);
-                BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
-                BasicBlock* neg1DenCase = m_blockInsertionSet.insertBefore(m_block);
-                BasicBlock* intMinCase = m_blockInsertionSet.insertBefore(m_block);
-
-                before->replaceLastWithNew<ControlValue>(
-                    m_proc, Branch, m_origin, isDenOK,
-                    FrequentedBlock(normalDivCase, FrequencyClass::Normal),
-                    FrequentedBlock(shadyDenCase, FrequencyClass::Rare));
-
-                UpsilonValue* normalResult = normalDivCase->appendNew<UpsilonValue>(
-                    m_proc, m_origin,
-                    normalDivCase->appendNew<Value>(m_proc, Div, m_origin, num, den));
-                normalDivCase->appendNew<ControlValue>(
-                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
-
-                shadyDenCase->appendNew<ControlValue>(
-                    m_proc, Branch, m_origin, den,
-                    FrequentedBlock(neg1DenCase, FrequencyClass::Normal),
-                    FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
-
-                UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
-                    m_proc, m_origin,
-                    zeroDenCase->appendIntConstant(m_proc, m_value, 0));
-                zeroDenCase->appendNew<ControlValue>(
-                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
-
-                int64_t badNumeratorConst;
-                switch (m_value->type()) {
-                case Int32:
-                    badNumeratorConst = std::numeric_limits<int32_t>::min();
-                    break;
-                case Int64:
-                    badNumeratorConst = std::numeric_limits<int64_t>::min();
-                    break;
-                default:
-                    ASSERT_NOT_REACHED();
-                    badNumeratorConst = 0;
+            case Mod: {
+                if (m_value->type() == Double) {
+                    Value* functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, fmod);
+                    Value* result = m_insertionSet.insert<CCallValue>(m_index, Double, m_origin,
+                        Effects::none(),
+                        functionAddress,
+                        m_value->child(0),
+                        m_value->child(1));
+                    m_value->replaceWithIdentity(result);
+                } else if (m_value->type() == Float) {
+                    Value* numeratorAsDouble = m_insertionSet.insert<Value>(m_index, FloatToDouble, m_origin, m_value->child(0));
+                    Value* denominatorAsDouble = m_insertionSet.insert<Value>(m_index, FloatToDouble, m_origin, m_value->child(1));
+                    Value* functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, fmod);
+                    Value* doubleMod = m_insertionSet.insert<CCallValue>(m_index, Double, m_origin,
+                        Effects::none(),
+                        functionAddress,
+                        numeratorAsDouble,
+                        denominatorAsDouble);
+                    Value* result = m_insertionSet.insert<Value>(m_index, DoubleToFloat, m_origin, doubleMod);
+                    m_value->replaceWithIdentity(result);
                 }
+                break;
+            }
+            case ChillDiv: {
+                makeDivisionChill(Div);
+                break;
+            }
 
-                Value* badNumerator =
-                    neg1DenCase->appendIntConstant(m_proc, m_value, badNumeratorConst);
-
-                neg1DenCase->appendNew<ControlValue>(
-                    m_proc, Branch, m_origin,
-                    neg1DenCase->appendNew<Value>(
-                        m_proc, Equal, m_origin, num, badNumerator),
-                    FrequentedBlock(intMinCase, FrequencyClass::Rare),
-                    FrequentedBlock(normalDivCase, FrequencyClass::Normal));
-
-                UpsilonValue* intMinResult = intMinCase->appendNew<UpsilonValue>(
-                    m_proc, m_origin, badNumerator);
-                intMinCase->appendNew<ControlValue>(
-                    m_proc, Jump, m_origin, FrequentedBlock(m_block));
-
-                Value* phi = m_insertionSet.insert<Value>(
-                    m_index, Phi, m_value->type(), m_origin);
-                normalResult->setPhi(phi);
-                zeroResult->setPhi(phi);
-                intMinResult->setPhi(phi);
-
-                m_value->replaceWithIdentity(phi);
-                before->updatePredecessorsAfter();
+            case ChillMod: {
+                makeDivisionChill(Mod);
                 break;
             }
 
@@ -199,6 +133,108 @@ private:
         m_insertionSet.execute(m_block);
     }
 
+    void makeDivisionChill(Opcode nonChillOpcode)
+    {
+        ASSERT(nonChillOpcode == Div || nonChillOpcode == Mod);
+
+        // ARM supports this instruction natively.
+        if (isARM64())
+            return;
+
+        // We implement "res = ChillDiv/ChillMod(num, den)" as follows:
+        //
+        //     if (den + 1 <=_unsigned 1) {
+        //         if (!den) {
+        //             res = 0;
+        //             goto done;
+        //         }
+        //         if (num == -2147483648) {
+        //             res = isDiv ? num : 0;
+        //             goto done;
+        //         }
+        //     }
+        //     res = num (/ or %) dev;
+        // done:
+        m_changed = true;
+
+        Value* num = m_value->child(0);
+        Value* den = m_value->child(1);
+
+        Value* one = m_insertionSet.insertIntConstant(m_index, m_value, 1);
+        Value* isDenOK = m_insertionSet.insert<Value>(
+            m_index, Above, m_origin,
+            m_insertionSet.insert<Value>(m_index, Add, m_origin, den, one),
+            one);
+
+        BasicBlock* before = m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
+
+        BasicBlock* normalDivCase = m_blockInsertionSet.insertBefore(m_block);
+        BasicBlock* shadyDenCase = m_blockInsertionSet.insertBefore(m_block);
+        BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
+        BasicBlock* neg1DenCase = m_blockInsertionSet.insertBefore(m_block);
+        BasicBlock* intMinCase = m_blockInsertionSet.insertBefore(m_block);
+
+        before->replaceLastWithNew<ControlValue>(
+            m_proc, Branch, m_origin, isDenOK,
+            FrequentedBlock(normalDivCase, FrequencyClass::Normal),
+            FrequentedBlock(shadyDenCase, FrequencyClass::Rare));
+
+        UpsilonValue* normalResult = normalDivCase->appendNew<UpsilonValue>(
+            m_proc, m_origin,
+            normalDivCase->appendNew<Value>(m_proc, nonChillOpcode, m_origin, num, den));
+        normalDivCase->appendNew<ControlValue>(
+            m_proc, Jump, m_origin, FrequentedBlock(m_block));
+
+        shadyDenCase->appendNew<ControlValue>(
+            m_proc, Branch, m_origin, den,
+            FrequentedBlock(neg1DenCase, FrequencyClass::Normal),
+            FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
+
+        UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
+            m_proc, m_origin,
+            zeroDenCase->appendIntConstant(m_proc, m_value, 0));
+        zeroDenCase->appendNew<ControlValue>(
+            m_proc, Jump, m_origin, FrequentedBlock(m_block));
+
+        int64_t badNumeratorConst = 0;
+        switch (m_value->type()) {
+        case Int32:
+            badNumeratorConst = std::numeric_limits<int32_t>::min();
+            break;
+        case Int64:
+            badNumeratorConst = std::numeric_limits<int64_t>::min();
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            badNumeratorConst = 0;
+        }
+
+        Value* badNumerator =
+            neg1DenCase->appendIntConstant(m_proc, m_value, badNumeratorConst);
+
+        neg1DenCase->appendNew<ControlValue>(
+            m_proc, Branch, m_origin,
+            neg1DenCase->appendNew<Value>(
+                m_proc, Equal, m_origin, num, badNumerator),
+            FrequentedBlock(intMinCase, FrequencyClass::Rare),
+            FrequentedBlock(normalDivCase, FrequencyClass::Normal));
+
+        Value* intMinResult = nonChillOpcode == Div ? badNumerator : intMinCase->appendIntConstant(m_proc, m_value, 0);
+        UpsilonValue* intMinResultUpsilon = intMinCase->appendNew<UpsilonValue>(
+            m_proc, m_origin, intMinResult);
+        intMinCase->appendNew<ControlValue>(
+            m_proc, Jump, m_origin, FrequentedBlock(m_block));
+
+        Value* phi = m_insertionSet.insert<Value>(
+            m_index, Phi, m_value->type(), m_origin);
+        normalResult->setPhi(phi);
+        zeroResult->setPhi(phi);
+        intMinResultUpsilon->setPhi(phi);
+
+        m_value->replaceWithIdentity(phi);
+        before->updatePredecessorsAfter();
+    }
+
     void recursivelyBuildSwitch(
         const Vector<SwitchCase>& cases, unsigned start, bool hardStart, unsigned end,
         BasicBlock* before)
index 274dc9d..09cc9cb 100644 (file)
@@ -1441,29 +1441,8 @@ private:
 
         case Div: {
             if (isInt(m_value->type())) {
-                Tmp eax = Tmp(X86Registers::eax);
-                Tmp edx = Tmp(X86Registers::edx);
-
-                Air::Opcode convertToDoubleWord;
-                Air::Opcode div;
-                switch (m_value->type()) {
-                case Int32:
-                    convertToDoubleWord = X86ConvertToDoubleWord32;
-                    div = X86Div32;
-                    break;
-                case Int64:
-                    convertToDoubleWord = X86ConvertToQuadWord64;
-                    div = X86Div64;
-                    break;
-                default:
-                    RELEASE_ASSERT_NOT_REACHED();
-                    return;
-                }
-                
-                append(Move, tmp(m_value->child(0)), eax);
-                append(convertToDoubleWord, eax, edx);
-                append(div, eax, edx, tmp(m_value->child(1)));
-                append(Move, eax, tmp(m_value));
+                lowerX86Div();
+                append(Move, Tmp(X86Registers::eax), tmp(m_value));
                 return;
             }
             ASSERT(isFloat(m_value->type()));
@@ -1472,6 +1451,12 @@ private:
             return;
         }
 
+        case Mod: {
+            lowerX86Div();
+            append(Move, Tmp(X86Registers::edx), tmp(m_value));
+            return;
+        }
+
         case BitAnd: {
             appendBinOp<And32, And64, Commutative>(
                 m_value->child(0), m_value->child(1));
@@ -1977,6 +1962,32 @@ private:
         dataLog("FATAL: could not lower ", deepDump(m_value), "\n");
         RELEASE_ASSERT_NOT_REACHED();
     }
+
+    void lowerX86Div()
+    {
+        Tmp eax = Tmp(X86Registers::eax);
+        Tmp edx = Tmp(X86Registers::edx);
+
+        Air::Opcode convertToDoubleWord;
+        Air::Opcode div;
+        switch (m_value->type()) {
+        case Int32:
+            convertToDoubleWord = X86ConvertToDoubleWord32;
+            div = X86Div32;
+            break;
+        case Int64:
+            convertToDoubleWord = X86ConvertToQuadWord64;
+            div = X86Div64;
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+        
+        append(Move, tmp(m_value->child(0)), eax);
+        append(convertToDoubleWord, eax, edx);
+        append(div, eax, edx, tmp(m_value->child(1)));
+    }
     
     IndexSet<Value> m_locked; // These are values that will have no Tmp in Air.
     IndexMap<Value, Tmp> m_valueToTmp; // These are values that must have a Tmp in Air. We say that a Value* with a non-null Tmp is "pinned".
index da02471..bc60935 100644 (file)
@@ -116,11 +116,14 @@ void printInternal(PrintStream& out, Opcode opcode)
     case Div:
         out.print("Div");
         return;
+    case Mod:
+        out.print("Mod");
+        return;
     case ChillDiv:
         out.print("ChillDiv");
         return;
-    case Mod:
-        out.print("Mod");
+    case ChillMod:
+        out.print("ChillMod");
         return;
     case BitAnd:
         out.print("BitAnd");
index 2c8f2e5..14aec4a 100644 (file)
@@ -71,10 +71,11 @@ enum Opcode : int16_t {
     Sub,
     Mul,
     Div, // All bets are off as to what will happen when you execute this for -2^31/-1 and x/0.
+    Mod, // All bets are off as to what will happen when you execute this for -2^31%-1 and x%0.
 
     // Integer math.
     ChillDiv, // doesn't trap ever, behaves like JS (x/y)|0.
-    Mod,
+    ChillMod, // doesn't trap ever, behaves like JS (x%y)|0.
     BitAnd,
     BitOr,
     BitXor,
index b82e091..873eb00 100644 (file)
@@ -291,6 +291,11 @@ private:
             replaceWithNewValue(m_value->child(0)->divConstant(m_proc, m_value->child(1)));
             break;
 
+        case Mod:
+        case ChillMod:
+            replaceWithNewValue(m_value->child(0)->modConstant(m_proc, m_value->child(1)));
+            break;
+
         case BitAnd:
             handleCommutativity();
 
@@ -658,7 +663,7 @@ private:
             }
 
             // Turn this: Load(constant1, offset = constant2)
-            // Into this: Laod(constant1 + constant2)
+            // Into this: Load(constant1 + constant2)
             //
             // This is a fun canonicalization. It purely regresses naively generated code. We rely
             // on constant materialization to be smart enough to materialize this constant the smart
@@ -677,6 +682,18 @@ private:
             break;
         }
 
+        case CCall:
+            // Turn this: Call(fmod, constant1, constant2)
+            // Into this: fcall-constant(constant1, constant2)
+            if (m_value->type() == Double
+                && m_value->numChildren() == 3
+                && m_value->child(0)->isIntPtr(reinterpret_cast<intptr_t>(fmod))
+                && m_value->child(1)->type() == Double
+                && m_value->child(2)->type() == Double) {
+                replaceWithNewValue(m_value->child(1)->modConstant(m_proc, m_value->child(2)));
+            }
+            break;
+
         case Equal:
             handleCommutativity();
 
index 7587443..e00963c 100644 (file)
@@ -153,13 +153,14 @@ public:
             case Sub:
             case Mul:
             case Div:
+            case Mod:
                 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() != Void, ("At ", *value));
                 break;
             case ChillDiv:
-            case Mod:
+            case ChillMod:
             case BitAnd:
             case BitOr:
             case BitXor:
index c042767..67cb226 100644 (file)
@@ -164,6 +164,11 @@ Value* Value::divConstant(Procedure&, const Value*) const
     return nullptr;
 }
 
+Value* Value::modConstant(Procedure&, const Value*) const
+{
+    return nullptr;
+}
+
 Value* Value::bitAndConstant(Procedure&, const Value*) const
 {
     return nullptr;
@@ -337,7 +342,7 @@ Effects Value::effects() const
     case Sub:
     case Mul:
     case ChillDiv:
-    case Mod:
+    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
@@ -369,6 +374,7 @@ Effects Value::effects() const
     case Select:
         break;
     case Div:
+    case Mod:
         result.controlDependent = true;
         break;
     case Load8Z:
@@ -436,8 +442,10 @@ ValueKey Value::key() const
     case Add:
     case Sub:
     case Mul:
-    case ChillDiv:
+    case Div:
     case Mod:
+    case ChillDiv:
+    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
@@ -452,7 +460,6 @@ ValueKey Value::key() const
     case Below:
     case AboveEqual:
     case BelowEqual:
-    case Div:
     case CheckAdd:
     case CheckSub:
     case CheckMul:
@@ -514,8 +521,9 @@ Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
     case Sub:
     case Mul:
     case Div:
-    case ChillDiv:
     case Mod:
+    case ChillDiv:
+    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
index 91e49d1..ed2d10d 100644 (file)
@@ -121,6 +121,7 @@ public:
     virtual Value* checkMulConstant(Procedure&, const Value* other) const;
     virtual Value* checkNegConstant(Procedure&) const;
     virtual Value* divConstant(Procedure&, const Value* other) const; // This chooses ChillDiv semantics for integers.
+    virtual Value* modConstant(Procedure&, const Value* other) const; // This chooses ChillMod semantics for integers.
     virtual Value* bitAndConstant(Procedure&, const Value* other) const;
     virtual Value* bitOrConstant(Procedure&, const Value* other) const;
     virtual Value* bitXorConstant(Procedure&, const Value* other) const;
index d7f2d05..0604bb0 100644 (file)
@@ -1027,6 +1027,145 @@ void testDivImmsFloat(float a, float b)
     CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a / b)));
 }
 
+void testModArgDouble(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Mod, Origin(), value, value));
+
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, a)));
+}
+
+void testModArgsDouble(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
+
+    CHECK(isIdentical(compileAndRun<double>(proc, a, b), fmod(a, b)));
+}
+
+void testModArgImmDouble(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
+
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, b)));
+}
+
+void testModImmArgDouble(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
+
+    CHECK(isIdentical(compileAndRun<double>(proc, b), fmod(a, b)));
+}
+
+void testModImmsDouble(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
+
+    CHECK(isIdentical(compileAndRun<double>(proc), fmod(a, b)));
+}
+
+void testModArgFloat(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, a)))));
+}
+
+void testModArgsFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
+void testModArgImmFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
+void testModImmArgFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
+void testModImmsFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
 void testDivArgFloatWithUselessDoubleConversion(float a)
 {
     Procedure proc;
@@ -6300,6 +6439,190 @@ void testChillDiv64(int64_t num, int64_t den, int64_t res)
     }
 }
 
+void testModArg(int64_t value)
+{
+    if (!value)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(!compileAndRun<int64_t>(proc, value));
+}
+
+void testModArgs(int64_t numerator, int64_t denominator)
+{
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
+}
+
+void testModImms(int64_t numerator, int64_t denominator)
+{
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
+}
+
+void testModArg32(int32_t value)
+{
+    if (!value)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(!compileAndRun<int32_t>(proc, value));
+}
+
+void testModArgs32(int32_t numerator, int32_t denominator)
+{
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
+}
+
+void testModImms32(int32_t numerator, int32_t denominator)
+{
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
+}
+
+void testChillModArg(int64_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(!compileAndRun<int64_t>(proc, value));
+}
+
+void testChillModArgs(int64_t numerator, int64_t denominator)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+}
+
+void testChillModImms(int64_t numerator, int64_t denominator)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+}
+
+void testChillModArg32(int32_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(!compileAndRun<int32_t>(proc, value));
+}
+
+void testChillModArgs32(int32_t numerator, int32_t denominator)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+}
+
+void testChillModImms32(int32_t numerator, int32_t denominator)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+}
+
 void testSwitch(unsigned degree, unsigned gap = 1)
 {
     Procedure proc;
@@ -7059,6 +7382,17 @@ void run(const char* filter)
     RUN_BINARY(testDivArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_BINARY(testDivArgsFloatWithEffectfulDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>());
 
+    RUN_UNARY(testModArgDouble, floatingPointOperands<double>());
+    RUN_BINARY(testModArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
+    RUN_BINARY(testModArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
+    RUN_BINARY(testModImmArgDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
+    RUN_BINARY(testModImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
+    RUN_UNARY(testModArgFloat, floatingPointOperands<float>());
+    RUN_BINARY(testModArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
+    RUN_BINARY(testModArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
+    RUN_BINARY(testModImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
+    RUN_BINARY(testModImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
+
     RUN(testSubArg(24));
     RUN(testSubArgs(1, 1));
     RUN(testSubArgs(1, 2));
@@ -7633,6 +7967,19 @@ void run(const char* filter)
     RUN(testChillDivTwice(4, 0, 6, 2, 3));
     RUN(testChillDivTwice(4, 2, 6, 0, 2));
 
+    RUN_UNARY(testModArg, int64Operands());
+    RUN_BINARY(testModArgs, int64Operands(), int64Operands());
+    RUN_BINARY(testModImms, int64Operands(), int64Operands());
+    RUN_UNARY(testModArg32, int32Operands());
+    RUN_BINARY(testModArgs32, int32Operands(), int32Operands());
+    RUN_BINARY(testModImms32, int32Operands(), int32Operands());
+    RUN_UNARY(testChillModArg, int64Operands());
+    RUN_BINARY(testChillModArgs, int64Operands(), int64Operands());
+    RUN_BINARY(testChillModImms, int64Operands(), int64Operands());
+    RUN_UNARY(testChillModArg32, int32Operands());
+    RUN_BINARY(testChillModArgs32, int32Operands(), int32Operands());
+    RUN_BINARY(testChillModImms32, int32Operands(), int32Operands());
+
     RUN(testSwitch(0, 1));
     RUN(testSwitch(1, 1));
     RUN(testSwitch(2, 1));
index 5b09e72..f7eee52 100644 (file)
@@ -128,7 +128,8 @@ public:
     LValue mul(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Mul, origin(), left, right); }
     LValue div(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Div, origin(), left, right); }
     LValue chillDiv(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::ChillDiv, origin(), left, right); }
-    LValue rem(LValue left, LValue right) { CRASH(); }
+    LValue mod(LValue left, LValue right) { m_block->appendNew<B3::Value>(m_proc, B3::Mod, origin(), left, right); }
+    LValue chillMod(LValue left, LValue right) { m_block->appendNew<B3::Value>(m_proc, B3::ChillMod, origin(), left, right); }
     LValue neg(LValue value)
     {
         LValue zero = m_block->appendIntConstant(m_proc, origin(), value->type(), 0);
@@ -139,7 +140,7 @@ public:
     LValue doubleSub(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Sub, origin(), left, right); }
     LValue doubleMul(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Mul, origin(), left, right); }
     LValue doubleDiv(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Div, origin(), left, right); }
-    LValue doubleRem(LValue left, LValue right) { return callWithoutSideEffects(B3::Double, fmod, left, right); }
+    LValue doubleMod(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::Mod, origin(), left, right); }
     LValue doubleNeg(LValue value)
     {
         return sub(doubleZero, value);
index deb637c..ee35d2f 100644 (file)
@@ -2025,89 +2025,53 @@ private:
         case Int32Use: {
             LValue numerator = lowInt32(m_node->child1());
             LValue denominator = lowInt32(m_node->child2());
-            
-            LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
-            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
-            LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
-            
-            Vector<ValueFromBlock, 3> results;
-            
-            LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
-            
-            m_out.branch(
-                m_out.above(adjustedDenominator, m_out.int32One),
-                usually(continuation), rarely(unsafeDenominator));
-            
-            LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
-            
-            LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
-            
-            // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
-            // separate case for that. But it probably doesn't matter so much.
+
+            LValue remainder;
             if (shouldCheckOverflow(m_node->arithMode())) {
+                LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
+                LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
+
+                LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
+                m_out.branch(
+                    m_out.above(adjustedDenominator, m_out.int32One),
+                    usually(continuation), rarely(unsafeDenominator));
+
+                LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
+                LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
                 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
                 speculate(Overflow, noValue(), 0, cond);
                 m_out.jump(continuation);
-            } else {
-                // This is the case where we convert the result to an int after we're done. So,
-                // if the denominator is zero, then the result should be result should be zero.
-                // If the denominator is not zero (i.e. it's -1 because we're guarded by the
-                // check above) and the numerator is -2^31 then the result should be -2^31.
-                
-                LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
-                LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
-                LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
-                
-                m_out.branch(
-                    m_out.isZero32(denominator), rarely(modByZero), usually(notModByZero));
-                
-                m_out.appendTo(modByZero, notModByZero);
-                results.append(m_out.anchor(m_out.int32Zero));
-                m_out.jump(done);
-                
-                m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
-                m_out.branch(
-                    m_out.equal(numerator, neg2ToThe31),
-                    rarely(neg2ToThe31ByNeg1), usually(continuation));
-                
-                m_out.appendTo(neg2ToThe31ByNeg1, continuation);
-                results.append(m_out.anchor(m_out.int32Zero));
-                m_out.jump(done);
-            }
-            
-            m_out.appendTo(continuation, done);
-            
-            LValue remainder = m_out.rem(numerator, denominator);
-            
+
+                m_out.appendTo(continuation, lastNext);
+                LValue result = m_out.mod(numerator, denominator);
+                remainder = result;
+            } else
+                remainder = m_out.chillMod(numerator, denominator);
+
             if (shouldCheckNegativeZero(m_node->arithMode())) {
                 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
                 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
-                
+
                 m_out.branch(
                     m_out.lessThan(numerator, m_out.int32Zero),
                     unsure(negativeNumerator), unsure(numeratorContinuation));
-                
+
                 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
-                
+
                 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
-                
+
                 m_out.jump(numeratorContinuation);
-                
+
                 m_out.appendTo(numeratorContinuation, innerLastNext);
             }
-            
-            results.append(m_out.anchor(remainder));
-            m_out.jump(done);
-            
-            m_out.appendTo(done, lastNext);
-            
-            setInt32(m_out.phi(m_out.int32, results));
+
+            setInt32(remainder);
             break;
         }
             
         case DoubleRepUse: {
             setDouble(
-                m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+                m_out.doubleMod(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
             break;
         }
             
index b921026..aa025ae 100644 (file)
@@ -116,6 +116,47 @@ LValue Output::chillDiv(LValue numerator, LValue denominator)
     return phi(int32, results);
 }
 
+LValue Output::chillMod(LValue numerator, LValue denominator)
+{
+    LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(*this, ("ChillMod unsafe denominator"));
+    LBasicBlock continuation = FTL_NEW_BLOCK(*this, ("ChillMod continuation"));
+    LBasicBlock done = FTL_NEW_BLOCK(*this, ("ChillMod done"));
+    LBasicBlock divByZero = FTL_NEW_BLOCK(*this, ("ChillMod divide by zero"));
+    LBasicBlock notDivByZero = FTL_NEW_BLOCK(*this, ("ChillMod not divide by zero"));
+    LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(*this, ("ChillMod -2^31/-1"));
+
+    LValue adjustedDenominator = add(denominator, int32One);
+    branch(
+        above(adjustedDenominator, int32One),
+        usually(continuation), rarely(unsafeDenominator));
+
+    Vector<ValueFromBlock, 3> results;
+    LBasicBlock lastNext = appendTo(unsafeDenominator, continuation);
+
+    LValue neg2ToThe31 = constInt32(-2147483647-1);
+    branch(isZero32(denominator), rarely(divByZero), usually(notDivByZero));
+
+    appendTo(divByZero, notDivByZero);
+    results.append(anchor(int32Zero));
+    jump(done);
+
+    appendTo(notDivByZero, neg2ToThe31ByNeg1);
+    branch(equal(numerator, neg2ToThe31),
+        rarely(neg2ToThe31ByNeg1), usually(continuation));
+
+    appendTo(neg2ToThe31ByNeg1, continuation);
+    results.append(anchor(int32Zero));
+    jump(done);
+
+    appendTo(continuation, done);
+    LValue result = mod(numerator, denominator);
+    results.append(anchor(result));
+    jump(done);
+
+    appendTo(done, lastNext);
+    return phi(int32, results);
+}
+
 LValue Output::sensibleDoubleToInt(LValue value)
 {
     RELEASE_ASSERT(isX86());
index bd59ab6..448189b 100644 (file)
@@ -126,14 +126,15 @@ public:
     LValue mul(LValue left, LValue right) { return buildMul(m_builder, left, right); }
     LValue div(LValue left, LValue right) { return buildDiv(m_builder, left, right); }
     LValue chillDiv(LValue left, LValue right);
-    LValue rem(LValue left, LValue right) { return buildRem(m_builder, left, right); }
+    LValue mod(LValue left, LValue right) { return buildRem(m_builder, left, right); }
+    LValue chillMod(LValue left, LValue right);
     LValue neg(LValue value) { return buildNeg(m_builder, value); }
 
     LValue doubleAdd(LValue left, LValue right) { return buildFAdd(m_builder, left, right); }
     LValue doubleSub(LValue left, LValue right) { return buildFSub(m_builder, left, right); }
     LValue doubleMul(LValue left, LValue right) { return buildFMul(m_builder, left, right); }
     LValue doubleDiv(LValue left, LValue right) { return buildFDiv(m_builder, left, right); }
-    LValue doubleRem(LValue left, LValue right) { return buildFRem(m_builder, left, right); }
+    LValue doubleMod(LValue left, LValue right) { return buildFRem(m_builder, left, right); }
     LValue doubleNeg(LValue value) { return buildFNeg(m_builder, value); }
 
     LValue bitAnd(LValue left, LValue right) { return buildAnd(m_builder, left, right); }