Changeset 192072 in webkit


Ignore:
Timestamp:
Nov 5, 2015 1:51:05 PM (8 years ago)
Author:
fpizlo@apple.com
Message:

B3->Air lowering should have a story for compare-branch fusion
https://bugs.webkit.org/show_bug.cgi?id=150721

Reviewed by Geoffrey Garen.

This adds comprehensive support for compares and compare/branch fusion to B3. The fusion is
super aggressive. It can even handle things like Branch(LessThan(Load8S(...), constant)). It
can even handle flipping the operands to the branch, and flipping the comparison condition,
if it enables a more efficient instruction. This happens when there is asymmetry in the
admitted argument kinds. For example, Branch32 will only accept an Imm as a second operand.
If we do a LessThan(constant, load) then we will generate it as:

Branch32 GreaterThan, (addr), $imm

This also supports compiling and fusing tests, and to some extent, compiling and fusing
double compares. Though we cannot test doubles yet because we don't have enough support for
that.

This also supports fusing compare/branches in Checks. We basically get that for free.

Because I wanted to fuse comparisons with sub-32-bit loads, I added support for those loads
directly, too.

The tests are now getting super big, so I made testb3 run tests in parallel.

Finally, this slightly changes the semantics of Branch and Check. Previously they would have
accepted a double to branch on. I found that this is awkward. It's especially awkward since
we want to be explicit about when a double zero constant is materialized. So, from now on, we
require that to branch on a double being non-zero, you have to do Branch(NotEqual(value, 0)).

  • assembler/MacroAssembler.h:

(JSC::MacroAssembler::invert):
(JSC::MacroAssembler::isInvertible):
(JSC::MacroAssembler::flip):
(JSC::MacroAssembler::isSigned):
(JSC::MacroAssembler::isUnsigned):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::test32):
(JSC::MacroAssemblerX86Common::invert):

  • b3/B3CheckSpecial.cpp:

(JSC::B3::CheckSpecial::Key::Key):
(JSC::B3::CheckSpecial::Key::dump):
(JSC::B3::CheckSpecial::CheckSpecial):
(JSC::B3::CheckSpecial::~CheckSpecial):

  • b3/B3CheckSpecial.h:

(JSC::B3::CheckSpecial::Key::Key):
(JSC::B3::CheckSpecial::Key::operator==):
(JSC::B3::CheckSpecial::Key::operator!=):
(JSC::B3::CheckSpecial::Key::operator bool):
(JSC::B3::CheckSpecial::Key::opcode):
(JSC::B3::CheckSpecial::Key::numArgs):
(JSC::B3::CheckSpecial::Key::isHashTableDeletedValue):
(JSC::B3::CheckSpecial::Key::hash):
(JSC::B3::CheckSpecialKeyHash::hash):
(JSC::B3::CheckSpecialKeyHash::equal):

  • b3/B3Const32Value.cpp:

(JSC::B3::Const32Value::zShrConstant):
(JSC::B3::Const32Value::equalConstant):
(JSC::B3::Const32Value::notEqualConstant):
(JSC::B3::Const32Value::lessThanConstant):
(JSC::B3::Const32Value::greaterThanConstant):
(JSC::B3::Const32Value::lessEqualConstant):
(JSC::B3::Const32Value::greaterEqualConstant):
(JSC::B3::Const32Value::aboveConstant):
(JSC::B3::Const32Value::belowConstant):
(JSC::B3::Const32Value::aboveEqualConstant):
(JSC::B3::Const32Value::belowEqualConstant):
(JSC::B3::Const32Value::dumpMeta):

  • b3/B3Const32Value.h:
  • b3/B3Const64Value.cpp:

(JSC::B3::Const64Value::zShrConstant):
(JSC::B3::Const64Value::equalConstant):
(JSC::B3::Const64Value::notEqualConstant):
(JSC::B3::Const64Value::lessThanConstant):
(JSC::B3::Const64Value::greaterThanConstant):
(JSC::B3::Const64Value::lessEqualConstant):
(JSC::B3::Const64Value::greaterEqualConstant):
(JSC::B3::Const64Value::aboveConstant):
(JSC::B3::Const64Value::belowConstant):
(JSC::B3::Const64Value::aboveEqualConstant):
(JSC::B3::Const64Value::belowEqualConstant):
(JSC::B3::Const64Value::dumpMeta):

  • b3/B3Const64Value.h:
  • b3/B3ConstDoubleValue.cpp:

(JSC::B3::ConstDoubleValue::subConstant):
(JSC::B3::ConstDoubleValue::equalConstant):
(JSC::B3::ConstDoubleValue::notEqualConstant):
(JSC::B3::ConstDoubleValue::lessThanConstant):
(JSC::B3::ConstDoubleValue::greaterThanConstant):
(JSC::B3::ConstDoubleValue::lessEqualConstant):
(JSC::B3::ConstDoubleValue::greaterEqualConstant):
(JSC::B3::ConstDoubleValue::dumpMeta):

  • b3/B3ConstDoubleValue.h:
  • b3/B3LowerToAir.cpp:

(JSC::B3::Air::LowerToAir::LowerToAir):
(JSC::B3::Air::LowerToAir::run):
(JSC::B3::Air::LowerToAir::shouldCopyPropagate):
(JSC::B3::Air::LowerToAir::ArgPromise::ArgPromise):
(JSC::B3::Air::LowerToAir::ArgPromise::tmp):
(JSC::B3::Air::LowerToAir::ArgPromise::operator bool):
(JSC::B3::Air::LowerToAir::ArgPromise::kind):
(JSC::B3::Air::LowerToAir::ArgPromise::peek):
(JSC::B3::Air::LowerToAir::ArgPromise::consume):
(JSC::B3::Air::LowerToAir::tmp):
(JSC::B3::Air::LowerToAir::tmpPromise):
(JSC::B3::Air::LowerToAir::canBeInternal):
(JSC::B3::Air::LowerToAir::addr):
(JSC::B3::Air::LowerToAir::loadPromise):
(JSC::B3::Air::LowerToAir::imm):
(JSC::B3::Air::LowerToAir::appendBinOp):
(JSC::B3::Air::LowerToAir::tryAppendStoreUnOp):
(JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
(JSC::B3::Air::LowerToAir::createGenericCompare):
(JSC::B3::Air::LowerToAir::createBranch):
(JSC::B3::Air::LowerToAir::createCompare):
(JSC::B3::Air::LowerToAir::tryLoad):
(JSC::B3::Air::LowerToAir::tryLoad8S):
(JSC::B3::Air::LowerToAir::tryLoad8Z):
(JSC::B3::Air::LowerToAir::tryLoad16S):
(JSC::B3::Air::LowerToAir::tryLoad16Z):
(JSC::B3::Air::LowerToAir::tryAdd):
(JSC::B3::Air::LowerToAir::tryStackSlot):
(JSC::B3::Air::LowerToAir::tryEqual):
(JSC::B3::Air::LowerToAir::tryNotEqual):
(JSC::B3::Air::LowerToAir::tryLessThan):
(JSC::B3::Air::LowerToAir::tryGreaterThan):
(JSC::B3::Air::LowerToAir::tryLessEqual):
(JSC::B3::Air::LowerToAir::tryGreaterEqual):
(JSC::B3::Air::LowerToAir::tryAbove):
(JSC::B3::Air::LowerToAir::tryBelow):
(JSC::B3::Air::LowerToAir::tryAboveEqual):
(JSC::B3::Air::LowerToAir::tryBelowEqual):
(JSC::B3::Air::LowerToAir::tryPatchpoint):
(JSC::B3::Air::LowerToAir::tryCheck):
(JSC::B3::Air::LowerToAir::tryBranch):
(JSC::B3::Air::LowerToAir::loadAddr): Deleted.

  • b3/B3LoweringMatcher.patterns:
  • b3/B3Opcode.cpp:

(JSC::B3::invertedCompare):

  • b3/B3Opcode.h:

(JSC::B3::isCheckMath):

  • b3/B3Procedure.cpp:

(JSC::B3::Procedure::addBlock):
(JSC::B3::Procedure::addIntConstant):
(JSC::B3::Procedure::addBoolConstant):
(JSC::B3::Procedure::resetValueOwners):

  • b3/B3Procedure.h:
  • b3/B3ReduceStrength.cpp:
  • b3/B3Validate.cpp:
  • b3/B3Value.cpp:

(JSC::B3::Value::zShrConstant):
(JSC::B3::Value::equalConstant):
(JSC::B3::Value::notEqualConstant):
(JSC::B3::Value::lessThanConstant):
(JSC::B3::Value::greaterThanConstant):
(JSC::B3::Value::lessEqualConstant):
(JSC::B3::Value::greaterEqualConstant):
(JSC::B3::Value::aboveConstant):
(JSC::B3::Value::belowConstant):
(JSC::B3::Value::aboveEqualConstant):
(JSC::B3::Value::belowEqualConstant):
(JSC::B3::Value::invertedCompare):

  • b3/B3Value.h:
  • b3/air/AirArg.cpp:

(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::dump):
(WTF::printInternal):

  • b3/air/AirArg.h:

(JSC::B3::Air::Arg::isUse):
(JSC::B3::Air::Arg::typeForB3Type):
(JSC::B3::Air::Arg::widthForB3Type):
(JSC::B3::Air::Arg::Arg):
(JSC::B3::Air::Arg::value):
(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::asNumber):
(JSC::B3::Air::Arg::pointerValue):
(JSC::B3::Air::Arg::asDoubleCondition):
(JSC::B3::Air::Arg::inverted):
(JSC::B3::Air::Arg::flipped):
(JSC::B3::Air::Arg::isSignedCond):
(JSC::B3::Air::Arg::isUnsignedCond):

  • b3/air/AirInst.h:

(JSC::B3::Air::Inst::Inst):
(JSC::B3::Air::Inst::operator bool):

  • b3/air/AirOpcode.opcodes:
  • b3/air/opcode_generator.rb:
  • b3/testb3.cpp:

(hiddenTruthBecauseNoReturnIsStupid):
(JSC::B3::testStoreLoadStackSlot):
(JSC::B3::modelLoad):
(JSC::B3::testLoad):
(JSC::B3::testBranch):
(JSC::B3::testComplex):
(JSC::B3::testSimplePatchpoint):
(JSC::B3::testSimpleCheck):
(JSC::B3::genericTestCompare):
(JSC::B3::modelCompare):
(JSC::B3::testCompareLoad):
(JSC::B3::testCompareImpl):
(JSC::B3::testCompare):
(JSC::B3::run):
(main):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithMod):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitIntTypedArrayGetByVal):
(JSC::JIT::emitIntTypedArrayPutByVal):

Location:
trunk/Source/JavaScriptCore
Files:
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r192064 r192072  
     12015-11-05  Filip Pizlo  <fpizlo@apple.com>
     2
     3        B3->Air lowering should have a story for compare-branch fusion
     4        https://bugs.webkit.org/show_bug.cgi?id=150721
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This adds comprehensive support for compares and compare/branch fusion to B3. The fusion is
     9        super aggressive. It can even handle things like Branch(LessThan(Load8S(...), constant)). It
     10        can even handle flipping the operands to the branch, and flipping the comparison condition,
     11        if it enables a more efficient instruction. This happens when there is asymmetry in the
     12        admitted argument kinds. For example, Branch32 will only accept an Imm as a second operand.
     13        If we do a LessThan(constant, load) then we will generate it as:
     14
     15            Branch32 GreaterThan, (addr), $imm
     16
     17        This also supports compiling and fusing tests, and to some extent, compiling and fusing
     18        double compares. Though we cannot test doubles yet because we don't have enough support for
     19        that.
     20
     21        This also supports fusing compare/branches in Checks. We basically get that for free.
     22
     23        Because I wanted to fuse comparisons with sub-32-bit loads, I added support for those loads
     24        directly, too.
     25
     26        The tests are now getting super big, so I made testb3 run tests in parallel.
     27
     28        Finally, this slightly changes the semantics of Branch and Check. Previously they would have
     29        accepted a double to branch on. I found that this is awkward. It's especially awkward since
     30        we want to be explicit about when a double zero constant is materialized. So, from now on, we
     31        require that to branch on a double being non-zero, you have to do Branch(NotEqual(value, 0)).
     32
     33        * assembler/MacroAssembler.h:
     34        (JSC::MacroAssembler::invert):
     35        (JSC::MacroAssembler::isInvertible):
     36        (JSC::MacroAssembler::flip):
     37        (JSC::MacroAssembler::isSigned):
     38        (JSC::MacroAssembler::isUnsigned):
     39        * assembler/MacroAssemblerX86Common.h:
     40        (JSC::MacroAssemblerX86Common::test32):
     41        (JSC::MacroAssemblerX86Common::invert):
     42        * b3/B3CheckSpecial.cpp:
     43        (JSC::B3::CheckSpecial::Key::Key):
     44        (JSC::B3::CheckSpecial::Key::dump):
     45        (JSC::B3::CheckSpecial::CheckSpecial):
     46        (JSC::B3::CheckSpecial::~CheckSpecial):
     47        * b3/B3CheckSpecial.h:
     48        (JSC::B3::CheckSpecial::Key::Key):
     49        (JSC::B3::CheckSpecial::Key::operator==):
     50        (JSC::B3::CheckSpecial::Key::operator!=):
     51        (JSC::B3::CheckSpecial::Key::operator bool):
     52        (JSC::B3::CheckSpecial::Key::opcode):
     53        (JSC::B3::CheckSpecial::Key::numArgs):
     54        (JSC::B3::CheckSpecial::Key::isHashTableDeletedValue):
     55        (JSC::B3::CheckSpecial::Key::hash):
     56        (JSC::B3::CheckSpecialKeyHash::hash):
     57        (JSC::B3::CheckSpecialKeyHash::equal):
     58        * b3/B3Const32Value.cpp:
     59        (JSC::B3::Const32Value::zShrConstant):
     60        (JSC::B3::Const32Value::equalConstant):
     61        (JSC::B3::Const32Value::notEqualConstant):
     62        (JSC::B3::Const32Value::lessThanConstant):
     63        (JSC::B3::Const32Value::greaterThanConstant):
     64        (JSC::B3::Const32Value::lessEqualConstant):
     65        (JSC::B3::Const32Value::greaterEqualConstant):
     66        (JSC::B3::Const32Value::aboveConstant):
     67        (JSC::B3::Const32Value::belowConstant):
     68        (JSC::B3::Const32Value::aboveEqualConstant):
     69        (JSC::B3::Const32Value::belowEqualConstant):
     70        (JSC::B3::Const32Value::dumpMeta):
     71        * b3/B3Const32Value.h:
     72        * b3/B3Const64Value.cpp:
     73        (JSC::B3::Const64Value::zShrConstant):
     74        (JSC::B3::Const64Value::equalConstant):
     75        (JSC::B3::Const64Value::notEqualConstant):
     76        (JSC::B3::Const64Value::lessThanConstant):
     77        (JSC::B3::Const64Value::greaterThanConstant):
     78        (JSC::B3::Const64Value::lessEqualConstant):
     79        (JSC::B3::Const64Value::greaterEqualConstant):
     80        (JSC::B3::Const64Value::aboveConstant):
     81        (JSC::B3::Const64Value::belowConstant):
     82        (JSC::B3::Const64Value::aboveEqualConstant):
     83        (JSC::B3::Const64Value::belowEqualConstant):
     84        (JSC::B3::Const64Value::dumpMeta):
     85        * b3/B3Const64Value.h:
     86        * b3/B3ConstDoubleValue.cpp:
     87        (JSC::B3::ConstDoubleValue::subConstant):
     88        (JSC::B3::ConstDoubleValue::equalConstant):
     89        (JSC::B3::ConstDoubleValue::notEqualConstant):
     90        (JSC::B3::ConstDoubleValue::lessThanConstant):
     91        (JSC::B3::ConstDoubleValue::greaterThanConstant):
     92        (JSC::B3::ConstDoubleValue::lessEqualConstant):
     93        (JSC::B3::ConstDoubleValue::greaterEqualConstant):
     94        (JSC::B3::ConstDoubleValue::dumpMeta):
     95        * b3/B3ConstDoubleValue.h:
     96        * b3/B3LowerToAir.cpp:
     97        (JSC::B3::Air::LowerToAir::LowerToAir):
     98        (JSC::B3::Air::LowerToAir::run):
     99        (JSC::B3::Air::LowerToAir::shouldCopyPropagate):
     100        (JSC::B3::Air::LowerToAir::ArgPromise::ArgPromise):
     101        (JSC::B3::Air::LowerToAir::ArgPromise::tmp):
     102        (JSC::B3::Air::LowerToAir::ArgPromise::operator bool):
     103        (JSC::B3::Air::LowerToAir::ArgPromise::kind):
     104        (JSC::B3::Air::LowerToAir::ArgPromise::peek):
     105        (JSC::B3::Air::LowerToAir::ArgPromise::consume):
     106        (JSC::B3::Air::LowerToAir::tmp):
     107        (JSC::B3::Air::LowerToAir::tmpPromise):
     108        (JSC::B3::Air::LowerToAir::canBeInternal):
     109        (JSC::B3::Air::LowerToAir::addr):
     110        (JSC::B3::Air::LowerToAir::loadPromise):
     111        (JSC::B3::Air::LowerToAir::imm):
     112        (JSC::B3::Air::LowerToAir::appendBinOp):
     113        (JSC::B3::Air::LowerToAir::tryAppendStoreUnOp):
     114        (JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
     115        (JSC::B3::Air::LowerToAir::createGenericCompare):
     116        (JSC::B3::Air::LowerToAir::createBranch):
     117        (JSC::B3::Air::LowerToAir::createCompare):
     118        (JSC::B3::Air::LowerToAir::tryLoad):
     119        (JSC::B3::Air::LowerToAir::tryLoad8S):
     120        (JSC::B3::Air::LowerToAir::tryLoad8Z):
     121        (JSC::B3::Air::LowerToAir::tryLoad16S):
     122        (JSC::B3::Air::LowerToAir::tryLoad16Z):
     123        (JSC::B3::Air::LowerToAir::tryAdd):
     124        (JSC::B3::Air::LowerToAir::tryStackSlot):
     125        (JSC::B3::Air::LowerToAir::tryEqual):
     126        (JSC::B3::Air::LowerToAir::tryNotEqual):
     127        (JSC::B3::Air::LowerToAir::tryLessThan):
     128        (JSC::B3::Air::LowerToAir::tryGreaterThan):
     129        (JSC::B3::Air::LowerToAir::tryLessEqual):
     130        (JSC::B3::Air::LowerToAir::tryGreaterEqual):
     131        (JSC::B3::Air::LowerToAir::tryAbove):
     132        (JSC::B3::Air::LowerToAir::tryBelow):
     133        (JSC::B3::Air::LowerToAir::tryAboveEqual):
     134        (JSC::B3::Air::LowerToAir::tryBelowEqual):
     135        (JSC::B3::Air::LowerToAir::tryPatchpoint):
     136        (JSC::B3::Air::LowerToAir::tryCheck):
     137        (JSC::B3::Air::LowerToAir::tryBranch):
     138        (JSC::B3::Air::LowerToAir::loadAddr): Deleted.
     139        * b3/B3LoweringMatcher.patterns:
     140        * b3/B3Opcode.cpp:
     141        (JSC::B3::invertedCompare):
     142        * b3/B3Opcode.h:
     143        (JSC::B3::isCheckMath):
     144        * b3/B3Procedure.cpp:
     145        (JSC::B3::Procedure::addBlock):
     146        (JSC::B3::Procedure::addIntConstant):
     147        (JSC::B3::Procedure::addBoolConstant):
     148        (JSC::B3::Procedure::resetValueOwners):
     149        * b3/B3Procedure.h:
     150        * b3/B3ReduceStrength.cpp:
     151        * b3/B3Validate.cpp:
     152        * b3/B3Value.cpp:
     153        (JSC::B3::Value::zShrConstant):
     154        (JSC::B3::Value::equalConstant):
     155        (JSC::B3::Value::notEqualConstant):
     156        (JSC::B3::Value::lessThanConstant):
     157        (JSC::B3::Value::greaterThanConstant):
     158        (JSC::B3::Value::lessEqualConstant):
     159        (JSC::B3::Value::greaterEqualConstant):
     160        (JSC::B3::Value::aboveConstant):
     161        (JSC::B3::Value::belowConstant):
     162        (JSC::B3::Value::aboveEqualConstant):
     163        (JSC::B3::Value::belowEqualConstant):
     164        (JSC::B3::Value::invertedCompare):
     165        * b3/B3Value.h:
     166        * b3/air/AirArg.cpp:
     167        (JSC::B3::Air::Arg::isRepresentableAs):
     168        (JSC::B3::Air::Arg::dump):
     169        (WTF::printInternal):
     170        * b3/air/AirArg.h:
     171        (JSC::B3::Air::Arg::isUse):
     172        (JSC::B3::Air::Arg::typeForB3Type):
     173        (JSC::B3::Air::Arg::widthForB3Type):
     174        (JSC::B3::Air::Arg::Arg):
     175        (JSC::B3::Air::Arg::value):
     176        (JSC::B3::Air::Arg::isRepresentableAs):
     177        (JSC::B3::Air::Arg::asNumber):
     178        (JSC::B3::Air::Arg::pointerValue):
     179        (JSC::B3::Air::Arg::asDoubleCondition):
     180        (JSC::B3::Air::Arg::inverted):
     181        (JSC::B3::Air::Arg::flipped):
     182        (JSC::B3::Air::Arg::isSignedCond):
     183        (JSC::B3::Air::Arg::isUnsignedCond):
     184        * b3/air/AirInst.h:
     185        (JSC::B3::Air::Inst::Inst):
     186        (JSC::B3::Air::Inst::operator bool):
     187        * b3/air/AirOpcode.opcodes:
     188        * b3/air/opcode_generator.rb:
     189        * b3/testb3.cpp:
     190        (hiddenTruthBecauseNoReturnIsStupid):
     191        (JSC::B3::testStoreLoadStackSlot):
     192        (JSC::B3::modelLoad):
     193        (JSC::B3::testLoad):
     194        (JSC::B3::testBranch):
     195        (JSC::B3::testComplex):
     196        (JSC::B3::testSimplePatchpoint):
     197        (JSC::B3::testSimpleCheck):
     198        (JSC::B3::genericTestCompare):
     199        (JSC::B3::modelCompare):
     200        (JSC::B3::testCompareLoad):
     201        (JSC::B3::testCompareImpl):
     202        (JSC::B3::testCompare):
     203        (JSC::B3::run):
     204        (main):
     205        * dfg/DFGSpeculativeJIT.cpp:
     206        (JSC::DFG::SpeculativeJIT::compileArithMod):
     207        * jit/JITPropertyAccess.cpp:
     208        (JSC::JIT::emitIntTypedArrayGetByVal):
     209        (JSC::JIT::emitIntTypedArrayPutByVal):
     210
    12112015-11-05  Joseph Pecoraro  <pecoraro@apple.com>
    2212
  • trunk/Source/JavaScriptCore/assembler/MacroAssembler.h

    r191816 r192072  
    168168        case DoubleLessThanOrEqualOrUnordered:
    169169            return DoubleGreaterThan;
    170         default:
    171             RELEASE_ASSERT_NOT_REACHED();
    172             return DoubleEqual; // make compiler happy
    173         }
     170        }
     171        RELEASE_ASSERT_NOT_REACHED();
     172        return DoubleEqual; // make compiler happy
    174173    }
    175174   
     
    195194            RELEASE_ASSERT_NOT_REACHED();
    196195            return Zero; // Make compiler happy for release builds.
     196        }
     197    }
     198
     199    static RelationalCondition flip(RelationalCondition cond)
     200    {
     201        switch (cond) {
     202        case Equal:
     203        case NotEqual:
     204            return cond;
     205        case Above:
     206            return Below;
     207        case AboveOrEqual:
     208            return BelowOrEqual;
     209        case Below:
     210            return Above;
     211        case BelowOrEqual:
     212            return AboveOrEqual;
     213        case GreaterThan:
     214            return LessThan;
     215        case GreaterThanOrEqual:
     216            return LessThanOrEqual;
     217        case LessThan:
     218            return GreaterThan;
     219        case LessThanOrEqual:
     220            return GreaterThanOrEqual;
     221        }
     222
     223        RELEASE_ASSERT_NOT_REACHED();
     224        return Equal;
     225    }
     226
     227    // True if this:
     228    //     branch8(cond, value, value)
     229    // Is the same as this:
     230    //     branch32(cond, signExt8(value), signExt8(value))
     231    static bool isSigned(RelationalCondition cond)
     232    {
     233        switch (cond) {
     234        case Equal:
     235        case NotEqual:
     236        case GreaterThan:
     237        case GreaterThanOrEqual:
     238        case LessThan:
     239        case LessThanOrEqual:
     240            return true;
     241        default:
     242            return false;
     243        }
     244    }
     245
     246    // True if this:
     247    //     branch8(cond, value, value)
     248    // Is the same as this:
     249    //     branch32(cond, zeroExt8(value), zeroExt8(value))
     250    static bool isUnsigned(RelationalCondition cond)
     251    {
     252        switch (cond) {
     253        case Equal:
     254        case NotEqual:
     255        case Above:
     256        case AboveOrEqual:
     257        case Below:
     258        case BelowOrEqual:
     259            return true;
     260        default:
     261            return false;
    197262        }
    198263    }
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r192008 r192072  
    14721472    {
    14731473        generateTest32(address, mask);
     1474        set32(x86Condition(cond), dest);
     1475    }
     1476
     1477    void test32(ResultCondition cond, RegisterID reg, RegisterID mask, RegisterID dest)
     1478    {
     1479        m_assembler.testl_rr(reg, mask);
    14741480        set32(x86Condition(cond), dest);
    14751481    }
  • trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp

    r191993 r192072  
    5858} // anonymous namespace
    5959
     60CheckSpecial::Key::Key(const Inst& inst)
     61{
     62    m_opcode = inst.opcode;
     63    m_numArgs = inst.args.size();
     64}
     65
     66void CheckSpecial::Key::dump(PrintStream& out) const
     67{
     68    out.print(m_opcode, "(", m_numArgs, ")");
     69}
     70
    6071CheckSpecial::CheckSpecial(Air::Opcode opcode, unsigned numArgs)
    6172    : m_checkOpcode(opcode)
     
    6374{
    6475    ASSERT(isTerminal(opcode));
     76}
     77
     78CheckSpecial::CheckSpecial(const CheckSpecial::Key& key)
     79    : CheckSpecial(key.opcode(), key.numArgs())
     80{
    6581}
    6682
  • trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h

    r191705 r192072  
    3131#include "AirOpcode.h"
    3232#include "B3StackmapSpecial.h"
     33#include <wtf/HashMap.h>
    3334
    3435namespace JSC { namespace B3 {
     36
     37namespace Air {
     38struct Inst;
     39}
    3540
    3641// We want to lower Check instructions to a branch, but then we want to route that branch to our
     
    4752class CheckSpecial : public StackmapSpecial {
    4853public:
     54    // Support for hash consing these things.
     55    class Key {
     56    public:
     57        Key()
     58            : m_opcode(Air::Nop)
     59            , m_numArgs(0)
     60        {
     61        }
     62       
     63        Key(Air::Opcode opcode, unsigned numArgs)
     64            : m_opcode(opcode)
     65            , m_numArgs(numArgs)
     66        {
     67        }
     68
     69        explicit Key(const Air::Inst&);
     70
     71        bool operator==(const Key& other) const
     72        {
     73            return m_opcode == other.m_opcode
     74                && m_numArgs == other.m_numArgs;
     75        }
     76
     77        bool operator!=(const Key& other) const
     78        {
     79            return !(*this == other);
     80        }
     81
     82        explicit operator bool() const { return *this != Key(); }
     83
     84        Air::Opcode opcode() const { return m_opcode; }
     85        unsigned numArgs() const { return m_numArgs; }
     86
     87        void dump(PrintStream& out) const;
     88
     89        Key(WTF::HashTableDeletedValueType)
     90            : m_opcode(Air::Nop)
     91            , m_numArgs(1)
     92        {
     93        }
     94
     95        bool isHashTableDeletedValue() const
     96        {
     97            return *this == Key(WTF::HashTableDeletedValue);
     98        }
     99
     100        unsigned hash() const
     101        {
     102            // Seriously, we don't need to be smart here. It just doesn't matter.
     103            return m_opcode + m_numArgs;
     104        }
     105       
     106    private:
     107        Air::Opcode m_opcode;
     108        unsigned m_numArgs;
     109    };
     110   
    49111    CheckSpecial(Air::Opcode, unsigned numArgs);
     112    CheckSpecial(const Key&);
    50113    ~CheckSpecial();
    51114
     
    71134};
    72135
     136struct CheckSpecialKeyHash {
     137    static unsigned hash(const CheckSpecial::Key& key) { return key.hash(); }
     138    static bool equal(const CheckSpecial::Key& a, const CheckSpecial::Key& b) { return a == b; }
     139    static const bool safeToCompareToEmptyOrDeleted = true;
     140};
     141
    73142} } // namespace JSC::B3
     143
     144namespace WTF {
     145
     146template<typename T> struct DefaultHash;
     147template<> struct DefaultHash<JSC::B3::CheckSpecial::Key> {
     148    typedef JSC::B3::CheckSpecialKeyHash Hash;
     149};
     150
     151template<typename T> struct HashTraits;
     152template<> struct HashTraits<JSC::B3::CheckSpecial::Key> : SimpleClassHashTraits<JSC::B3::CheckSpecial::Key> {
     153    // I don't want to think about this very hard, it's not worth it. I'm a be conservative.
     154    static const bool emptyValueIsZero = false;
     155};
     156
     157} // namespace WTF
    74158
    75159#endif // ENABLE(B3_JIT)
  • trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp

    r192051 r192072  
    104104}
    105105
    106 Value* Const32Value::equalConstant(Procedure& proc, Value* other) const
     106TriState Const32Value::equalConstant(Value* other) const
    107107{
    108108    if (!other->hasInt32())
    109         return nullptr;
    110     return proc.add<Const32Value>(origin(), m_value == other->asInt32());
     109        return MixedTriState;
     110    return triState(m_value == other->asInt32());
    111111}
    112112
    113 Value* Const32Value::notEqualConstant(Procedure& proc, Value* other) const
     113TriState Const32Value::notEqualConstant(Value* other) const
    114114{
    115115    if (!other->hasInt32())
    116         return nullptr;
    117     return proc.add<Const32Value>(origin(), m_value != other->asInt32());
     116        return MixedTriState;
     117    return triState(m_value != other->asInt32());
     118}
     119
     120TriState Const32Value::lessThanConstant(Value* other) const
     121{
     122    if (!other->hasInt32())
     123        return MixedTriState;
     124    return triState(m_value < other->asInt32());
     125}
     126
     127TriState Const32Value::greaterThanConstant(Value* other) const
     128{
     129    if (!other->hasInt32())
     130        return MixedTriState;
     131    return triState(m_value > other->asInt32());
     132}
     133
     134TriState Const32Value::lessEqualConstant(Value* other) const
     135{
     136    if (!other->hasInt32())
     137        return MixedTriState;
     138    return triState(m_value <= other->asInt32());
     139}
     140
     141TriState Const32Value::greaterEqualConstant(Value* other) const
     142{
     143    if (!other->hasInt32())
     144        return MixedTriState;
     145    return triState(m_value >= other->asInt32());
     146}
     147
     148TriState Const32Value::aboveConstant(Value* other) const
     149{
     150    if (!other->hasInt32())
     151        return MixedTriState;
     152    return triState(static_cast<uint32_t>(m_value) > static_cast<uint32_t>(other->asInt32()));
     153}
     154
     155TriState Const32Value::belowConstant(Value* other) const
     156{
     157    if (!other->hasInt32())
     158        return MixedTriState;
     159    return triState(static_cast<uint32_t>(m_value) < static_cast<uint32_t>(other->asInt32()));
     160}
     161
     162TriState Const32Value::aboveEqualConstant(Value* other) const
     163{
     164    if (!other->hasInt32())
     165        return MixedTriState;
     166    return triState(static_cast<uint32_t>(m_value) >= static_cast<uint32_t>(other->asInt32()));
     167}
     168
     169TriState Const32Value::belowEqualConstant(Value* other) const
     170{
     171    if (!other->hasInt32())
     172        return MixedTriState;
     173    return triState(static_cast<uint32_t>(m_value) <= static_cast<uint32_t>(other->asInt32()));
    118174}
    119175
  • trunk/Source/JavaScriptCore/b3/B3Const32Value.h

    r192051 r192072  
    5151    Value* sShrConstant(Procedure&, Value* other) const override;
    5252    Value* zShrConstant(Procedure&, Value* other) const override;
    53     Value* equalConstant(Procedure&, Value* other) const override;
    54     Value* notEqualConstant(Procedure&, Value* other) const override;
     53
     54    TriState equalConstant(Value* other) const override;
     55    TriState notEqualConstant(Value* other) const override;
     56    TriState lessThanConstant(Value* other) const override;
     57    TriState greaterThanConstant(Value* other) const override;
     58    TriState lessEqualConstant(Value* other) const override;
     59    TriState greaterEqualConstant(Value* other) const override;
     60    TriState aboveConstant(Value* other) const override;
     61    TriState belowConstant(Value* other) const override;
     62    TriState aboveEqualConstant(Value* other) const override;
     63    TriState belowEqualConstant(Value* other) const override;
    5564
    5665protected:
  • trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp

    r192051 r192072  
    104104}
    105105
    106 Value* Const64Value::equalConstant(Procedure& proc, Value* other) const
     106TriState Const64Value::equalConstant(Value* other) const
    107107{
    108108    if (!other->hasInt64())
    109         return nullptr;
    110     return proc.add<Const32Value>(origin(), m_value == other->asInt64());
     109        return MixedTriState;
     110    return triState(m_value == other->asInt64());
    111111}
    112112
    113 Value* Const64Value::notEqualConstant(Procedure& proc, Value* other) const
     113TriState Const64Value::notEqualConstant(Value* other) const
    114114{
    115115    if (!other->hasInt64())
    116         return nullptr;
    117     return proc.add<Const32Value>(origin(), m_value != other->asInt64());
     116        return MixedTriState;
     117    return triState(m_value != other->asInt64());
     118}
     119
     120TriState Const64Value::lessThanConstant(Value* other) const
     121{
     122    if (!other->hasInt64())
     123        return MixedTriState;
     124    return triState(m_value < other->asInt64());
     125}
     126
     127TriState Const64Value::greaterThanConstant(Value* other) const
     128{
     129    if (!other->hasInt64())
     130        return MixedTriState;
     131    return triState(m_value > other->asInt64());
     132}
     133
     134TriState Const64Value::lessEqualConstant(Value* other) const
     135{
     136    if (!other->hasInt64())
     137        return MixedTriState;
     138    return triState(m_value <= other->asInt64());
     139}
     140
     141TriState Const64Value::greaterEqualConstant(Value* other) const
     142{
     143    if (!other->hasInt64())
     144        return MixedTriState;
     145    return triState(m_value >= other->asInt64());
     146}
     147
     148TriState Const64Value::aboveConstant(Value* other) const
     149{
     150    if (!other->hasInt64())
     151        return MixedTriState;
     152    return triState(static_cast<uint64_t>(m_value) > static_cast<uint64_t>(other->asInt64()));
     153}
     154
     155TriState Const64Value::belowConstant(Value* other) const
     156{
     157    if (!other->hasInt64())
     158        return MixedTriState;
     159    return triState(static_cast<uint64_t>(m_value) < static_cast<uint64_t>(other->asInt64()));
     160}
     161
     162TriState Const64Value::aboveEqualConstant(Value* other) const
     163{
     164    if (!other->hasInt64())
     165        return MixedTriState;
     166    return triState(static_cast<uint64_t>(m_value) >= static_cast<uint64_t>(other->asInt64()));
     167}
     168
     169TriState Const64Value::belowEqualConstant(Value* other) const
     170{
     171    if (!other->hasInt64())
     172        return MixedTriState;
     173    return triState(static_cast<uint64_t>(m_value) <= static_cast<uint64_t>(other->asInt64()));
    118174}
    119175
  • trunk/Source/JavaScriptCore/b3/B3Const64Value.h

    r192051 r192072  
    5151    Value* sShrConstant(Procedure&, Value* other) const override;
    5252    Value* zShrConstant(Procedure&, Value* other) const override;
    53     Value* equalConstant(Procedure&, Value* other) const override;
    54     Value* notEqualConstant(Procedure&, Value* other) const override;
     53
     54    TriState equalConstant(Value* other) const override;
     55    TriState notEqualConstant(Value* other) const override;
     56    TriState lessThanConstant(Value* other) const override;
     57    TriState greaterThanConstant(Value* other) const override;
     58    TriState lessEqualConstant(Value* other) const override;
     59    TriState greaterEqualConstant(Value* other) const override;
     60    TriState aboveConstant(Value* other) const override;
     61    TriState belowConstant(Value* other) const override;
     62    TriState aboveEqualConstant(Value* other) const override;
     63    TriState belowEqualConstant(Value* other) const override;
    5564
    5665protected:
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp

    r191993 r192072  
    6262}
    6363
    64 Value* ConstDoubleValue::equalConstant(Procedure& proc, Value* other) const
     64TriState ConstDoubleValue::equalConstant(Value* other) const
    6565{
    6666    if (!other->hasDouble())
    67         return nullptr;
    68     return proc.add<Const32Value>(origin(), m_value == other->asDouble());
     67        return MixedTriState;
     68    return triState(m_value == other->asDouble());
    6969}
    7070
    71 Value* ConstDoubleValue::notEqualConstant(Procedure& proc, Value* other) const
     71TriState ConstDoubleValue::notEqualConstant(Value* other) const
    7272{
    7373    if (!other->hasDouble())
    74         return nullptr;
    75     return proc.add<Const32Value>(origin(), m_value != other->asDouble());
     74        return MixedTriState;
     75    return triState(m_value != other->asDouble());
     76}
     77
     78TriState ConstDoubleValue::lessThanConstant(Value* other) const
     79{
     80    if (!other->hasDouble())
     81        return MixedTriState;
     82    return triState(m_value < other->asDouble());
     83}
     84
     85TriState ConstDoubleValue::greaterThanConstant(Value* other) const
     86{
     87    if (!other->hasDouble())
     88        return MixedTriState;
     89    return triState(m_value > other->asDouble());
     90}
     91
     92TriState ConstDoubleValue::lessEqualConstant(Value* other) const
     93{
     94    if (!other->hasDouble())
     95        return MixedTriState;
     96    return triState(m_value <= other->asDouble());
     97}
     98
     99TriState ConstDoubleValue::greaterEqualConstant(Value* other) const
     100{
     101    if (!other->hasDouble())
     102        return MixedTriState;
     103    return triState(m_value >= other->asDouble());
    76104}
    77105
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h

    r191994 r192072  
    4545    Value* addConstant(Procedure& proc, Value* other) const override;
    4646    Value* subConstant(Procedure& proc, Value* other) const override;
    47     Value* equalConstant(Procedure& proc, Value* other) const override;
    48     Value* notEqualConstant(Procedure& proc, Value* other) const override;
     47
     48    TriState equalConstant(Value* other) const override;
     49    TriState notEqualConstant(Value* other) const override;
     50    TriState lessThanConstant(Value* other) const override;
     51    TriState greaterThanConstant(Value* other) const override;
     52    TriState lessEqualConstant(Value* other) const override;
     53    TriState greaterEqualConstant(Value* other) const override;
    4954
    5055protected:
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r192051 r192072  
    5858namespace {
    5959
     60const bool verbose = false;
     61
    6062class LowerToAir {
    6163public:
     
    8789            // Reset some state.
    8890            insts.resize(0);
     91
     92            if (verbose)
     93                dataLog("Lowering Block ", *block, ":\n");
    8994           
    9095            // Process blocks in reverse order so we see uses before defs. That's what allows us
     
    96101                    continue;
    97102                insts.append(Vector<Inst>());
     103                if (verbose)
     104                    dataLog("Lowering ", deepDump(currentValue), ":\n");
    98105                bool result = runLoweringMatcher(currentValue, *this);
    99106                if (!result) {
    100107                    dataLog("FATAL: could not lower ", deepDump(currentValue), "\n");
    101108                    RELEASE_ASSERT_NOT_REACHED();
     109                }
     110                if (verbose) {
     111                    for (Inst& inst : insts.last())
     112                        dataLog("    ", inst, "\n");
    102113                }
    103114            }
     
    163174    }
    164175
     176    class ArgPromise {
     177    public:
     178        ArgPromise() { }
     179
     180        ArgPromise(const Arg& arg, Value* valueToLock = nullptr)
     181            : m_arg(arg)
     182            , m_value(valueToLock)
     183        {
     184        }
     185
     186        static ArgPromise tmp(Value* value)
     187        {
     188            ArgPromise result;
     189            result.m_value = value;
     190            return result;
     191        }
     192
     193        explicit operator bool() const { return m_arg || m_value; }
     194
     195        Arg::Kind kind() const
     196        {
     197            if (!m_arg && m_value)
     198                return Arg::Tmp;
     199            return m_arg.kind();
     200        }
     201
     202        const Arg& peek() const
     203        {
     204            return m_arg;
     205        }
     206
     207        Arg consume(LowerToAir& lower) const
     208        {
     209            if (!m_arg && m_value)
     210                return lower.tmp(m_value);
     211            if (m_value)
     212                lower.commitInternal(m_value);
     213            return m_arg;
     214        }
     215       
     216    private:
     217        // Three forms:
     218        // Everything null: invalid.
     219        // Arg non-null, value null: just use the arg, nothing special.
     220        // Arg null, value non-null: it's a tmp, pin it when necessary.
     221        // Arg non-null, value non-null: use the arg, lock the value.
     222        Arg m_arg;
     223        Value* m_value;
     224    };
     225
     226    // Consider using tmpPromise() in cases where you aren't sure that you want to pin the value yet.
     227    // Here are three canonical ways of using tmp() and tmpPromise():
     228    //
     229    // Idiom #1: You know that you want a tmp() and you know that it will be valid for the
     230    // instruction you're emitting.
     231    //
     232    //     append(Foo, tmp(bar));
     233    //
     234    // Idiom #2: You don't know if you want to use a tmp() because you haven't determined if the
     235    // instruction will accept it, so you query first. Note that the call to tmp() happens only after
     236    // you are sure that you will use it.
     237    //
     238    //     if (isValidForm(Foo, Arg::Tmp))
     239    //         append(Foo, tmp(bar))
     240    //
     241    // Idiom #3: Same as Idiom #2, but using tmpPromise. Notice that this calls consume() only after
     242    // it's sure it will use the tmp. That's deliberate.
     243    //
     244    //     ArgPromise promise = tmpPromise(bar);
     245    //     if (isValidForm(Foo, promise.kind()))
     246    //         append(Foo, promise.consume(*this))
     247    //
     248    // In both idiom #2 and idiom #3, we don't pin the value to a temporary except when we actually
     249    // emit the instruction. Both tmp() and tmpPromise().consume(*this) will pin it. Pinning means
     250    // that we will henceforth require that the value of 'bar' is generated as a separate
     251    // instruction. We don't want to pin the value to a temporary if we might change our minds, and
     252    // pass an address operand representing 'bar' to Foo instead.
     253    //
     254    // Because tmp() pins, the following is not an idiom you should use:
     255    //
     256    //     Tmp tmp = this->tmp(bar);
     257    //     if (isValidForm(Foo, tmp.kind()))
     258    //         append(Foo, tmp);
     259    //
     260    // That's because if isValidForm() returns false, you will have already pinned the 'bar' to a
     261    // temporary. You might later want to try to do something like loadPromise(), and that will fail.
     262    // This arises in operations that have both a Addr,Tmp and Tmp,Addr forms. The following code
     263    // seems right, but will actually fail to ever match the Tmp,Addr form because by then, the right
     264    // value is already pinned.
     265    //
     266    //     auto tryThings = [this] (const Arg& left, const Arg& right) {
     267    //         if (isValidForm(Foo, left.kind(), right.kind()))
     268    //             return Inst(Foo, currentValue, left, right);
     269    //         return Inst();
     270    //     };
     271    //     if (Inst result = tryThings(loadAddr(left), tmp(right)))
     272    //         return result;
     273    //     if (Inst result = tryThings(tmp(left), loadAddr(right))) // this never succeeds.
     274    //         return result;
     275    //     return Inst(Foo, currentValue, tmp(left), tmp(right));
     276    //
     277    // If you imagine that loadAddr(value) is just loadPromise(value).consume(*this), then this code
     278    // will run correctly - it will generate OK code - but the second form is never matched.
     279    // loadAddr(right) will never succeed because it will observe that 'right' is already pinned.
     280    // Of course, it's exactly because of the risky nature of such code that we don't have a
     281    // loadAddr() helper and require you to balance ArgPromise's in code like this. Such code will
     282    // work fine if written as:
     283    //
     284    //     auto tryThings = [this] (const ArgPromise& left, const ArgPromise& right) {
     285    //         if (isValidForm(Foo, left.kind(), right.kind()))
     286    //             return Inst(Foo, currentValue, left.consume(*this), right.consume(*this));
     287    //         return Inst();
     288    //     };
     289    //     if (Inst result = tryThings(loadPromise(left), tmpPromise(right)))
     290    //         return result;
     291    //     if (Inst result = tryThings(tmpPromise(left), loadPromise(right)))
     292    //         return result;
     293    //     return Inst(Foo, currentValue, tmp(left), tmp(right));
     294    //
     295    // Notice that we did use tmp in the fall-back case at the end, because by then, we know for sure
     296    // that we want a tmp. But using tmpPromise in the tryThings() calls ensures that doing so
     297    // doesn't prevent us from trying loadPromise on the same value.
    165298    Tmp tmp(Value* value)
    166299    {
     
    169302            while (shouldCopyPropagate(value))
    170303                value = value->child(0);
    171             tmp = code.newTmp(isInt(value->type()) ? Arg::GP : Arg::FP);
    172             valueToTmp[value] = tmp;
     304            Tmp& realTmp = valueToTmp[value];
     305            if (!realTmp)
     306                realTmp = code.newTmp(Arg::typeForB3Type(value->type()));
     307            tmp = realTmp;
    173308        }
    174309        return tmp;
     310    }
     311
     312    ArgPromise tmpPromise(Value* value)
     313    {
     314        return ArgPromise::tmp(value);
    175315    }
    176316
     
    254394    }
    255395
    256     Arg loadAddr(Value* loadValue)
    257     {
    258         if (loadValue->opcode() != Load)
     396    ArgPromise loadPromise(Value* loadValue, B3::Opcode loadOpcode)
     397    {
     398        if (loadValue->opcode() != loadOpcode)
    259399            return Arg();
    260400        if (!canBeInternal(loadValue))
     
    262402        if (crossesInterference(loadValue))
    263403            return Arg();
    264         return addr(loadValue);
     404        return ArgPromise(addr(loadValue), loadValue);
     405    }
     406
     407    ArgPromise loadPromise(Value* loadValue)
     408    {
     409        return loadPromise(loadValue, Load);
    265410    }
    266411
     
    341486       
    342487        if (commutativity == Commutative) {
    343             Arg leftAddr = loadAddr(left);
     488            ArgPromise leftAddr = loadPromise(left);
    344489            if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
    345                 commitInternal(left);
    346490                append(relaxedMoveForType(currentValue->type()), tmp(right), result);
    347                 append(opcode, leftAddr, result);
     491                append(opcode, leftAddr.consume(*this), result);
    348492                return;
    349493            }
    350494        }
    351495
    352         Arg rightAddr = loadAddr(right);
     496        ArgPromise rightAddr = loadPromise(right);
    353497        if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) {
    354             commitInternal(right);
    355498            append(relaxedMoveForType(currentValue->type()), tmp(left), result);
    356             append(opcode, rightAddr, result);
     499            append(opcode, rightAddr.consume(*this), result);
    357500            return;
    358501        }
     
    379522        ASSERT(storeAddr);
    380523
    381         if (loadAddr(value) != storeAddr)
    382             return false;
    383 
    384         commitInternal(value);
     524        ArgPromise loadPromise = this->loadPromise(value);
     525        if (loadPromise.peek() != storeAddr)
     526            return false;
     527
     528        loadPromise.consume(*this);
    385529        append(opcode, storeAddr);
    386530        return true;
     
    393537        ASSERT(storeAddr);
    394538
    395         Value* loadValue;
    396         Value* otherValue;
    397         if (loadAddr(left) == storeAddr) {
    398             loadValue = left;
     539        ArgPromise loadPromise;
     540        Value* otherValue = nullptr;
     541       
     542        loadPromise = this->loadPromise(left);
     543        if (loadPromise.peek() == storeAddr)
    399544            otherValue = right;
    400         } else if (commutativity == Commutative && loadAddr(right) == storeAddr) {
    401             loadValue = right;
    402             otherValue = left;
    403         } else
     545        else if (commutativity == Commutative) {
     546            loadPromise = this->loadPromise(right);
     547            if (loadPromise.peek() == storeAddr)
     548                otherValue = left;
     549        }
     550
     551        if (!otherValue)
    404552            return false;
    405553
    406554        if (isValidForm(opcode, Arg::Imm, storeAddr.kind()) && imm(otherValue)) {
    407             commitInternal(loadValue);
     555            loadPromise.consume(*this);
    408556            append(opcode, imm(otherValue), storeAddr);
    409557            return true;
     
    413561            return false;
    414562
    415         commitInternal(loadValue);
     563        loadPromise.consume(*this);
    416564        append(opcode, tmp(otherValue), storeAddr);
    417565        return true;
     
    623771    AddressSelector addressSelector;
    624772
     773    // Create an Inst to do the comparison specified by the given value.
     774    template<typename CompareFunctor, typename TestFunctor, typename CompareDoubleFunctor>
     775    Inst createGenericCompare(
     776        Value* value,
     777        const CompareFunctor& compare, // Signature: (Arg::Width, Arg relCond, Arg, Arg) -> Inst
     778        const TestFunctor& test, // Signature: (Arg::Width, Arg resCond, Arg, Arg) -> Inst
     779        const CompareDoubleFunctor& compareDouble, // Signature: (Arg doubleCond, Arg, Arg) -> Inst
     780        bool inverted = false)
     781    {
     782        // Chew through any negations. It's not strictly necessary for this to be a loop, but we like
     783        // to follow the rule that the instruction selector reduces strength whenever it doesn't
     784        // require making things more complicated.
     785        for (;;) {
     786            if (!canBeInternal(value) && value != currentValue)
     787                break;
     788            bool shouldInvert =
     789                (value->opcode() == BitXor && value->child(1)->isInt(1) && value->child(0)->returnsBool())
     790                || (value->opcode() == Equal && value->child(1)->isInt(0));
     791            if (!shouldInvert)
     792                break;
     793            value = value->child(0);
     794            inverted = !inverted;
     795            commitInternal(value);
     796        }
     797
     798        auto createRelCond = [&] (
     799            MacroAssembler::RelationalCondition relationalCondition,
     800            MacroAssembler::DoubleCondition doubleCondition) {
     801            Arg relCond = Arg::relCond(relationalCondition).inverted(inverted);
     802            Arg doubleCond = Arg::doubleCond(doubleCondition).inverted(inverted);
     803            Value* left = value->child(0);
     804            Value* right = value->child(1);
     805
     806            if (isInt(value->child(0)->type())) {
     807                Arg leftImm = imm(left);
     808                Arg rightImm = imm(right);
     809
     810                auto tryCompare = [&] (
     811                    Arg::Width width, const ArgPromise& left, const ArgPromise& right) -> Inst {
     812                    if (Inst result = compare(width, relCond, left, right))
     813                        return result;
     814                    if (Inst result = compare(width, relCond.flipped(), right, left))
     815                        return result;
     816                    return Inst();
     817                };
     818
     819                auto tryCompareLoadImm = [&] (
     820                    Arg::Width width, B3::Opcode loadOpcode, Arg::Signedness signedness) -> Inst {
     821                    if (rightImm && rightImm.isRepresentableAs(width, signedness)) {
     822                        if (Inst result = tryCompare(width, loadPromise(left, loadOpcode), rightImm)) {
     823                            commitInternal(left);
     824                            return result;
     825                        }
     826                    }
     827                    if (leftImm && leftImm.isRepresentableAs(width, signedness)) {
     828                        if (Inst result = tryCompare(width, leftImm, loadPromise(right, loadOpcode))) {
     829                            commitInternal(right);
     830                            return result;
     831                        }
     832                    }
     833                    return Inst();
     834                };
     835
     836                // First handle compares that involve fewer bits than B3's type system supports.
     837                // This is pretty important. For example, we want this to be a single instruction:
     838                //
     839                //     @1 = Load8S(...)
     840                //     @2 = Const32(...)
     841                //     @3 = LessThan(@1, @2)
     842                //     Branch(@3)
     843               
     844                if (relCond.isSignedCond()) {
     845                    if (Inst result = tryCompareLoadImm(Arg::Width8, Load8S, Arg::Signed))
     846                        return result;
     847                }
     848               
     849                if (relCond.isUnsignedCond()) {
     850                    if (Inst result = tryCompareLoadImm(Arg::Width8, Load8Z, Arg::Unsigned))
     851                        return result;
     852                }
     853
     854                if (relCond.isSignedCond()) {
     855                    if (Inst result = tryCompareLoadImm(Arg::Width16, Load16S, Arg::Signed))
     856                        return result;
     857                }
     858               
     859                if (relCond.isUnsignedCond()) {
     860                    if (Inst result = tryCompareLoadImm(Arg::Width16, Load16Z, Arg::Unsigned))
     861                        return result;
     862                }
     863
     864                // Now handle compares that involve a load and an immediate.
     865
     866                Arg::Width width = Arg::widthForB3Type(value->child(0)->type());
     867                if (Inst result = tryCompareLoadImm(width, Load, Arg::Signed))
     868                    return result;
     869
     870                // Now handle compares that involve a load. It's not obvious that it's better to
     871                // handle this before the immediate cases or not. Probably doesn't matter.
     872
     873                if (Inst result = tryCompare(width, loadPromise(left), tmpPromise(right))) {
     874                    commitInternal(left);
     875                    return result;
     876                }
     877               
     878                if (Inst result = tryCompare(width, tmpPromise(left), loadPromise(right))) {
     879                    commitInternal(right);
     880                    return result;
     881                }
     882
     883                // Now handle compares that involve an immediate and a tmp.
     884               
     885                if (leftImm && leftImm.isRepresentableAs<int32_t>()) {
     886                    if (Inst result = tryCompare(width, leftImm, tmpPromise(right)))
     887                        return result;
     888                }
     889               
     890                if (rightImm && rightImm.isRepresentableAs<int32_t>()) {
     891                    if (Inst result = tryCompare(width, tmpPromise(left), rightImm))
     892                        return result;
     893                }
     894
     895                // Finally, handle comparison between tmps.
     896                return tryCompare(width, tmpPromise(left), tmpPromise(right));
     897            }
     898
     899            // Double comparisons can't really do anything smart.
     900            return compareDouble(doubleCond, tmpPromise(left), tmpPromise(right));
     901        };
     902
     903        Arg::Width width = Arg::widthForB3Type(value->type());
     904        Arg resCond = Arg::resCond(MacroAssembler::NonZero).inverted(inverted);
     905       
     906        auto attemptFused = [&] () -> Inst {
     907            switch (value->opcode()) {
     908            case NotEqual:
     909                return createRelCond(MacroAssembler::NotEqual, MacroAssembler::DoubleNotEqualOrUnordered);
     910            case Equal:
     911                return createRelCond(MacroAssembler::Equal, MacroAssembler::DoubleEqual);
     912            case LessThan:
     913                return createRelCond(MacroAssembler::LessThan, MacroAssembler::DoubleLessThan);
     914            case GreaterThan:
     915                return createRelCond(MacroAssembler::GreaterThan, MacroAssembler::DoubleGreaterThan);
     916            case LessEqual:
     917                return createRelCond(MacroAssembler::LessThanOrEqual, MacroAssembler::DoubleLessThanOrEqual);
     918            case GreaterEqual:
     919                return createRelCond(MacroAssembler::GreaterThanOrEqual, MacroAssembler::DoubleGreaterThanOrEqual);
     920            case Above:
     921                // We use a bogus double condition because these integer comparisons won't got down that
     922                // path anyway.
     923                return createRelCond(MacroAssembler::Above, MacroAssembler::DoubleEqual);
     924            case Below:
     925                return createRelCond(MacroAssembler::Below, MacroAssembler::DoubleEqual);
     926            case AboveEqual:
     927                return createRelCond(MacroAssembler::AboveOrEqual, MacroAssembler::DoubleEqual);
     928            case BelowEqual:
     929                return createRelCond(MacroAssembler::BelowOrEqual, MacroAssembler::DoubleEqual);
     930            case BitAnd: {
     931                Value* left = value->child(0);
     932                Value* right = value->child(1);
     933
     934                Arg leftImm = imm(left);
     935                Arg rightImm = imm(right);
     936               
     937                auto tryTest = [&] (
     938                    Arg::Width width, const ArgPromise& left, const ArgPromise& right) -> Inst {
     939                    if (Inst result = test(width, resCond, left, right))
     940                        return result;
     941                    if (Inst result = test(width, resCond, right, left))
     942                        return result;
     943                    return Inst();
     944                };
     945
     946                auto tryTestLoadImm = [&] (Arg::Width width, B3::Opcode loadOpcode) -> Inst {
     947                    if (rightImm && rightImm.isRepresentableAs(width, Arg::Unsigned)) {
     948                        if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm)) {
     949                            commitInternal(left);
     950                            return result;
     951                        }
     952                    }
     953                    if (leftImm && leftImm.isRepresentableAs(width, Arg::Unsigned)) {
     954                        if (Inst result = tryTest(width, leftImm, loadPromise(right, loadOpcode))) {
     955                            commitInternal(right);
     956                            return result;
     957                        }
     958                    }
     959                    return Inst();
     960                };
     961
     962                // First handle test's that involve fewer bits than B3's type system supports.
     963
     964                if (Inst result = tryTestLoadImm(Arg::Width8, Load8Z))
     965                    return result;
     966
     967                if (Inst result = tryTestLoadImm(Arg::Width8, Load8S))
     968                    return result;
     969
     970                if (Inst result = tryTestLoadImm(Arg::Width16, Load16Z))
     971                    return result;
     972
     973                if (Inst result = tryTestLoadImm(Arg::Width16, Load16S))
     974                    return result;
     975
     976                // Now handle test's that involve a load and an immediate. Note that immediates are
     977                // 32-bit, and we want zero-extension. Hence, the immediate form is compiled as a
     978                // 32-bit test. Note that this spits on the grave of inferior endians, such as the
     979                // big one.
     980               
     981                if (Inst result = tryTestLoadImm(Arg::Width32, Load))
     982                    return result;
     983
     984                // Now handle test's that involve a load.
     985
     986                Arg::Width width = Arg::widthForB3Type(value->child(0)->type());
     987                if (Inst result = tryTest(width, loadPromise(left), tmpPromise(right))) {
     988                    commitInternal(left);
     989                    return result;
     990                }
     991
     992                if (Inst result = tryTest(width, tmpPromise(left), loadPromise(right))) {
     993                    commitInternal(right);
     994                    return result;
     995                }
     996
     997                // Now handle test's that involve an immediate and a tmp.
     998
     999                if (leftImm && leftImm.isRepresentableAs<uint32_t>()) {
     1000                    if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right)))
     1001                        return result;
     1002                }
     1003
     1004                if (rightImm && rightImm.isRepresentableAs<uint32_t>()) {
     1005                    if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm))
     1006                        return result;
     1007                }
     1008
     1009                // Finally, just do tmp's.
     1010                return tryTest(width, tmpPromise(left), tmpPromise(right));
     1011            }
     1012            default:
     1013                return Inst();
     1014            }
     1015        };
     1016
     1017        if (canBeInternal(value) || value == currentValue) {
     1018            if (Inst result = attemptFused()) {
     1019                commitInternal(value);
     1020                return result;
     1021            }
     1022        }
     1023
     1024        if (Inst result = test(width, resCond, tmpPromise(value), Arg::imm(-1)))
     1025            return result;
     1026       
     1027        // Sometimes this is the only form of test available. We prefer not to use this because
     1028        // it's less canonical.
     1029        return test(width, resCond, tmpPromise(value), tmpPromise(value));
     1030    }
     1031
     1032    Inst createBranch(Value* value, bool inverted = false)
     1033    {
     1034        return createGenericCompare(
     1035            value,
     1036            [this] (
     1037                Arg::Width width, const Arg& relCond,
     1038                const ArgPromise& left, const ArgPromise& right) -> Inst {
     1039                switch (width) {
     1040                case Arg::Width8:
     1041                    if (isValidForm(Branch8, Arg::RelCond, left.kind(), right.kind())) {
     1042                        return Inst(
     1043                            Branch8, currentValue, relCond,
     1044                            left.consume(*this), right.consume(*this));
     1045                    }
     1046                    return Inst();
     1047                case Arg::Width16:
     1048                    return Inst();
     1049                case Arg::Width32:
     1050                    if (isValidForm(Branch32, Arg::RelCond, left.kind(), right.kind())) {
     1051                        return Inst(
     1052                            Branch32, currentValue, relCond,
     1053                            left.consume(*this), right.consume(*this));
     1054                    }
     1055                    return Inst();
     1056                case Arg::Width64:
     1057                    if (isValidForm(Branch64, Arg::RelCond, left.kind(), right.kind())) {
     1058                        return Inst(
     1059                            Branch64, currentValue, relCond,
     1060                            left.consume(*this), right.consume(*this));
     1061                    }
     1062                    return Inst();
     1063                }
     1064            },
     1065            [this] (
     1066                Arg::Width width, const Arg& resCond,
     1067                const ArgPromise& left, const ArgPromise& right) -> Inst {
     1068                switch (width) {
     1069                case Arg::Width8:
     1070                    if (isValidForm(BranchTest8, Arg::ResCond, left.kind(), right.kind())) {
     1071                        return Inst(
     1072                            BranchTest8, currentValue, resCond,
     1073                            left.consume(*this), right.consume(*this));
     1074                    }
     1075                    return Inst();
     1076                case Arg::Width16:
     1077                    return Inst();
     1078                case Arg::Width32:
     1079                    if (isValidForm(BranchTest32, Arg::ResCond, left.kind(), right.kind())) {
     1080                        return Inst(
     1081                            BranchTest32, currentValue, resCond,
     1082                            left.consume(*this), right.consume(*this));
     1083                    }
     1084                    return Inst();
     1085                case Arg::Width64:
     1086                    if (isValidForm(BranchTest64, Arg::ResCond, left.kind(), right.kind())) {
     1087                        return Inst(
     1088                            BranchTest64, currentValue, resCond,
     1089                            left.consume(*this), right.consume(*this));
     1090                    }
     1091                    return Inst();
     1092                }
     1093            },
     1094            [this] (Arg doubleCond, const ArgPromise& left, const ArgPromise& right) -> Inst {
     1095                if (isValidForm(BranchDouble, Arg::DoubleCond, left.kind(), right.kind())) {
     1096                    return Inst(
     1097                        BranchDouble, currentValue, doubleCond,
     1098                        left.consume(*this), right.consume(*this));
     1099                }
     1100                return Inst();
     1101            },
     1102            inverted);
     1103    }
     1104
     1105    Inst createCompare(Value* value, bool inverted = false)
     1106    {
     1107        return createGenericCompare(
     1108            value,
     1109            [this] (
     1110                Arg::Width width, const Arg& relCond,
     1111                const ArgPromise& left, const ArgPromise& right) -> Inst {
     1112                switch (width) {
     1113                case Arg::Width8:
     1114                case Arg::Width16:
     1115                    return Inst();
     1116                case Arg::Width32:
     1117                    if (isValidForm(Compare32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) {
     1118                        return Inst(
     1119                            Compare32, currentValue, relCond,
     1120                            left.consume(*this), right.consume(*this), tmp(currentValue));
     1121                    }
     1122                    return Inst();
     1123                case Arg::Width64:
     1124                    if (isValidForm(Compare64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) {
     1125                        return Inst(
     1126                            Compare64, currentValue, relCond,
     1127                            left.consume(*this), right.consume(*this), tmp(currentValue));
     1128                    }
     1129                    return Inst();
     1130                }
     1131            },
     1132            [this] (
     1133                Arg::Width width, const Arg& resCond,
     1134                const ArgPromise& left, const ArgPromise& right) -> Inst {
     1135                switch (width) {
     1136                case Arg::Width8:
     1137                case Arg::Width16:
     1138                    return Inst();
     1139                case Arg::Width32:
     1140                    if (isValidForm(Test32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) {
     1141                        return Inst(
     1142                            Test32, currentValue, resCond,
     1143                            left.consume(*this), right.consume(*this), tmp(currentValue));
     1144                    }
     1145                    return Inst();
     1146                case Arg::Width64:
     1147                    if (isValidForm(Test64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) {
     1148                        return Inst(
     1149                            Test64, currentValue, resCond,
     1150                            left.consume(*this), right.consume(*this), tmp(currentValue));
     1151                    }
     1152                    return Inst();
     1153                }
     1154            },
     1155            [this] (const Arg&, const ArgPromise&, const ArgPromise&) -> Inst {
     1156                // FIXME: Implement this.
     1157                // https://bugs.webkit.org/show_bug.cgi?id=150903
     1158                return Inst();
     1159            },
     1160            inverted);
     1161    }
     1162
    6251163    // Below is the code for a lowering selector, so that we can pass *this to runLoweringMatcher.
    6261164    // This will match complex multi-value expressions, but only if there is no sharing. For example,
     
    6711209            moveForType(currentValue->type()),
    6721210            effectiveAddr(address, currentValue), tmp(currentValue));
     1211        return true;
     1212    }
     1213
     1214    bool tryLoad8S(Value* address)
     1215    {
     1216        append(Load8SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue));
     1217        return true;
     1218    }
     1219   
     1220    bool tryLoad8Z(Value* address)
     1221    {
     1222        append(Load8, effectiveAddr(address, currentValue), tmp(currentValue));
     1223        return true;
     1224    }
     1225   
     1226    bool tryLoad16S(Value* address)
     1227    {
     1228        append(Load16SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue));
     1229        return true;
     1230    }
     1231   
     1232    bool tryLoad16Z(Value* address)
     1233    {
     1234        append(Load16, effectiveAddr(address, currentValue), tmp(currentValue));
    6731235        return true;
    6741236    }
     
    8871449    }
    8881450
     1451    bool tryEqual()
     1452    {
     1453        insts.last().append(createCompare(currentValue));
     1454        return true;
     1455    }
     1456
     1457    bool tryNotEqual()
     1458    {
     1459        insts.last().append(createCompare(currentValue));
     1460        return true;
     1461    }
     1462
     1463    bool tryLessThan()
     1464    {
     1465        insts.last().append(createCompare(currentValue));
     1466        return true;
     1467    }
     1468
     1469    bool tryGreaterThan()
     1470    {
     1471        insts.last().append(createCompare(currentValue));
     1472        return true;
     1473    }
     1474
     1475    bool tryLessEqual()
     1476    {
     1477        insts.last().append(createCompare(currentValue));
     1478        return true;
     1479    }
     1480
     1481    bool tryGreaterEqual()
     1482    {
     1483        insts.last().append(createCompare(currentValue));
     1484        return true;
     1485    }
     1486
     1487    bool tryAbove()
     1488    {
     1489        insts.last().append(createCompare(currentValue));
     1490        return true;
     1491    }
     1492
     1493    bool tryBelow()
     1494    {
     1495        insts.last().append(createCompare(currentValue));
     1496        return true;
     1497    }
     1498
     1499    bool tryAboveEqual()
     1500    {
     1501        insts.last().append(createCompare(currentValue));
     1502        return true;
     1503    }
     1504
     1505    bool tryBelowEqual()
     1506    {
     1507        insts.last().append(createCompare(currentValue));
     1508        return true;
     1509    }
     1510
    8891511    PatchpointSpecial* patchpointSpecial { nullptr };
    8901512    bool tryPatchpoint()
     
    9041526    }
    9051527
    906     CheckSpecial* checkBranchTest32Special { nullptr };
    907     CheckSpecial* checkBranchTest64Special { nullptr };
     1528    HashMap<CheckSpecial::Key, CheckSpecial*> checkSpecials;
    9081529    bool tryCheck(Value* value)
    9091530    {
    910         if (!isInt(value->type())) {
    911             // FIXME: Implement double branches.
    912             // https://bugs.webkit.org/show_bug.cgi?id=150727
    913             return false;
    914         }
    915 
    916         CheckSpecial* special;
    917         switch (value->type()) {
    918         case Int32:
    919             special = ensureSpecial(checkBranchTest32Special, BranchTest32, 3);
    920             break;
    921         case Int64:
    922             special = ensureSpecial(checkBranchTest64Special, BranchTest64, 3);
    923             break;
    924         default:
    925             RELEASE_ASSERT_NOT_REACHED();
    926             break;
    927         }
     1531        Inst branch = createBranch(value);
     1532
     1533        CheckSpecial::Key key(branch);
     1534        auto result = checkSpecials.add(key, nullptr);
     1535        Special* special = ensureSpecial(result.iterator->value, key);
    9281536
    9291537        CheckValue* checkValue = currentValue->as<CheckValue>();
    9301538
    931         Inst inst(
    932             Patch, checkValue, Arg::special(special),
    933             Arg::resCond(MacroAssembler::NonZero), tmp(value), Arg::imm(-1));
     1539        Inst inst(Patch, checkValue, Arg::special(special));
     1540        inst.args.appendVector(branch.args);
    9341541
    9351542        fillStackmap(inst, checkValue, 1);
     
    9561563    bool tryBranch(Value* value)
    9571564    {
    958         // FIXME: Implement branch fusion by delegating to a pattern matcher for comparisons.
    959         // https://bugs.webkit.org/show_bug.cgi?id=150721
    960 
    961         // In B3 it's possible to branch on any value. The semantics of:
    962         //
    963         //     Branch(value)
    964         //
    965         // Are guaranteed to be identical to:
    966         //
    967         //     Branch(NotEqual(value, 0))
    968 
    969         if (!isInt(value->type())) {
    970             // FIXME: Implement double branches.
    971             // https://bugs.webkit.org/show_bug.cgi?id=150727
    972             return false;
    973         }
    974 
    975         Air::Opcode opcode;
    976         switch (value->type()) {
    977         case Int32:
    978             opcode = BranchTest32;
    979             break;
    980         case Int64:
    981             opcode = BranchTest64;
    982             break;
    983         default:
    984             RELEASE_ASSERT_NOT_REACHED();
    985             break;
    986         }
    987 
    988         Arg resCond = Arg::resCond(MacroAssembler::NonZero);
    989 
    990         Arg addr = loadAddr(value);
    991         if (isValidForm(opcode, resCond.kind(), addr.kind(), Arg::Imm)) {
    992             commitInternal(value);
    993             append(opcode, resCond, addr, Arg::imm(-1));
    994             return true;
    995         }
    996 
    997         append(opcode, resCond, tmp(value), Arg::imm(-1));
     1565        insts.last().append(createBranch(value));
    9981566        return true;
    9991567    }
  • trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns

    r192051 r192072  
    3131Load = Load(address)
    3232
     33Load8S = Load8S(address)
     34Load8Z = Load8Z(address)
     35Load16S = Load16S(address)
     36Load16Z = Load16Z(address)
     37
    3338Add = Add(left, right)
    3439Sub = Sub(left, right)
     
    5863FramePointer = FramePointer()
    5964
     65# These patterns delegate to the comparison matcher.
     66Equal = Equal()
     67NotEqual = NotEqual()
     68LessThan = LessThan()
     69GreaterThan = GreaterThan()
     70LessEqual = LessEqual()
     71GreaterEqual = GreaterEqual()
     72Above = Above()
     73Below = Below()
     74AboveEqual = AboveEqual()
     75BelowEqual = BelowEqual()
     76
    6077Patchpoint = Patchpoint()
    6178Check = Check(value)
  • trunk/Source/JavaScriptCore/b3/B3Opcode.cpp

    r191705 r192072  
    3131#include <wtf/PrintStream.h>
    3232
     33namespace JSC { namespace B3 {
     34
     35Optional<Opcode> invertedCompare(Opcode opcode, Type type)
     36{
     37    switch (opcode) {
     38    case Equal:
     39        return NotEqual;
     40    case NotEqual:
     41        return Equal;
     42    case LessThan:
     43        if (isInt(type))
     44            return GreaterEqual;
     45        return Nullopt;
     46    case GreaterThan:
     47        if (isInt(type))
     48            return LessEqual;
     49        return Nullopt;
     50    case LessEqual:
     51        if (isInt(type))
     52            return GreaterThan;
     53        return Nullopt;
     54    case GreaterEqual:
     55        if (isInt(type))
     56            return LessThan;
     57        return Nullopt;
     58    case Above:
     59        return BelowEqual;
     60    case Below:
     61        return AboveEqual;
     62    case AboveEqual:
     63        return Below;
     64    case BelowEqual:
     65        return Above;
     66    default:
     67        return Nullopt;
     68    }
     69}
     70
     71} } // namespace JSC::B3
     72
    3373namespace WTF {
    3474
  • trunk/Source/JavaScriptCore/b3/B3Opcode.h

    r192051 r192072  
    2929#if ENABLE(B3_JIT)
    3030
     31#include "B3Type.h"
     32#include <wtf/Optional.h>
    3133#include <wtf/StdLibExtras.h>
    3234
     
    167169
    168170    // Check that side-exits. Use the CheckValue class. Like CheckAdd and friends, this has a
    169     // stackmap with a generation callback. This takes an Int32 argument that this branches on, with
     171    // stackmap with a generation callback. This takes an int argument that this branches on, with
    170172    // full branch fusion in the instruction selector. A true value jumps to the generator's slow
    171173    // path.
     
    179181    Jump,
    180182   
    181     // Polymorphic branch, usable with any value type. Branches if not equal to zero. Uses the
     183    // Polymorphic branch, usable with any integer type. Branches if not equal to zero. Uses the
    182184    // ControlValue class, with the 0-index successor being the true successor.
    183185    Branch,
     
    206208}
    207209
     210Optional<Opcode> invertedCompare(Opcode, Type);
     211
    208212} } // namespace JSC::B3
    209213
  • trunk/Source/JavaScriptCore/b3/B3Procedure.cpp

    r191816 r192072  
    5151    m_blocks.append(WTF::move(block));
    5252    return result;
     53}
     54
     55Value* Procedure::addIntConstant(Type type, int64_t value)
     56{
     57    switch (type) {
     58    case Int32:
     59        return add<Const32Value>(Origin(), static_cast<int32_t>(value));
     60    case Int64:
     61        return add<Const64Value>(Origin(), value);
     62    case Double:
     63        return add<ConstDoubleValue>(Origin(), static_cast<double>(value));
     64    default:
     65        RELEASE_ASSERT_NOT_REACHED();
     66        return nullptr;
     67    }
     68}
     69
     70Value* Procedure::addBoolConstant(TriState triState)
     71{
     72    int32_t value = 0;
     73    switch (triState) {
     74    case FalseTriState:
     75        value = 0;
     76        break;
     77    case TrueTriState:
     78        value = 1;
     79        break;
     80    case MixedTriState:
     81        return nullptr;
     82    }
     83
     84    return addIntConstant(Int32, value);
    5385}
    5486
  • trunk/Source/JavaScriptCore/b3/B3Procedure.h

    r191762 r192072  
    2929#if ENABLE(B3_JIT)
    3030
     31#include "B3Type.h"
    3132#include "PureNaN.h"
    3233#include <wtf/Bag.h>
     
    3435#include <wtf/Noncopyable.h>
    3536#include <wtf/PrintStream.h>
     37#include <wtf/TriState.h>
    3638#include <wtf/Vector.h>
    3739
     
    5355    template<typename ValueType, typename... Arguments>
    5456    ValueType* add(Arguments...);
     57
     58    Value* addIntConstant(Type, int64_t value);
     59
     60    // Returns null for MixedTriState.
     61    Value* addBoolConstant(TriState);
    5562
    5663    void resetValueOwners();
  • trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp

    r192051 r192072  
    4444namespace {
    4545
     46// The goal of this phase is to:
     47//
     48// - Replace operations with less expensive variants. This includes constant folding and classic
     49//   strength reductions like turning Mul(x, 1 << k) into Shl(x, k).
     50//
     51// - Reassociate constant operations. For example, Load(Add(x, c)) is turned into Load(x, offset = c)
     52//   and Add(Add(x, c), d) is turned into Add(x, c + d).
     53//
     54// - Canonicalize operations. There are some cases where it's not at all obvious which kind of
     55//   operation is less expensive, but it's useful for subsequent phases - particularly LowerToAir -
     56//   to have only one way of representing things.
     57//
     58// This phase runs to fixpoint. Therefore, the canonicalizations must be designed to be monotonic.
     59// For example, if we had a canonicalization that said that Add(x, -c) should be Sub(x, c) and
     60// another canonicalization that said that Sub(x, d) should be Add(x, -d), then this phase would end
     61// up running forever. We don't want that.
     62//
     63// Therefore, we need to prioritize certain canonical forms over others. Naively, we want strength
     64// reduction to reduce the number of values, and so a form involving fewer total values is more
     65// canonical. But we might break this, for example when reducing strength of Mul(x, 9). This could be
     66// better written as Add(Shl(x, 3), x), which also happens to be representable using a single
     67// instruction on x86.
     68//
     69// Here are some of the rules we have:
     70//
     71// Canonical form of logical not: BitXor(value, 1). We may have to avoid using this form if we don't
     72// know for sure that 'value' is 0-or-1 (i.e. returnsBool). In that case we fall back on
     73// Equal(value, 0).
     74//
     75// Canonical form of commutative operations: if the operation involves a constant, the constant must
     76// come second. Add(x, constant) is canonical, while Add(constant, x) is not. If there are no
     77// constants then the canonical form involves the lower-indexed value first. Given Add(x, y), it's
     78// canonical if x->index() <= y->index().
     79
     80bool verbose = false;
     81
    4682class ReduceStrength {
    4783public:
     
    5591    {
    5692        bool result = false;
     93        unsigned index = 0;
    5794        do {
    5895            m_changed = false;
    5996            m_changedCFG = false;
     97
     98            if (verbose) {
     99                dataLog("Reduce strength IR before iteration #", ++index, "\n");
     100                dataLog(m_proc);
     101            }
    60102
    61103            for (BasicBlock* block : m_proc.blocksInPreOrder()) {
     
    258300            }
    259301
     302            // Turn this: BitXor(compare, 1)
     303            // Into this: invertedCompare
     304            if (m_value->child(1)->isInt32(1)) {
     305                if (Value* invertedCompare = m_value->child(0)->invertedCompare(m_proc)) {
     306                    replaceWithNewValue(invertedCompare);
     307                    break;
     308                }
     309            }
     310
    260311            // Turn this: BitXor(valueX, valueX)
    261312            // Into this: zero-constant.
    262313            if (m_value->child(0) == m_value->child(1)) {
    263                 Value* zeroConstant;
    264                 if (m_value->type() == Int32)
    265                     zeroConstant = m_proc.add<Const32Value>(m_value->origin(), 0);
    266                 else if (m_value->type() == Int64)
    267                     zeroConstant = m_proc.add<Const64Value>(m_value->origin(), 0);
    268                 else {
    269                     RELEASE_ASSERT(m_value->type() == Double);
    270                     zeroConstant = m_proc.add<ConstDoubleValue>(m_value->origin(), 0);
    271                 }
    272                 replaceWithNewValue(zeroConstant);
     314                replaceWithNewValue(m_proc.addIntConstant(m_value->type(), 0));
    273315                break;
    274316            }
     
    378420            handleCommutativity();
    379421
    380             // Turn this: Equal(Equal(x, 0), 0)
    381             // Into this: NotEqual(x, 0)
    382             if (m_value->child(0)->opcode() == Equal && m_value->child(1)->isInt32(0)
    383                 && m_value->child(0)->child(1)->isLikeZero()) {
     422            // Turn this: Equal(bool, 0)
     423            // Into this: BitXor(bool, 1)
     424            if (m_value->child(0)->returnsBool() && m_value->child(1)->isInt32(0)) {
    384425                replaceWithNew<Value>(
    385                     NotEqual, m_value->origin(),
    386                     m_value->child(0)->child(0), m_value->child(0)->child(1));
    387                 break;
    388             }
    389 
     426                    BitXor, m_value->origin(), m_value->child(0),
     427                    m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), 1));
     428                break;
     429            }
     430           
    390431            // Turn this Equal(bool, 1)
    391432            // Into this: bool
     
    396437            }
    397438
    398             // FIXME: Have a compare-flipping optimization, like Equal(LessThan(a, b), 0) turns into
    399             // GreaterEqual(a, b).
    400             // https://bugs.webkit.org/show_bug.cgi?id=150726
    401 
    402439            // Turn this: Equal(const1, const2)
    403440            // Into this: const1 == const2
    404             replaceWithNewValue(m_value->child(0)->equalConstant(m_proc, m_value->child(1)));
     441            replaceWithNewValue(
     442                m_proc.addBoolConstant(m_value->child(0)->equalConstant(m_value->child(1))));
    405443            break;
    406444           
     
    428466            // Turn this: NotEqual(const1, const2)
    429467            // Into this: const1 != const2
    430             replaceWithNewValue(m_value->child(0)->notEqualConstant(m_proc, m_value->child(1)));
     468            replaceWithNewValue(
     469                m_proc.addBoolConstant(m_value->child(0)->notEqualConstant(m_value->child(1))));
     470            break;
     471
     472        case LessThan:
     473            replaceWithNewValue(
     474                m_proc.addBoolConstant(m_value->child(0)->lessThanConstant(m_value->child(1))));
     475            break;
     476
     477        case GreaterThan:
     478            replaceWithNewValue(
     479                m_proc.addBoolConstant(m_value->child(0)->greaterThanConstant(m_value->child(1))));
     480            break;
     481
     482        case LessEqual:
     483            replaceWithNewValue(
     484                m_proc.addBoolConstant(m_value->child(0)->lessEqualConstant(m_value->child(1))));
     485            break;
     486
     487        case GreaterEqual:
     488            replaceWithNewValue(
     489                m_proc.addBoolConstant(m_value->child(0)->greaterEqualConstant(m_value->child(1))));
     490            break;
     491
     492        case Above:
     493            replaceWithNewValue(
     494                m_proc.addBoolConstant(m_value->child(0)->aboveConstant(m_value->child(1))));
     495            break;
     496
     497        case Below:
     498            replaceWithNewValue(
     499                m_proc.addBoolConstant(m_value->child(0)->belowConstant(m_value->child(1))));
     500            break;
     501
     502        case AboveEqual:
     503            replaceWithNewValue(
     504                m_proc.addBoolConstant(m_value->child(0)->aboveEqualConstant(m_value->child(1))));
     505            break;
     506
     507        case BelowEqual:
     508            replaceWithNewValue(
     509                m_proc.addBoolConstant(m_value->child(0)->belowEqualConstant(m_value->child(1))));
    431510            break;
    432511
     
    436515            // Turn this: Branch(NotEqual(x, 0))
    437516            // Into this: Branch(x)
    438             if (branch->child(0)->opcode() == NotEqual && branch->child(0)->child(1)->isLikeZero()) {
     517            if (branch->child(0)->opcode() == NotEqual && branch->child(0)->child(1)->isInt(0)) {
    439518                branch->child(0) = branch->child(0)->child(0);
    440519                m_changed = true;
     
    443522            // Turn this: Branch(Equal(x, 0), then, else)
    444523            // Into this: Branch(x, else, then)
    445             if (branch->child(0)->opcode() == Equal && branch->child(0)->child(1)->isLikeZero()) {
     524            if (branch->child(0)->opcode() == Equal && branch->child(0)->child(1)->isInt(0)) {
     525                branch->child(0) = branch->child(0)->child(0);
     526                std::swap(branch->taken(), branch->notTaken());
     527                m_changed = true;
     528            }
     529           
     530            // Turn this: Branch(BitXor(bool, 1), then, else)
     531            // Into this: Branch(bool, else, then)
     532            if (branch->child(0)->opcode() == BitXor
     533                && branch->child(0)->child(1)->isInt32(1)
     534                && branch->child(0)->child(0)->returnsBool()) {
    446535                branch->child(0) = branch->child(0)->child(0);
    447536                std::swap(branch->taken(), branch->notTaken());
  • trunk/Source/JavaScriptCore/b3/B3Validate.cpp

    r191993 r192072  
    280280                break;
    281281            case Check:
     282                VALIDATE(value->numChildren() >= 1, ("At ", *value));
     283                VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
     284                VALIDATE(value->as<StackmapValue>()->constrainedChild(0).rep() == ValueRep::Any, ("At ", *value));
    282285                validateStackmap(value);
    283286                break;
     
    292295                VALIDATE(value->type() != Void, ("At ", *value));
    293296                break;
     297            case Return:
     298                VALIDATE(value->numChildren() == 1, ("At ", *value));
     299                VALIDATE(value->type() == Void, ("At ", *value));
     300                break;
    294301            case Branch:
    295             case Return:
    296                 VALIDATE(value->numChildren() == 1, ("At ", *value));
    297                 VALIDATE(value->type() == Void, ("At ", *value));
    298                 break;
    299302            case Switch:
    300303                VALIDATE(value->numChildren() == 1, ("At ", *value));
  • trunk/Source/JavaScriptCore/b3/B3Value.cpp

    r192051 r192072  
    3333#include "B3ControlValue.h"
    3434#include "B3MemoryValue.h"
     35#include "B3ProcedureInlines.h"
    3536#include "B3StackSlotValue.h"
    3637#include "B3UpsilonValue.h"
     
    163164}
    164165
    165 Value* Value::equalConstant(Procedure&, Value*) const
    166 {
    167     return nullptr;
    168 }
    169 
    170 Value* Value::notEqualConstant(Procedure&, Value*) const
    171 {
     166TriState Value::equalConstant(Value*) const
     167{
     168    return MixedTriState;
     169}
     170
     171TriState Value::notEqualConstant(Value*) const
     172{
     173    return MixedTriState;
     174}
     175
     176TriState Value::lessThanConstant(Value*) const
     177{
     178    return MixedTriState;
     179}
     180
     181TriState Value::greaterThanConstant(Value*) const
     182{
     183    return MixedTriState;
     184}
     185
     186TriState Value::lessEqualConstant(Value*) const
     187{
     188    return MixedTriState;
     189}
     190
     191TriState Value::greaterEqualConstant(Value*) const
     192{
     193    return MixedTriState;
     194}
     195
     196TriState Value::aboveConstant(Value*) const
     197{
     198    return MixedTriState;
     199}
     200
     201TriState Value::belowConstant(Value*) const
     202{
     203    return MixedTriState;
     204}
     205
     206TriState Value::aboveEqualConstant(Value*) const
     207{
     208    return MixedTriState;
     209}
     210
     211TriState Value::belowEqualConstant(Value*) const
     212{
     213    return MixedTriState;
     214}
     215
     216Value* Value::invertedCompare(Procedure& proc) const
     217{
     218    if (!numChildren())
     219        return nullptr;
     220    if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type()))
     221        return proc.add<Value>(*invertedOpcode, type(), origin(), children());
    172222    return nullptr;
    173223}
  • trunk/Source/JavaScriptCore/b3/B3Value.h

    r192051 r192072  
    119119    virtual Value* sShrConstant(Procedure&, Value* other) const;
    120120    virtual Value* zShrConstant(Procedure&, Value* other) const;
    121     virtual Value* equalConstant(Procedure&, Value* other) const;
    122     virtual Value* notEqualConstant(Procedure&, Value* other) const;
     121   
     122    virtual TriState equalConstant(Value* other) const;
     123    virtual TriState notEqualConstant(Value* other) const;
     124    virtual TriState lessThanConstant(Value* other) const;
     125    virtual TriState greaterThanConstant(Value* other) const;
     126    virtual TriState lessEqualConstant(Value* other) const;
     127    virtual TriState greaterEqualConstant(Value* other) const;
     128    virtual TriState aboveConstant(Value* other) const;
     129    virtual TriState belowConstant(Value* other) const;
     130    virtual TriState aboveEqualConstant(Value* other) const;
     131    virtual TriState belowEqualConstant(Value* other) const;
     132
     133    // If the value is a comparison then this returns the inverted form of that comparison, if
     134    // possible. It can be impossible for double comparisons, where for example LessThan and
     135    // GreaterEqual behave differently. If this returns a value, it is a new value, which must be
     136    // either inserted into some block or deleted.
     137    Value* invertedCompare(Procedure&) const;
    123138
    124139    bool hasInt32() const;
  • trunk/Source/JavaScriptCore/b3/air/AirArg.cpp

    r191952 r192072  
    3434namespace JSC { namespace B3 { namespace Air {
    3535
     36bool Arg::isRepresentableAs(Width width, Signedness signedness) const
     37{
     38    switch (signedness) {
     39    case Signed:
     40        switch (width) {
     41        case Width8:
     42            return isRepresentableAs<int8_t>();
     43        case Width16:
     44            return isRepresentableAs<int16_t>();
     45        case Width32:
     46            return isRepresentableAs<int32_t>();
     47        case Width64:
     48            return isRepresentableAs<int64_t>();
     49        }
     50    case Unsigned:
     51        switch (width) {
     52        case Width8:
     53            return isRepresentableAs<uint8_t>();
     54        case Width16:
     55            return isRepresentableAs<uint16_t>();
     56        case Width32:
     57            return isRepresentableAs<uint32_t>();
     58        case Width64:
     59            return isRepresentableAs<uint64_t>();
     60        }
     61    }
     62}
     63
    3664void Arg::dump(PrintStream& out) const
    3765{
     
    91119} } } // namespace JSC::B3::Air
    92120
     121namespace WTF {
     122
     123using namespace JSC::B3::Air;
     124
     125void printInternal(PrintStream& out, Arg::Kind kind)
     126{
     127    switch (kind) {
     128    case Arg::Invalid:
     129        out.print("Invalid");
     130        return;
     131    case Arg::Tmp:
     132        out.print("Tmp");
     133        return;
     134    case Arg::Imm:
     135        out.print("Imm");
     136        return;
     137    case Arg::Imm64:
     138        out.print("Imm64");
     139        return;
     140    case Arg::Addr:
     141        out.print("Addr");
     142        return;
     143    case Arg::Stack:
     144        out.print("Stack");
     145        return;
     146    case Arg::CallArg:
     147        out.print("CallArg");
     148        return;
     149    case Arg::Index:
     150        out.print("Index");
     151        return;
     152    case Arg::RelCond:
     153        out.print("RelCond");
     154        return;
     155    case Arg::ResCond:
     156        out.print("ResCond");
     157        return;
     158    case Arg::DoubleCond:
     159        out.print("DoubleCond");
     160        return;
     161    case Arg::Special:
     162        out.print("Special");
     163        return;
     164    }
     165
     166    RELEASE_ASSERT_NOT_REACHED();
     167}
     168
     169void printInternal(PrintStream& out, Arg::Role role)
     170{
     171    switch (role) {
     172    case Arg::Use:
     173        out.print("Use");
     174        return;
     175    case Arg::Def:
     176        out.print("Def");
     177        return;
     178    case Arg::UseDef:
     179        out.print("UseDef");
     180        return;
     181    case Arg::UseAddr:
     182        out.print("UseAddr");
     183        return;
     184    }
     185
     186    RELEASE_ASSERT_NOT_REACHED();
     187}
     188
     189void printInternal(PrintStream& out, Arg::Type type)
     190{
     191    switch (type) {
     192    case Arg::GP:
     193        out.print("GP");
     194        return;
     195    case Arg::FP:
     196        out.print("FP");
     197        return;
     198    }
     199
     200    RELEASE_ASSERT_NOT_REACHED();
     201}
     202
     203void printInternal(PrintStream& out, Arg::Width width)
     204{
     205    switch (width) {
     206    case Arg::Width8:
     207        out.print("Width8");
     208        return;
     209    case Arg::Width16:
     210        out.print("Width16");
     211        return;
     212    case Arg::Width32:
     213        out.print("Width32");
     214        return;
     215    case Arg::Width64:
     216        out.print("Width64");
     217        return;
     218    }
     219
     220    RELEASE_ASSERT_NOT_REACHED();
     221}
     222
     223void printInternal(PrintStream& out, Arg::Signedness signedness)
     224{
     225    switch (signedness) {
     226    case Arg::Signed:
     227        out.print("Signed");
     228        return;
     229    case Arg::Unsigned:
     230        out.print("Unsigned");
     231        return;
     232    }
     233
     234    RELEASE_ASSERT_NOT_REACHED();
     235}
     236
     237} // namespace WTF
     238
    93239#endif // ENABLE(B3_JIT)
  • trunk/Source/JavaScriptCore/b3/air/AirArg.h

    r191957 r192072  
    111111    static const unsigned numTypes = 2;
    112112
     113    enum Width : int8_t {
     114        Width8,
     115        Width16,
     116        Width32,
     117        Width64
     118    };
     119
     120    enum Signedness : int8_t {
     121        Signed,
     122        Unsigned
     123    };
     124
    113125    // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for
    114126    // UseAddr, since isUse() for an Arg::addr means that we are loading from the address.
     
    152164        ASSERT_NOT_REACHED();
    153165        return GP;
     166    }
     167
     168    static Width widthForB3Type(B3::Type type)
     169    {
     170        switch (type) {
     171        case Void:
     172            ASSERT_NOT_REACHED();
     173            return Width8;
     174        case Int32:
     175            return Width32;
     176        case Int64:
     177        case Double:
     178            return Width64;
     179        }
    154180    }
    155181
     
    375401        ASSERT(kind() == Imm || kind() == Imm64);
    376402        return m_offset;
     403    }
     404
     405    template<typename T>
     406    bool isRepresentableAs() const
     407    {
     408        return B3::isRepresentableAs<T>(value());
     409    }
     410
     411    bool isRepresentableAs(Width, Signedness) const;
     412
     413    template<typename T>
     414    T asNumber() const
     415    {
     416        return static_cast<T>(value());
    377417    }
    378418
     
    685725    }
    686726
     727    // This is valid for condition arguments. It will invert them.
     728    Arg inverted(bool inverted = true) const
     729    {
     730        if (!inverted)
     731            return *this;
     732        switch (kind()) {
     733        case RelCond:
     734            return relCond(MacroAssembler::invert(asRelationalCondition()));
     735        case ResCond:
     736            return resCond(MacroAssembler::invert(asResultCondition()));
     737        case DoubleCond:
     738            return doubleCond(MacroAssembler::invert(asDoubleCondition()));
     739        default:
     740            RELEASE_ASSERT_NOT_REACHED();
     741            return Arg();
     742        }
     743    }
     744
     745    Arg flipped(bool flipped = true) const
     746    {
     747        if (!flipped)
     748            return Arg();
     749        return relCond(MacroAssembler::flip(asRelationalCondition()));
     750    }
     751
     752    bool isSignedCond() const
     753    {
     754        return isRelCond() && MacroAssembler::isSigned(asRelationalCondition());
     755    }
     756
     757    bool isUnsignedCond() const
     758    {
     759        return isRelCond() && MacroAssembler::isUnsigned(asRelationalCondition());
     760    }
     761
    687762    void dump(PrintStream&) const;
    688763
     
    722797namespace WTF {
    723798
     799void printInternal(PrintStream&, JSC::B3::Air::Arg::Kind);
     800void printInternal(PrintStream&, JSC::B3::Air::Arg::Role);
     801void printInternal(PrintStream&, JSC::B3::Air::Arg::Type);
     802void printInternal(PrintStream&, JSC::B3::Air::Arg::Width);
     803void printInternal(PrintStream&, JSC::B3::Air::Arg::Signedness);
     804
    724805template<typename T> struct DefaultHash;
    725806template<> struct DefaultHash<JSC::B3::Air::Arg> {
  • trunk/Source/JavaScriptCore/b3/air/AirInst.h

    r191846 r192072  
    8484    }
    8585
     86    explicit operator bool() const { return origin || opcode != Nop || args.size(); }
     87
    8688    // Note that these functors all avoid using "const" because we want to use them for things that
    8789    // edit IR. IR is meant to be edited; if you're carrying around a "const Inst&" then you're
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r192051 r192072  
    198198    Tmp, Tmp
    199199
     200Load8 U:G, D:G
     201    Addr, Tmp
     202    Index, Tmp
     203
     204Load8SignedExtendTo32 U:G, D:G
     205    Addr, Tmp
     206    Index, Tmp
     207
     208Load16 U:G, D:G
     209    Addr, Tmp
     210    Index, Tmp
     211
     212Load16SignedExtendTo32 U:G, D:G
     213    Addr, Tmp
     214    Index, Tmp
     215
     216Compare32 U:G, U:G, U:G, D:G
     217    RelCond, Tmp, Tmp, Tmp
     218    RelCond, Tmp, Imm, Tmp
     219
     220Compare64 U:G, U:G, U:G, D:G
     221    RelCond, Tmp, Imm, Tmp
     222    RelCond, Tmp, Tmp, Tmp
     223
     224Test32 U:G, U:G, U:G, D:G
     225    ResCond, Addr, Imm, Tmp
     226    ResCond, Tmp, Tmp, Tmp
     227
     228Test64 U:G, U:G, U:G, D:G
     229    ResCond, Tmp, Imm, Tmp
     230    ResCond, Tmp, Tmp, Tmp
     231
     232Branch8 U:G, U:G, U:G /branch
     233    RelCond, Addr, Imm
     234    RelCond, Index, Imm
     235
     236Branch32 U:G, U:G, U:G /branch
     237    RelCond, Addr, Imm
     238    RelCond, Tmp, Tmp
     239    RelCond, Tmp, Imm
     240    RelCond, Tmp, Addr
     241    RelCond, Addr, Tmp
     242    RelCond, Index, Imm
     243
     244Branch64 U:G, U:G, U:G /branch
     245    RelCond, Tmp, Tmp
     246    RelCond, Tmp, Addr
     247    RelCond, Addr, Tmp
     248    RelCond, Index, Tmp
     249
     250BranchTest8 U:G, U:G, U:G /branch
     251    ResCond, Addr, Imm
     252    ResCond, Index, Imm
     253
    200254BranchTest32 U:G, U:G, U:G /branch
    201255    ResCond, Tmp, Tmp
     
    204258    ResCond, Index, Imm
    205259
     260# Warning: forms that take an immediate will sign-extend their immediate. You probably want
     261# BranchTest32 in most cases where you use an immediate.
    206262BranchTest64 U:G, U:G, U:G /branch
    207263    ResCond, Tmp, Tmp
  • trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb

    r191846 r192072  
    411411
    412412    if columnIndex >= forms[0].kinds.length
    413         raise unless forms.length == 1
     413        raise "Did not reduce to one form: #{forms.inspect}" unless forms.length == 1
    414414        callback[forms[0]]
    415415        return
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r192051 r192072  
    4242#include "LinkBuffer.h"
    4343#include "VM.h"
     44#include <wtf/Lock.h>
     45#include <wtf/NumberOfCores.h>
     46#include <wtf/Threading.h>
    4447
    4548// We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
     
    17051708
    17061709    CHECK(compileAndRun<int>(proc, value) == value);
     1710}
     1711
     1712template<typename T>
     1713int32_t modelLoad(int32_t value)
     1714{
     1715    union {
     1716        int32_t original;
     1717        T loaded;
     1718    } u;
     1719
     1720    u.original = value;
     1721    if (std::is_signed<T>::value)
     1722        return static_cast<int32_t>(u.loaded);
     1723    return static_cast<int32_t>(static_cast<uint32_t>(u.loaded));
     1724}
     1725
     1726template<typename T>
     1727void testLoad(B3::Opcode opcode, int32_t value)
     1728{
     1729    // Simple load from an absolute address.
     1730    {
     1731        Procedure proc;
     1732        BasicBlock* root = proc.addBlock();
     1733       
     1734        root->appendNew<ControlValue>(
     1735            proc, Return, Origin(),
     1736            root->appendNew<MemoryValue>(
     1737                proc, opcode, Int32, Origin(),
     1738                root->appendNew<ConstPtrValue>(proc, Origin(), &value)));
     1739
     1740        CHECK(compileAndRun<int32_t>(proc) == modelLoad<T>(value));
     1741    }
     1742   
     1743    // Simple load from an address in a register.
     1744    {
     1745        Procedure proc;
     1746        BasicBlock* root = proc.addBlock();
     1747       
     1748        root->appendNew<ControlValue>(
     1749            proc, Return, Origin(),
     1750            root->appendNew<MemoryValue>(
     1751                proc, opcode, Int32, Origin(),
     1752                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
     1753
     1754        CHECK(compileAndRun<int32_t>(proc, &value) == modelLoad<T>(value));
     1755    }
     1756   
     1757    // Simple load from an address in a register, at an offset.
     1758    {
     1759        Procedure proc;
     1760        BasicBlock* root = proc.addBlock();
     1761       
     1762        root->appendNew<ControlValue>(
     1763            proc, Return, Origin(),
     1764            root->appendNew<MemoryValue>(
     1765                proc, opcode, Int32, Origin(),
     1766                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
     1767                sizeof(int32_t)));
     1768
     1769        CHECK(compileAndRun<int32_t>(proc, &value - 1) == modelLoad<T>(value));
     1770    }
     1771
     1772    // Load from a simple base-index with various scales.
     1773    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
     1774        Procedure proc;
     1775        BasicBlock* root = proc.addBlock();
     1776
     1777        root->appendNew<ControlValue>(
     1778            proc, Return, Origin(),
     1779            root->appendNew<MemoryValue>(
     1780                proc, opcode, Int32, Origin(),
     1781                root->appendNew<Value>(
     1782                    proc, Add, Origin(),
     1783                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
     1784                    root->appendNew<Value>(
     1785                        proc, Shl, Origin(),
     1786                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
     1787                        root->appendNew<Const32Value>(proc, Origin(), logScale)))));
     1788
     1789        CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value));
     1790    }
     1791
     1792    // Load from a simple base-index with various scales, but commuted.
     1793    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
     1794        Procedure proc;
     1795        BasicBlock* root = proc.addBlock();
     1796
     1797        root->appendNew<ControlValue>(
     1798            proc, Return, Origin(),
     1799            root->appendNew<MemoryValue>(
     1800                proc, opcode, Int32, Origin(),
     1801                root->appendNew<Value>(
     1802                    proc, Add, Origin(),
     1803                    root->appendNew<Value>(
     1804                        proc, Shl, Origin(),
     1805                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
     1806                        root->appendNew<Const32Value>(proc, Origin(), logScale)),
     1807                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
     1808
     1809        CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value));
     1810    }
    17071811}
    17081812
     
    22472351
    22482352    double after = monotonicallyIncreasingTimeMS();
    2249     dataLog("    That took ", after - before, " ms.\n");
     2353    dataLog(toCString("    That took ", after - before, " ms.\n"));
    22502354}
    22512355
     
    23002404}
    23012405
     2406template<typename LeftFunctor, typename RightFunctor>
     2407void genericTestCompare(
     2408    B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor,
     2409    int left, int right, int result)
     2410{
     2411    // Using a compare.
     2412    {
     2413        Procedure proc;
     2414        BasicBlock* root = proc.addBlock();
     2415
     2416        root->appendNew<ControlValue>(
     2417            proc, Return, Origin(),
     2418            root->appendNew<Value>(
     2419                proc, NotEqual, Origin(),
     2420                root->appendNew<Value>(
     2421                    proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)),
     2422                root->appendNew<Const32Value>(proc, Origin(), 0)));
     2423
     2424        CHECK(compileAndRun<int>(proc, left, right) == result);
     2425    }
     2426   
     2427    // Using a branch.
     2428    {
     2429        Procedure proc;
     2430        BasicBlock* root = proc.addBlock();
     2431        BasicBlock* thenCase = proc.addBlock();
     2432        BasicBlock* elseCase = proc.addBlock();
     2433
     2434        root->appendNew<ControlValue>(
     2435            proc, Branch, Origin(),
     2436            root->appendNew<Value>(
     2437                proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)),
     2438            FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     2439
     2440        // We use a patchpoint on the then case to ensure that this doesn't get if-converted.
     2441        PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin());
     2442        patchpoint->setGenerator(
     2443            [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     2444                CHECK(params.reps.size() == 1);
     2445                CHECK(params.reps[0].isGPR());
     2446                jit.move(CCallHelpers::TrustedImm32(1), params.reps[0].gpr());
     2447            });
     2448        thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
     2449
     2450        elseCase->appendNew<ControlValue>(
     2451            proc, Return, Origin(),
     2452            elseCase->appendNew<Const32Value>(proc, Origin(), 0));
     2453
     2454        CHECK(compileAndRun<int>(proc, left, right) == result);
     2455    }
     2456}
     2457
     2458int modelCompare(B3::Opcode opcode, int left, int right)
     2459{
     2460    switch (opcode) {
     2461    case Equal:
     2462        return left == right;
     2463    case NotEqual:
     2464        return left != right;
     2465    case LessThan:
     2466        return left < right;
     2467    case GreaterThan:
     2468        return left > right;
     2469    case LessEqual:
     2470        return left <= right;
     2471    case GreaterEqual:
     2472        return left >= right;
     2473    case Above:
     2474        return static_cast<unsigned>(left) > static_cast<unsigned>(right);
     2475    case Below:
     2476        return static_cast<unsigned>(left) < static_cast<unsigned>(right);
     2477    case AboveEqual:
     2478        return static_cast<unsigned>(left) >= static_cast<unsigned>(right);
     2479    case BelowEqual:
     2480        return static_cast<unsigned>(left) <= static_cast<unsigned>(right);
     2481    case BitAnd:
     2482        return !!(left & right);
     2483    default:
     2484        RELEASE_ASSERT_NOT_REACHED();
     2485        return 0;
     2486    }
     2487}
     2488
     2489template<typename T>
     2490void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right)
     2491{
     2492    int result = modelCompare(opcode, modelLoad<T>(left), right);
     2493   
     2494    // Test addr-to-tmp
     2495    int slot = left;
     2496    genericTestCompare(
     2497        opcode,
     2498        [&] (BasicBlock* block, Procedure& proc) {
     2499            return block->appendNew<MemoryValue>(
     2500                proc, loadOpcode, Int32, Origin(),
     2501                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     2502        },
     2503        [&] (BasicBlock* block, Procedure& proc) {
     2504            return block->appendNew<Value>(
     2505                proc, Trunc, Origin(),
     2506                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     2507        },
     2508        left, right, result);
     2509
     2510    // Test addr-to-imm
     2511    slot = left;
     2512    genericTestCompare(
     2513        opcode,
     2514        [&] (BasicBlock* block, Procedure& proc) {
     2515            return block->appendNew<MemoryValue>(
     2516                proc, loadOpcode, Int32, Origin(),
     2517                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     2518        },
     2519        [&] (BasicBlock* block, Procedure& proc) {
     2520            return block->appendNew<Const32Value>(proc, Origin(), right);
     2521        },
     2522        left, right, result);
     2523
     2524    result = modelCompare(opcode, left, modelLoad<T>(right));
     2525   
     2526    // Test tmp-to-addr
     2527    slot = right;
     2528    genericTestCompare(
     2529        opcode,
     2530        [&] (BasicBlock* block, Procedure& proc) {
     2531            return block->appendNew<Value>(
     2532                proc, Trunc, Origin(),
     2533                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     2534        },
     2535        [&] (BasicBlock* block, Procedure& proc) {
     2536            return block->appendNew<MemoryValue>(
     2537                proc, loadOpcode, Int32, Origin(),
     2538                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     2539        },
     2540        left, right, result);
     2541
     2542    // Test imm-to-addr
     2543    slot = right;
     2544    genericTestCompare(
     2545        opcode,
     2546        [&] (BasicBlock* block, Procedure& proc) {
     2547            return block->appendNew<Const32Value>(proc, Origin(), left);
     2548        },
     2549        [&] (BasicBlock* block, Procedure& proc) {
     2550            return block->appendNew<MemoryValue>(
     2551                proc, loadOpcode, Int32, Origin(),
     2552                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     2553        },
     2554        left, right, result);
     2555}
     2556
     2557void testCompareImpl(B3::Opcode opcode, int left, int right)
     2558{
     2559    int result = modelCompare(opcode, left, right);
     2560   
     2561    // Test tmp-to-tmp.
     2562    genericTestCompare(
     2563        opcode,
     2564        [&] (BasicBlock* block, Procedure& proc) {
     2565            return block->appendNew<Value>(
     2566                proc, Trunc, Origin(),
     2567                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     2568        },
     2569        [&] (BasicBlock* block, Procedure& proc) {
     2570            return block->appendNew<Value>(
     2571                proc, Trunc, Origin(),
     2572                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     2573        },
     2574        left, right, result);
     2575
     2576    // Test imm-to-tmp.
     2577    genericTestCompare(
     2578        opcode,
     2579        [&] (BasicBlock* block, Procedure& proc) {
     2580            return block->appendNew<Const32Value>(proc, Origin(), left);
     2581        },
     2582        [&] (BasicBlock* block, Procedure& proc) {
     2583            return block->appendNew<Value>(
     2584                proc, Trunc, Origin(),
     2585                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     2586        },
     2587        left, right, result);
     2588
     2589    // Test tmp-to-imm.
     2590    genericTestCompare(
     2591        opcode,
     2592        [&] (BasicBlock* block, Procedure& proc) {
     2593            return block->appendNew<Value>(
     2594                proc, Trunc, Origin(),
     2595                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     2596        },
     2597        [&] (BasicBlock* block, Procedure& proc) {
     2598            return block->appendNew<Const32Value>(proc, Origin(), right);
     2599        },
     2600        left, right, result);
     2601
     2602    // Test imm-to-imm.
     2603    genericTestCompare(
     2604        opcode,
     2605        [&] (BasicBlock* block, Procedure& proc) {
     2606            return block->appendNew<Const32Value>(proc, Origin(), left);
     2607        },
     2608        [&] (BasicBlock* block, Procedure& proc) {
     2609            return block->appendNew<Const32Value>(proc, Origin(), right);
     2610        },
     2611        left, right, result);
     2612
     2613    testCompareLoad<int32_t>(opcode, Load, left, right);
     2614    testCompareLoad<int8_t>(opcode, Load8S, left, right);
     2615    testCompareLoad<uint8_t>(opcode, Load8Z, left, right);
     2616    testCompareLoad<int16_t>(opcode, Load16S, left, right);
     2617    testCompareLoad<uint16_t>(opcode, Load16Z, left, right);
     2618}
     2619
     2620void testCompare(B3::Opcode opcode, int left, int right)
     2621{
     2622    auto variants = [&] (int left, int right) {
     2623        testCompareImpl(opcode, left, right);
     2624        testCompareImpl(opcode, left, right + 1);
     2625        testCompareImpl(opcode, left, right - 1);
     2626
     2627        auto multipliedTests = [&] (int factor) {
     2628            testCompareImpl(opcode, left * factor, right);
     2629            testCompareImpl(opcode, left * factor, right + 1);
     2630            testCompareImpl(opcode, left * factor, right - 1);
     2631       
     2632            testCompareImpl(opcode, left, right * factor);
     2633            testCompareImpl(opcode, left, (right + 1) * factor);
     2634            testCompareImpl(opcode, left, (right - 1) * factor);
     2635       
     2636            testCompareImpl(opcode, left * factor, right * factor);
     2637            testCompareImpl(opcode, left * factor, (right + 1) * factor);
     2638            testCompareImpl(opcode, left * factor, (right - 1) * factor);
     2639        };
     2640
     2641        multipliedTests(10);
     2642        multipliedTests(100);
     2643        multipliedTests(1000);
     2644        multipliedTests(100000);
     2645    };
     2646
     2647    variants(left, right);
     2648    variants(-left, right);
     2649    variants(left, -right);
     2650    variants(-left, -right);
     2651}
     2652
    23022653#define RUN(test) do {                          \
    23032654        if (!shouldRun(#test))                  \
    23042655            break;                              \
    2305         dataLog(#test ":\n");                   \
    2306         test;                                   \
    2307         dataLog("    OK!\n");                   \
    2308         didRun++;                               \
     2656        tasks.append(                           \
     2657            createSharedTask<void()>(           \
     2658                [&] () {                        \
     2659                    dataLog(#test "...\n");     \
     2660                    test;                       \
     2661                    dataLog(#test ": OK!\n");   \
     2662                }));                            \
    23092663    } while (false);
    23102664
     
    23142668    vm = &VM::create(LargeHeap).leakRef();
    23152669
     2670    Deque<RefPtr<SharedTask<void()>>> tasks;
     2671
    23162672    auto shouldRun = [&] (const char* testName) -> bool {
    2317         return !!strcasestr(testName, filter);
     2673        return !filter || !!strcasestr(testName, filter);
    23182674    };
    2319     unsigned didRun = 0;
    23202675
    23212676    RUN(test42());
     
    26713026    RUN(testLoadFromFramePointer());
    26723027    RUN(testStoreLoadStackSlot(50));
     3028   
    26733029    RUN(testBranch());
    26743030    RUN(testBranchPtr());
     
    27003056    RUN(testSimpleCheck());
    27013057
    2702     if (!didRun)
     3058    RUN(testCompare(Equal, 42, 42));
     3059    RUN(testCompare(NotEqual, 42, 42));
     3060    RUN(testCompare(LessThan, 42, 42));
     3061    RUN(testCompare(GreaterThan, 42, 42));
     3062    RUN(testCompare(LessEqual, 42, 42));
     3063    RUN(testCompare(GreaterEqual, 42, 42));
     3064    RUN(testCompare(Below, 42, 42));
     3065    RUN(testCompare(Above, 42, 42));
     3066    RUN(testCompare(BelowEqual, 42, 42));
     3067    RUN(testCompare(AboveEqual, 42, 42));
     3068
     3069    RUN(testCompare(BitAnd, 42, 42));
     3070    RUN(testCompare(BitAnd, 42, 0));
     3071
     3072    RUN(testLoad<int32_t>(Load, 60));
     3073    RUN(testLoad<int32_t>(Load, -60));
     3074    RUN(testLoad<int32_t>(Load, 1000));
     3075    RUN(testLoad<int32_t>(Load, -1000));
     3076    RUN(testLoad<int32_t>(Load, 1000000));
     3077    RUN(testLoad<int32_t>(Load, -1000000));
     3078    RUN(testLoad<int32_t>(Load, 1000000000));
     3079    RUN(testLoad<int32_t>(Load, -1000000000));
     3080   
     3081    RUN(testLoad<int8_t>(Load8S, 60));
     3082    RUN(testLoad<int8_t>(Load8S, -60));
     3083    RUN(testLoad<int8_t>(Load8S, 1000));
     3084    RUN(testLoad<int8_t>(Load8S, -1000));
     3085    RUN(testLoad<int8_t>(Load8S, 1000000));
     3086    RUN(testLoad<int8_t>(Load8S, -1000000));
     3087    RUN(testLoad<int8_t>(Load8S, 1000000000));
     3088    RUN(testLoad<int8_t>(Load8S, -1000000000));
     3089   
     3090    RUN(testLoad<uint8_t>(Load8Z, 60));
     3091    RUN(testLoad<uint8_t>(Load8Z, -60));
     3092    RUN(testLoad<uint8_t>(Load8Z, 1000));
     3093    RUN(testLoad<uint8_t>(Load8Z, -1000));
     3094    RUN(testLoad<uint8_t>(Load8Z, 1000000));
     3095    RUN(testLoad<uint8_t>(Load8Z, -1000000));
     3096    RUN(testLoad<uint8_t>(Load8Z, 1000000000));
     3097    RUN(testLoad<uint8_t>(Load8Z, -1000000000));
     3098
     3099    RUN(testLoad<int16_t>(Load16S, 60));
     3100    RUN(testLoad<int16_t>(Load16S, -60));
     3101    RUN(testLoad<int16_t>(Load16S, 1000));
     3102    RUN(testLoad<int16_t>(Load16S, -1000));
     3103    RUN(testLoad<int16_t>(Load16S, 1000000));
     3104    RUN(testLoad<int16_t>(Load16S, -1000000));
     3105    RUN(testLoad<int16_t>(Load16S, 1000000000));
     3106    RUN(testLoad<int16_t>(Load16S, -1000000000));
     3107   
     3108    RUN(testLoad<uint16_t>(Load16Z, 60));
     3109    RUN(testLoad<uint16_t>(Load16Z, -60));
     3110    RUN(testLoad<uint16_t>(Load16Z, 1000));
     3111    RUN(testLoad<uint16_t>(Load16Z, -1000));
     3112    RUN(testLoad<uint16_t>(Load16Z, 1000000));
     3113    RUN(testLoad<uint16_t>(Load16Z, -1000000));
     3114    RUN(testLoad<uint16_t>(Load16Z, 1000000000));
     3115    RUN(testLoad<uint16_t>(Load16Z, -1000000000));
     3116
     3117    if (tasks.isEmpty())
    27033118        usage();
     3119
     3120    Lock lock;
     3121
     3122    Vector<ThreadIdentifier> threads;
     3123    for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
     3124        threads.append(
     3125            createThread(
     3126                "testb3 thread",
     3127                [&] () {
     3128                    for (;;) {
     3129                        RefPtr<SharedTask<void()>> task;
     3130                        {
     3131                            LockHolder locker(lock);
     3132                            if (tasks.isEmpty())
     3133                                return;
     3134                            task = tasks.takeFirst();
     3135                        }
     3136
     3137                        task->run();
     3138                    }
     3139                }));
     3140    }
     3141
     3142    for (ThreadIdentifier thread : threads)
     3143        waitForThreadCompletion(thread);
    27043144}
    27053145
     
    27173157int main(int argc, char** argv)
    27183158{
    2719     const char* filter = "";
     3159    const char* filter = nullptr;
    27203160    switch (argc) {
    27213161    case 1:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r192000 r192072  
    34753475            int32_t divisor = node->child2()->asInt32();
    34763476            if (divisor > 1 && hasOneBitSet(divisor)) {
    3477                 unsigned logarithm = WTF::fastLog2(divisor);
     3477                unsigned logarithm = WTF::fastLog2(static_cast<uint32_t>(divisor));
    34783478                GPRReg dividendGPR = op1.gpr();
    34793479                GPRTemporary result(this);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r191937 r192072  
    14591459    switch (elementSize(type)) {
    14601460    case 1:
    1461         if (isSigned(type))
     1461        if (JSC::isSigned(type))
    14621462            load8SignedExtendTo32(BaseIndex(scratch, property, TimesOne), resultPayload);
    14631463        else
     
    14651465        break;
    14661466    case 2:
    1467         if (isSigned(type))
     1467        if (JSC::isSigned(type))
    14681468            load16SignedExtendTo32(BaseIndex(scratch, property, TimesTwo), resultPayload);
    14691469        else
     
    15971597    if (isClamped(type)) {
    15981598        ASSERT(elementSize(type) == 1);
    1599         ASSERT(!isSigned(type));
     1599        ASSERT(!JSC::isSigned(type));
    16001600        Jump inBounds = branch32(BelowOrEqual, earlyScratch, TrustedImm32(0xff));
    16011601        Jump tooBig = branch32(GreaterThan, earlyScratch, TrustedImm32(0xff));
Note: See TracChangeset for help on using the changeset viewer.