Changeset 222564 in webkit


Ignore:
Timestamp:
Sep 27, 2017 11:51:12 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

Add Above/Below comparisons for UInt32 patterns
https://bugs.webkit.org/show_bug.cgi?id=177281

Reviewed by Saam Barati.

JSTests:

  • stress/uint32-comparison-jump.js: Added.

(shouldBe):
(above):
(aboveOrEqual):
(below):
(belowOrEqual):
(notAbove):
(notAboveOrEqual):
(notBelow):
(notBelowOrEqual):

  • stress/uint32-comparison.js: Added.

(shouldBe):
(above):
(aboveOrEqual):
(below):
(belowOrEqual):
(aboveTest):
(aboveOrEqualTest):
(belowTest):
(belowOrEqualTest):

Source/JavaScriptCore:

Sometimes, we would like to have UInt32 operations in JS. While VM does
not support UInt32 nicely, VM supports efficient Int32 operations. As long
as signedness does not matter, we can just perform Int32 operations instead
and recognize its bit pattern as UInt32.

But of course, some operations respect signedness. The most frequently
used one is comparison. Octane/zlib performs UInt32 comparison by performing
val >>> 0. It emits op_urshift and op_unsigned. op_urshift produces
UInt32 in Int32 form. And op_unsigned will generate Double value if
the generated Int32 is < 0 (which should be UInt32).

There is a chance for optimization. The given code pattern is the following.

op_unsigned(op_urshift(@1)) lessThan:< op_unsigned(op_urshift(@2))

This can be converted to the following.

op_urshift(@1) below:< op_urshift(@2)

The above conversion is nice since

  1. We can avoid op_unsigned. This could be unsignedness check in DFG. Since

this check depends on the value of Int32, dropping this check is not as easy as
removing Int32 edge filters.

  1. We can perform unsigned comparison in Int32 form. We do not need to convert

them to DoubleRep.

Since the above comparison exists in Octane/zlib's *super* hot path, dropping
op_unsigned offers huge win.

At first, my patch attempts to convert the above thing in DFG pipeline.
However it poses several problems.

  1. MovHint is not well removed. It makes UInt32ToNumber (which is for op_unsigned) live.
  2. UInt32ToNumber could cause an OSR exit. So if we have the following nodes,

2: UInt32ToNumber(@0)
3: MovHint(@2, xxx)
4: UInt32ToNumber(@1)
5: MovHint(@1, xxx)

we could drop @5's MovHint. But @3 is difficult since @4 can exit.

So, instead, we start introducing a simple optimization in the bytecode compiler.
It performs pattern matching for op_urshift and comparison to drop op_unsigned.
We adds op_below and op_above families to bytecodes. They only accept Int32 and
perform unsigned comparison.

This offers 4% performance improvement in Octane/zlib.

baseline patched

zlib x2 431.07483+-16.28434 414.33407+-9.38375 might be 1.0404x faster

  • bytecode/BytecodeDumper.cpp:

(JSC::BytecodeDumper<Block>::printCompareJump):
(JSC::BytecodeDumper<Block>::dumpBytecode):

  • bytecode/BytecodeDumper.h:
  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/Opcode.h:

(JSC::isBranch):

  • bytecode/PreciseJumpTargetsInlines.h:

(JSC::extractStoredJumpTargetsForBytecodeOffset):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitJumpIfTrue):
(JSC::BytecodeGenerator::emitJumpIfFalse):

  • bytecompiler/NodesCodegen.cpp:

(JSC::BinaryOpNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGIntegerRangeOptimizationPhase.cpp:
  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCompareUnsigned):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):

  • dfg/DFGValidate.cpp:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareBelow):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareBelowEq):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_below):
(JSC::JIT::emit_op_beloweq):
(JSC::JIT::emit_op_jbelow):
(JSC::JIT::emit_op_jbeloweq):
(JSC::JIT::emit_compareUnsignedAndJump):
(JSC::JIT::emit_compareUnsigned):

  • jit/JITArithmetic32_64.cpp:

(JSC::JIT::emit_compareUnsignedAndJump):
(JSC::JIT::emit_compareUnsigned):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/Nodes.h:

(JSC::ExpressionNode::isBinaryOpNode const):

Location:
trunk
Files:
2 added
36 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r222563 r222564  
     12017-09-27  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        Add Above/Below comparisons for UInt32 patterns
     4        https://bugs.webkit.org/show_bug.cgi?id=177281
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/uint32-comparison-jump.js: Added.
     9        (shouldBe):
     10        (above):
     11        (aboveOrEqual):
     12        (below):
     13        (belowOrEqual):
     14        (notAbove):
     15        (notAboveOrEqual):
     16        (notBelow):
     17        (notBelowOrEqual):
     18        * stress/uint32-comparison.js: Added.
     19        (shouldBe):
     20        (above):
     21        (aboveOrEqual):
     22        (below):
     23        (belowOrEqual):
     24        (aboveTest):
     25        (aboveOrEqualTest):
     26        (belowTest):
     27        (belowOrEqualTest):
     28
    1292017-09-25  Yusuke Suzuki  <utatane.tea@gmail.com>
    230
  • trunk/Source/JavaScriptCore/ChangeLog

    r222563 r222564  
     12017-09-27  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        Add Above/Below comparisons for UInt32 patterns
     4        https://bugs.webkit.org/show_bug.cgi?id=177281
     5
     6        Reviewed by Saam Barati.
     7
     8        Sometimes, we would like to have UInt32 operations in JS. While VM does
     9        not support UInt32 nicely, VM supports efficient Int32 operations. As long
     10        as signedness does not matter, we can just perform Int32 operations instead
     11        and recognize its bit pattern as UInt32.
     12
     13        But of course, some operations respect signedness. The most frequently
     14        used one is comparison. Octane/zlib performs UInt32 comparison by performing
     15        `val >>> 0`. It emits op_urshift and op_unsigned. op_urshift produces
     16        UInt32 in Int32 form. And op_unsigned will generate Double value if
     17        the generated Int32 is < 0 (which should be UInt32).
     18
     19        There is a chance for optimization. The given code pattern is the following.
     20
     21            op_unsigned(op_urshift(@1)) lessThan:< op_unsigned(op_urshift(@2))
     22
     23        This can be converted to the following.
     24
     25            op_urshift(@1) below:< op_urshift(@2)
     26
     27        The above conversion is nice since
     28
     29        1. We can avoid op_unsigned. This could be unsignedness check in DFG. Since
     30        this check depends on the value of Int32, dropping this check is not as easy as
     31        removing Int32 edge filters.
     32
     33        2. We can perform unsigned comparison in Int32 form. We do not need to convert
     34        them to DoubleRep.
     35
     36        Since the above comparison exists in Octane/zlib's *super* hot path, dropping
     37        op_unsigned offers huge win.
     38
     39        At first, my patch attempts to convert the above thing in DFG pipeline.
     40        However it poses several problems.
     41
     42        1. MovHint is not well removed. It makes UInt32ToNumber (which is for op_unsigned) live.
     43        2. UInt32ToNumber could cause an OSR exit. So if we have the following nodes,
     44
     45            2: UInt32ToNumber(@0)
     46            3: MovHint(@2, xxx)
     47            4: UInt32ToNumber(@1)
     48            5: MovHint(@1, xxx)
     49
     50        we could drop @5's MovHint. But @3 is difficult since @4 can exit.
     51
     52        So, instead, we start introducing a simple optimization in the bytecode compiler.
     53        It performs pattern matching for op_urshift and comparison to drop op_unsigned.
     54        We adds op_below and op_above families to bytecodes. They only accept Int32 and
     55        perform unsigned comparison.
     56
     57        This offers 4% performance improvement in Octane/zlib.
     58
     59                                    baseline                  patched
     60
     61        zlib           x2     431.07483+-16.28434       414.33407+-9.38375         might be 1.0404x faster
     62
     63        * bytecode/BytecodeDumper.cpp:
     64        (JSC::BytecodeDumper<Block>::printCompareJump):
     65        (JSC::BytecodeDumper<Block>::dumpBytecode):
     66        * bytecode/BytecodeDumper.h:
     67        * bytecode/BytecodeList.json:
     68        * bytecode/BytecodeUseDef.h:
     69        (JSC::computeUsesForBytecodeOffset):
     70        (JSC::computeDefsForBytecodeOffset):
     71        * bytecode/Opcode.h:
     72        (JSC::isBranch):
     73        * bytecode/PreciseJumpTargetsInlines.h:
     74        (JSC::extractStoredJumpTargetsForBytecodeOffset):
     75        * bytecompiler/BytecodeGenerator.cpp:
     76        (JSC::BytecodeGenerator::emitJumpIfTrue):
     77        (JSC::BytecodeGenerator::emitJumpIfFalse):
     78        * bytecompiler/NodesCodegen.cpp:
     79        (JSC::BinaryOpNode::emitBytecode):
     80        * dfg/DFGAbstractInterpreterInlines.h:
     81        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     82        * dfg/DFGByteCodeParser.cpp:
     83        (JSC::DFG::ByteCodeParser::parseBlock):
     84        * dfg/DFGCapabilities.cpp:
     85        (JSC::DFG::capabilityLevel):
     86        * dfg/DFGClobberize.h:
     87        (JSC::DFG::clobberize):
     88        * dfg/DFGDoesGC.cpp:
     89        (JSC::DFG::doesGC):
     90        * dfg/DFGFixupPhase.cpp:
     91        (JSC::DFG::FixupPhase::fixupNode):
     92        * dfg/DFGIntegerRangeOptimizationPhase.cpp:
     93        * dfg/DFGNodeType.h:
     94        * dfg/DFGPredictionPropagationPhase.cpp:
     95        * dfg/DFGSafeToExecute.h:
     96        (JSC::DFG::safeToExecute):
     97        * dfg/DFGSpeculativeJIT.cpp:
     98        (JSC::DFG::SpeculativeJIT::compileCompareUnsigned):
     99        * dfg/DFGSpeculativeJIT.h:
     100        * dfg/DFGSpeculativeJIT32_64.cpp:
     101        (JSC::DFG::SpeculativeJIT::compile):
     102        * dfg/DFGSpeculativeJIT64.cpp:
     103        (JSC::DFG::SpeculativeJIT::compile):
     104        * dfg/DFGStrengthReductionPhase.cpp:
     105        (JSC::DFG::StrengthReductionPhase::handleNode):
     106        * dfg/DFGValidate.cpp:
     107        * ftl/FTLCapabilities.cpp:
     108        (JSC::FTL::canCompile):
     109        * ftl/FTLLowerDFGToB3.cpp:
     110        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     111        (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelow):
     112        (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelowEq):
     113        * jit/JIT.cpp:
     114        (JSC::JIT::privateCompileMainPass):
     115        * jit/JIT.h:
     116        * jit/JITArithmetic.cpp:
     117        (JSC::JIT::emit_op_below):
     118        (JSC::JIT::emit_op_beloweq):
     119        (JSC::JIT::emit_op_jbelow):
     120        (JSC::JIT::emit_op_jbeloweq):
     121        (JSC::JIT::emit_compareUnsignedAndJump):
     122        (JSC::JIT::emit_compareUnsigned):
     123        * jit/JITArithmetic32_64.cpp:
     124        (JSC::JIT::emit_compareUnsignedAndJump):
     125        (JSC::JIT::emit_compareUnsigned):
     126        * llint/LowLevelInterpreter.asm:
     127        * llint/LowLevelInterpreter32_64.asm:
     128        * llint/LowLevelInterpreter64.asm:
     129        * parser/Nodes.h:
     130        (JSC::ExpressionNode::isBinaryOpNode const):
     131
    11322017-09-25  Yusuke Suzuki  <utatane.tea@gmail.com>
    2133
  • trunk/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp

    r222523 r222564  
    361361
    362362template<class Block>
     363void BytecodeDumper<Block>::printCompareJump(PrintStream& out, const typename Block::Instruction*, const typename Block::Instruction*& it, int location, const char* op)
     364{
     365    int r0 = (++it)->u.operand;
     366    int r1 = (++it)->u.operand;
     367    int offset = (++it)->u.operand;
     368    printLocationAndOp(out, location, it, op);
     369    out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     370}
     371
     372template<class Block>
    363373void BytecodeDumper<Block>::printGetByIdOp(PrintStream& out, int location, const typename Block::Instruction*& it)
    364374{
     
    835845        break;
    836846    }
     847    case op_below: {
     848        printBinaryOp(out, location, it, "below");
     849        break;
     850    }
     851    case op_beloweq: {
     852        printBinaryOp(out, location, it, "beloweq");
     853        break;
     854    }
    837855    case op_inc: {
    838856        int r0 = (++it)->u.operand;
     
    11981216    }
    11991217    case op_jless: {
    1200         int r0 = (++it)->u.operand;
    1201         int r1 = (++it)->u.operand;
    1202         int offset = (++it)->u.operand;
    1203         printLocationAndOp(out, location, it, "jless");
    1204         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1218        printCompareJump(out, begin, it, location, "jless");
    12051219        break;
    12061220    }
    12071221    case op_jlesseq: {
    1208         int r0 = (++it)->u.operand;
    1209         int r1 = (++it)->u.operand;
    1210         int offset = (++it)->u.operand;
    1211         printLocationAndOp(out, location, it, "jlesseq");
    1212         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1222        printCompareJump(out, begin, it, location, "jlesseq");
    12131223        break;
    12141224    }
    12151225    case op_jgreater: {
    1216         int r0 = (++it)->u.operand;
    1217         int r1 = (++it)->u.operand;
    1218         int offset = (++it)->u.operand;
    1219         printLocationAndOp(out, location, it, "jgreater");
    1220         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1226        printCompareJump(out, begin, it, location, "jgreater");
    12211227        break;
    12221228    }
    12231229    case op_jgreatereq: {
    1224         int r0 = (++it)->u.operand;
    1225         int r1 = (++it)->u.operand;
    1226         int offset = (++it)->u.operand;
    1227         printLocationAndOp(out, location, it, "jgreatereq");
    1228         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1230        printCompareJump(out, begin, it, location, "jgreatereq");
    12291231        break;
    12301232    }
    12311233    case op_jnless: {
    1232         int r0 = (++it)->u.operand;
    1233         int r1 = (++it)->u.operand;
    1234         int offset = (++it)->u.operand;
    1235         printLocationAndOp(out, location, it, "jnless");
    1236         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1234        printCompareJump(out, begin, it, location, "jnless");
    12371235        break;
    12381236    }
    12391237    case op_jnlesseq: {
    1240         int r0 = (++it)->u.operand;
    1241         int r1 = (++it)->u.operand;
    1242         int offset = (++it)->u.operand;
    1243         printLocationAndOp(out, location, it, "jnlesseq");
    1244         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1238        printCompareJump(out, begin, it, location, "jnlesseq");
    12451239        break;
    12461240    }
    12471241    case op_jngreater: {
    1248         int r0 = (++it)->u.operand;
    1249         int r1 = (++it)->u.operand;
    1250         int offset = (++it)->u.operand;
    1251         printLocationAndOp(out, location, it, "jngreater");
    1252         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1242        printCompareJump(out, begin, it, location, "jngreater");
    12531243        break;
    12541244    }
    12551245    case op_jngreatereq: {
    1256         int r0 = (++it)->u.operand;
    1257         int r1 = (++it)->u.operand;
    1258         int offset = (++it)->u.operand;
    1259         printLocationAndOp(out, location, it, "jngreatereq");
    1260         out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
     1246        printCompareJump(out, begin, it, location, "jngreatereq");
     1247        break;
     1248    }
     1249    case op_jbelow: {
     1250        printCompareJump(out, begin, it, location, "jbelow");
     1251        break;
     1252    }
     1253    case op_jbeloweq: {
     1254        printCompareJump(out, begin, it, location, "jbeloweq");
    12611255        break;
    12621256    }
  • trunk/Source/JavaScriptCore/bytecode/BytecodeDumper.h

    r222523 r222564  
    6868    void printBinaryOp(PrintStream& out, int location, const Instruction*& it, const char* op);
    6969    void printConditionalJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op);
     70    void printCompareJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op);
    7071    void printGetByIdOp(PrintStream& out, int location, const Instruction*& it);
    7172    void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.json

    r222523 r222564  
    3333            { "name" : "op_greater", "length" : 4 },
    3434            { "name" : "op_greatereq", "length" : 4 },
     35            { "name" : "op_below", "length" : 4 },
     36            { "name" : "op_beloweq", "length" : 4 },
    3537            { "name" : "op_inc", "length" : 2 },
    3638            { "name" : "op_dec", "length" : 2 },
     
    112114            { "name" : "op_jngreater", "length" : 4 },
    113115            { "name" : "op_jngreatereq", "length" : 4 },
     116            { "name" : "op_jbelow", "length" : 4 },
     117            { "name" : "op_jbeloweq", "length" : 4 },
    114118            { "name" : "op_loop_hint", "length" : 1 },
    115119            { "name" : "op_switch_imm", "length" : 4 },
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h

    r222523 r222564  
    8686    case op_jngreatereq:
    8787    case op_jless:
     88    case op_jbelow:
     89    case op_jbeloweq:
    8890    case op_set_function_name:
    8991    case op_log_shadow_chicken_tail: {
     
    238240    case op_greater:
    239241    case op_greatereq:
     242    case op_below:
     243    case op_beloweq:
    240244    case op_nstricteq:
    241245    case op_stricteq:
     
    344348    case op_jngreater:
    345349    case op_jngreatereq:
     350    case op_jbelow:
     351    case op_jbeloweq:
    346352    case op_loop_hint:
    347353    case op_switch_imm:
     
    464470    case op_greater:
    465471    case op_greatereq:
     472    case op_below:
     473    case op_beloweq:
    466474    case op_neq_null:
    467475    case op_eq_null:
  • trunk/Source/JavaScriptCore/bytecode/Opcode.h

    r222523 r222564  
    152152    case op_jngreater:
    153153    case op_jngreatereq:
     154    case op_jbelow:
     155    case op_jbeloweq:
    154156    case op_switch_imm:
    155157    case op_switch_char:
  • trunk/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h

    r222523 r222564  
    5656    case op_jngreater:
    5757    case op_jngreatereq:
     58    case op_jbelow:
     59    case op_jbeloweq:
    5860        function(current[3].u.operand);
    5961        break;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r222523 r222564  
    13651365void BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label& target)
    13661366{
    1367     if (m_lastOpcodeID == op_less) {
     1367    auto fuseCompareAndJump = [&] (OpcodeID jumpID) {
    13681368        int dstIndex;
    13691369        int src1Index;
     
    13761376
    13771377            size_t begin = instructions().size();
    1378             emitOpcode(op_jless);
     1378            emitOpcode(jumpID);
    13791379            instructions().append(src1Index);
    13801380            instructions().append(src2Index);
    13811381            instructions().append(target.bind(begin, instructions().size()));
     1382            return true;
     1383        }
     1384        return false;
     1385    };
     1386
     1387    if (m_lastOpcodeID == op_less) {
     1388        if (fuseCompareAndJump(op_jless))
    13821389            return;
    1383         }
    13841390    } else if (m_lastOpcodeID == op_lesseq) {
    1385         int dstIndex;
    1386         int src1Index;
    1387         int src2Index;
    1388 
    1389         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1390 
    1391         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1392             rewindBinaryOp();
    1393 
    1394             size_t begin = instructions().size();
    1395             emitOpcode(op_jlesseq);
    1396             instructions().append(src1Index);
    1397             instructions().append(src2Index);
    1398             instructions().append(target.bind(begin, instructions().size()));
     1391        if (fuseCompareAndJump(op_jlesseq))
    13991392            return;
    1400         }
    14011393    } else if (m_lastOpcodeID == op_greater) {
    1402         int dstIndex;
    1403         int src1Index;
    1404         int src2Index;
    1405 
    1406         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1407 
    1408         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1409             rewindBinaryOp();
    1410 
    1411             size_t begin = instructions().size();
    1412             emitOpcode(op_jgreater);
    1413             instructions().append(src1Index);
    1414             instructions().append(src2Index);
    1415             instructions().append(target.bind(begin, instructions().size()));
     1394        if (fuseCompareAndJump(op_jgreater))
    14161395            return;
    1417         }
    14181396    } else if (m_lastOpcodeID == op_greatereq) {
    1419         int dstIndex;
    1420         int src1Index;
    1421         int src2Index;
    1422 
    1423         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1424 
    1425         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1426             rewindBinaryOp();
    1427 
    1428             size_t begin = instructions().size();
    1429             emitOpcode(op_jgreatereq);
    1430             instructions().append(src1Index);
    1431             instructions().append(src2Index);
    1432             instructions().append(target.bind(begin, instructions().size()));
     1397        if (fuseCompareAndJump(op_jgreatereq))
    14331398            return;
    1434         }
     1399    } else if (m_lastOpcodeID == op_below) {
     1400        if (fuseCompareAndJump(op_jbelow))
     1401            return;
     1402    } else if (m_lastOpcodeID == op_beloweq) {
     1403        if (fuseCompareAndJump(op_jbeloweq))
     1404            return;
    14351405    } else if (m_lastOpcodeID == op_eq_null && target.isForward()) {
    14361406        int dstIndex;
     
    14741444void BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label& target)
    14751445{
    1476     if (m_lastOpcodeID == op_less && target.isForward()) {
     1446    auto fuseCompareAndJump = [&] (OpcodeID jumpID, bool replaceOperands) {
    14771447        int dstIndex;
    14781448        int src1Index;
     
    14851455
    14861456            size_t begin = instructions().size();
    1487             emitOpcode(op_jnless);
     1457            emitOpcode(jumpID);
     1458            // Since op_below and op_beloweq only accepts Int32, replacing operands is not observable to users.
     1459            if (replaceOperands)
     1460                std::swap(src1Index, src2Index);
    14881461            instructions().append(src1Index);
    14891462            instructions().append(src2Index);
    14901463            instructions().append(target.bind(begin, instructions().size()));
     1464            return true;
     1465        }
     1466        return false;
     1467    };
     1468
     1469    if (m_lastOpcodeID == op_less && target.isForward()) {
     1470        if (fuseCompareAndJump(op_jnless, false))
    14911471            return;
    1492         }
    14931472    } else if (m_lastOpcodeID == op_lesseq && target.isForward()) {
    1494         int dstIndex;
    1495         int src1Index;
    1496         int src2Index;
    1497 
    1498         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1499 
    1500         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1501             rewindBinaryOp();
    1502 
    1503             size_t begin = instructions().size();
    1504             emitOpcode(op_jnlesseq);
    1505             instructions().append(src1Index);
    1506             instructions().append(src2Index);
    1507             instructions().append(target.bind(begin, instructions().size()));
     1473        if (fuseCompareAndJump(op_jnlesseq, false))
    15081474            return;
    1509         }
    15101475    } else if (m_lastOpcodeID == op_greater && target.isForward()) {
    1511         int dstIndex;
    1512         int src1Index;
    1513         int src2Index;
    1514 
    1515         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1516 
    1517         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1518             rewindBinaryOp();
    1519 
    1520             size_t begin = instructions().size();
    1521             emitOpcode(op_jngreater);
    1522             instructions().append(src1Index);
    1523             instructions().append(src2Index);
    1524             instructions().append(target.bind(begin, instructions().size()));
     1476        if (fuseCompareAndJump(op_jngreater, false))
    15251477            return;
    1526         }
    15271478    } else if (m_lastOpcodeID == op_greatereq && target.isForward()) {
    1528         int dstIndex;
    1529         int src1Index;
    1530         int src2Index;
    1531 
    1532         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
    1533 
    1534         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
    1535             rewindBinaryOp();
    1536 
    1537             size_t begin = instructions().size();
    1538             emitOpcode(op_jngreatereq);
    1539             instructions().append(src1Index);
    1540             instructions().append(src2Index);
    1541             instructions().append(target.bind(begin, instructions().size()));
     1479        if (fuseCompareAndJump(op_jngreatereq, false))
    15421480            return;
    1543         }
     1481    } else if (m_lastOpcodeID == op_below && target.isForward()) {
     1482        if (fuseCompareAndJump(op_jbeloweq, true))
     1483            return;
     1484    } else if (m_lastOpcodeID == op_beloweq && target.isForward()) {
     1485        if (fuseCompareAndJump(op_jbelow, true))
     1486            return;
    15441487    } else if (m_lastOpcodeID == op_not) {
    15451488        int dstIndex;
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r222523 r222564  
    19821982    OpcodeID opcodeID = this->opcodeID();
    19831983
     1984    if (opcodeID == op_less || opcodeID == op_lesseq || opcodeID == op_greater || opcodeID == op_greatereq) {
     1985        auto isUInt32 = [&] (ExpressionNode* node) -> std::optional<UInt32Result> {
     1986            if (node->isBinaryOpNode() && static_cast<BinaryOpNode*>(node)->opcodeID() == op_urshift)
     1987                return UInt32Result::UInt32;
     1988            if (node->isNumber() && static_cast<NumberNode*>(node)->isIntegerNode()) {
     1989                int32_t value = static_cast<int32_t>(static_cast<IntegerNode*>(node)->value());
     1990                if (value >= 0)
     1991                    return UInt32Result::Constant;
     1992            }
     1993            return std::nullopt;
     1994        };
     1995        auto leftResult = isUInt32(m_expr1);
     1996        auto rightResult = isUInt32(m_expr2);
     1997        if ((leftResult && rightResult) && (leftResult.value() == UInt32Result::UInt32 || rightResult.value() == UInt32Result::UInt32)) {
     1998            auto* left = m_expr1;
     1999            auto* right = m_expr2;
     2000            if (left->isBinaryOpNode()) {
     2001                ASSERT(static_cast<BinaryOpNode*>(left)->opcodeID() == op_urshift);
     2002                static_cast<BinaryOpNode*>(left)->m_shouldToUnsignedResult = false;
     2003            }
     2004            if (right->isBinaryOpNode()) {
     2005                ASSERT(static_cast<BinaryOpNode*>(right)->opcodeID() == op_urshift);
     2006                static_cast<BinaryOpNode*>(right)->m_shouldToUnsignedResult = false;
     2007            }
     2008            RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator));
     2009            RefPtr<RegisterID> src2 = generator.emitNode(right);
     2010            generator.emitExpressionInfo(position(), position(), position());
     2011
     2012            // Since the both sides only accept Int32, replacing operands is not observable to users.
     2013            bool replaceOperands = false;
     2014            OpcodeID resultOp = opcodeID;
     2015            switch (opcodeID) {
     2016            case op_less:
     2017                resultOp = op_below;
     2018                break;
     2019            case op_lesseq:
     2020                resultOp = op_beloweq;
     2021                break;
     2022            case op_greater:
     2023                resultOp = op_below;
     2024                replaceOperands = true;
     2025                break;
     2026            case op_greatereq:
     2027                resultOp = op_beloweq;
     2028                replaceOperands = true;
     2029                break;
     2030            default:
     2031                RELEASE_ASSERT_NOT_REACHED();
     2032            }
     2033            OperandTypes operandTypes(left->resultDescriptor(), right->resultDescriptor());
     2034            if (replaceOperands) {
     2035                std::swap(src1, src2);
     2036                operandTypes = OperandTypes(right->resultDescriptor(), left->resultDescriptor());
     2037            }
     2038            return generator.emitBinaryOp(resultOp, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), operandTypes);
     2039        }
     2040    }
     2041
    19842042    if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) {
    19852043        generator.emitExpressionInfo(position(), position(), position());
     
    20172075    }
    20182076    RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
    2019     if (opcodeID == op_urshift && dst != generator.ignoredResult())
    2020         return generator.emitUnaryOp(op_unsigned, result, result);
     2077    if (m_shouldToUnsignedResult) {
     2078        if (opcodeID == op_urshift && dst != generator.ignoredResult())
     2079            return generator.emitUnaryOp(op_unsigned, result, result);
     2080    }
    20212081    return result;
    20222082}
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r222523 r222564  
    14081408        break;
    14091409    }
    1410            
     1410
     1411    case CompareBelow:
     1412    case CompareBelowEq: {
     1413        JSValue leftConst = forNode(node->child1()).value();
     1414        JSValue rightConst = forNode(node->child2()).value();
     1415        if (leftConst && rightConst) {
     1416            if (leftConst.isInt32() && rightConst.isInt32()) {
     1417                uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
     1418                uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
     1419                switch (node->op()) {
     1420                case CompareBelow:
     1421                    setConstant(node, jsBoolean(a < b));
     1422                    break;
     1423                case CompareBelowEq:
     1424                    setConstant(node, jsBoolean(a <= b));
     1425                    break;
     1426                default:
     1427                    RELEASE_ASSERT_NOT_REACHED();
     1428                    break;
     1429                }
     1430                break;
     1431            }
     1432        }
     1433
     1434        if (node->child1() == node->child2()) {
     1435            switch (node->op()) {
     1436            case CompareBelow:
     1437                setConstant(node, jsBoolean(false));
     1438                break;
     1439            case CompareBelowEq:
     1440                setConstant(node, jsBoolean(true));
     1441                break;
     1442            default:
     1443                DFG_CRASH(m_graph, node, "Unexpected node type");
     1444                break;
     1445            }
     1446            break;
     1447        }
     1448        forNode(node).setType(SpecBoolean);
     1449        break;
     1450    }
     1451
    14111452    case CompareLess:
    14121453    case CompareLessEq:
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r222563 r222564  
    47544754        }
    47554755
     4756        case op_below: {
     4757            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
     4758            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
     4759            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelow, op1, op2));
     4760            NEXT_OPCODE(op_below);
     4761        }
     4762
     4763        case op_beloweq: {
     4764            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
     4765            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
     4766            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelowEq, op1, op2));
     4767            NEXT_OPCODE(op_beloweq);
     4768        }
     4769
    47564770        case op_eq: {
    47574771            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
     
    51995213            LAST_OPCODE(op_jngreatereq);
    52005214        }
    5201            
     5215
     5216        case op_jbelow: {
     5217            unsigned relativeOffset = currentInstruction[3].u.operand;
     5218            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
     5219            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
     5220            Node* condition = addToGraph(CompareBelow, op1, op2);
     5221            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbelow))), condition);
     5222            LAST_OPCODE(op_jbelow);
     5223        }
     5224
     5225        case op_jbeloweq: {
     5226            unsigned relativeOffset = currentInstruction[3].u.operand;
     5227            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
     5228            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
     5229            Node* condition = addToGraph(CompareBelowEq, op1, op2);
     5230            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbeloweq))), condition);
     5231            LAST_OPCODE(op_jbeloweq);
     5232        }
     5233
    52025234        case op_switch_imm: {
    52035235            SwitchData& data = *m_graph.m_switchData.add();
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp

    r222523 r222564  
    152152    case op_greater:
    153153    case op_greatereq:
     154    case op_below:
     155    case op_beloweq:
    154156    case op_eq:
    155157    case op_eq_null:
     
    193195    case op_jngreater:
    194196    case op_jngreatereq:
     197    case op_jbelow:
     198    case op_jbeloweq:
    195199    case op_loop_hint:
    196200    case op_check_traps:
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r222523 r222564  
    14871487        def(PureValue(node));
    14881488        return;
     1489
     1490    case CompareBelow:
     1491    case CompareBelowEq:
     1492        def(PureValue(node));
     1493        return;
    14891494       
    14901495    case CompareEq:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r222523 r222564  
    144144    case CompareGreater:
    145145    case CompareGreaterEq:
     146    case CompareBelow:
     147    case CompareBelowEq:
    146148    case CompareEq:
    147149    case CompareStrictEq:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r222563 r222564  
    143143            else {
    144144                node->setArithMode(Arith::DoOverflow);
    145                 node->clearFlags(NodeMustGenerate);
    146145                node->setResult(enableInt52() ? NodeResultInt52 : NodeResultDouble);
    147146            }
     
    15961595        case GetTypedArrayByteOffset: {
    15971596            fixEdge<KnownCellUse>(node->child1());
     1597            break;
     1598        }
     1599
     1600        case CompareBelow:
     1601        case CompareBelowEq: {
     1602            fixEdge<Int32Use>(node->child1());
     1603            fixEdge<Int32Use>(node->child2());
    15981604            break;
    15991605        }
  • trunk/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp

    r222523 r222564  
    11411141                            terminal->child1().node(), m_zero, Relationship::NotEqual, 0);
    11421142                    } else {
     1143                        // FIXME: Handle CompareBelow and CompareBelowEq.
    11431144                        Node* compare = terminal->child1().node();
    11441145                        switch (compare->op()) {
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r222563 r222564  
    122122    macro(ValueToInt32, NodeResultInt32) \
    123123    /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
    124     macro(UInt32ToNumber, NodeResultNumber | NodeMustGenerate) \
     124    macro(UInt32ToNumber, NodeResultNumber) \
    125125    /* Converts booleans to numbers but passes everything else through. */\
    126126    macro(BooleanToNumber, NodeResultJS) \
     
    287287    macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \
    288288    macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \
     289    macro(CompareBelow, NodeResultBoolean) \
     290    macro(CompareBelowEq, NodeResultBoolean) \
    289291    macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
    290292    macro(CompareStrictEq, NodeResultBoolean) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r222523 r222564  
    819819        case CompareGreater:
    820820        case CompareGreaterEq:
     821        case CompareBelow:
     822        case CompareBelowEq:
    821823        case CompareEq:
    822824        case CompareStrictEq:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r222523 r222564  
    267267    case CompareGreater:
    268268    case CompareGreaterEq:
     269    case CompareBelow:
     270    case CompareBelowEq:
    269271    case CompareEq:
    270272    case CompareStrictEq:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r222563 r222564  
    57115711}
    57125712
     5713void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition)
     5714{
     5715    compileInt32Compare(node, condition);
     5716}
     5717
    57135718bool SpeculativeJIT::compileStrictEq(Node* node)
    57145719{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r222563 r222564  
    27412741   
    27422742    bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ);
     2743    void compileCompareUnsigned(Node*, MacroAssembler::RelationalCondition);
    27432744    bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ);
    27442745    void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r222563 r222564  
    25212521        if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
    25222522            return;
     2523        break;
     2524
     2525    case CompareBelow:
     2526        compileCompareUnsigned(node, JITCompiler::Below);
     2527        break;
     2528
     2529    case CompareBelowEq:
     2530        compileCompareUnsigned(node, JITCompiler::BelowOrEqual);
    25232531        break;
    25242532
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r222563 r222564  
    26632663        if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
    26642664            return;
     2665        break;
     2666
     2667    case CompareBelow:
     2668        compileCompareUnsigned(node, JITCompiler::Below);
     2669        break;
     2670
     2671    case CompareBelowEq:
     2672        compileCompareUnsigned(node, JITCompiler::BelowOrEqual);
    26652673        break;
    26662674
  • trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp

    r222523 r222564  
    7676
    7777private:
     78    enum class UInt32Result { UInt32, Constant };
     79
    7880    void handleNode()
    7981    {
     
    263265                }
    264266                break;
     267            }
     268            break;
     269        }
     270
     271        case CompareEq:
     272        case CompareLess:
     273        case CompareLessEq:
     274        case CompareGreater:
     275        case CompareGreaterEq: {
     276            if (m_node->isBinaryUseKind(Int32Use)) {
     277                auto isUInt32 = [&] (Edge& edge) -> std::optional<UInt32Result> {
     278                    if (edge->op() == UInt32ToNumber)
     279                        return UInt32Result::UInt32;
     280                    if (edge->isInt32Constant()) {
     281                        if (edge->asInt32() >= 0)
     282                            return UInt32Result::Constant;
     283                    }
     284                    return std::nullopt;
     285                };
     286
     287                auto child1Result = isUInt32(m_node->child1());
     288                auto child2Result = isUInt32(m_node->child2());
     289                if ((child1Result && child2Result) && (child1Result.value() == UInt32Result::UInt32 || child2Result.value() == UInt32Result::UInt32)) {
     290                    NodeType op = m_node->op();
     291                    bool replaceOperands = false;
     292                    switch (m_node->op()) {
     293                    case CompareEq:
     294                        op = CompareEq;
     295                        break;
     296                    case CompareLess:
     297                        op = CompareBelow;
     298                        break;
     299                    case CompareLessEq:
     300                        op = CompareBelowEq;
     301                        break;
     302                    case CompareGreater:
     303                        op = CompareBelow;
     304                        replaceOperands = true;
     305                        break;
     306                    case CompareGreaterEq:
     307                        op = CompareBelowEq;
     308                        replaceOperands = true;
     309                        break;
     310                    default:
     311                        RELEASE_ASSERT_NOT_REACHED();
     312                    }
     313
     314                    auto extractChild = [&] (Edge& edge) {
     315                        if (edge->op() == UInt32ToNumber)
     316                            return edge->child1().node();
     317                        return edge.node();
     318                    };
     319
     320                    m_node->setOp(op);
     321                    m_node->child1() = Edge(extractChild(m_node->child1()), Int32Use);
     322                    m_node->child2() = Edge(extractChild(m_node->child2()), Int32Use);
     323                    if (replaceOperands)
     324                        std::swap(m_node->child1(), m_node->child2());
     325                    m_changed = true;
     326                }
    265327            }
    266328            break;
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r222523 r222564  
    268268                case CompareGreater:
    269269                case CompareGreaterEq:
     270                case CompareBelow:
     271                case CompareBelowEq:
    270272                case CompareEq:
    271273                case CompareStrictEq:
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r222523 r222564  
    285285    case CompareGreater:
    286286    case CompareGreaterEq:
     287    case CompareBelow:
     288    case CompareBelowEq:
    287289    case CompareStrictEq:
    288290    case DefineDataProperty:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r222563 r222564  
    933933            compileCompareGreaterEq();
    934934            break;
     935        case CompareBelow:
     936            compileCompareBelow();
     937            break;
     938        case CompareBelowEq:
     939            compileCompareBelowEq();
     940            break;
    935941        case CompareEqPtr:
    936942            compileCompareEqPtr();
     
    64046410            operationCompareStringGreaterEq,
    64056411            operationCompareGreaterEq);
     6412    }
     6413
     6414    void compileCompareBelow()
     6415    {
     6416        setBoolean(m_out.below(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     6417    }
     6418   
     6419    void compileCompareBelowEq()
     6420    {
     6421        setBoolean(m_out.belowOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
    64066422    }
    64076423   
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r222523 r222564  
    302302        DEFINE_OP(op_eq)
    303303        DEFINE_OP(op_eq_null)
     304        DEFINE_OP(op_below)
     305        DEFINE_OP(op_beloweq)
    304306        DEFINE_OP(op_try_get_by_id)
    305307        case op_get_array_length:
     
    332334        DEFINE_OP(op_jngreater)
    333335        DEFINE_OP(op_jngreatereq)
     336        DEFINE_OP(op_jbelow)
     337        DEFINE_OP(op_jbeloweq)
    334338        DEFINE_OP(op_jtrue)
    335339        DEFINE_OP(op_loop_hint)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r222523 r222564  
    461461
    462462        void emit_compareAndJump(OpcodeID, int op1, int op2, unsigned target, RelationalCondition);
     463        void emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition);
     464        void emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition);
    463465        void emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&);
    464466       
     
    500502        void emit_op_eq(Instruction*);
    501503        void emit_op_eq_null(Instruction*);
     504        void emit_op_below(Instruction*);
     505        void emit_op_beloweq(Instruction*);
    502506        void emit_op_try_get_by_id(Instruction*);
    503507        void emit_op_get_by_id(Instruction*);
     
    530534        void emit_op_jngreater(Instruction*);
    531535        void emit_op_jngreatereq(Instruction*);
     536        void emit_op_jbelow(Instruction*);
     537        void emit_op_jbeloweq(Instruction*);
    532538        void emit_op_jtrue(Instruction*);
    533539        void emit_op_loop_hint(Instruction*);
  • trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp

    r222523 r222564  
    196196
    197197    emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrUnordered, operationCompareGreaterEq, true, iter);
     198}
     199
     200void JIT::emit_op_below(Instruction* currentInstruction)
     201{
     202    int dst = currentInstruction[1].u.operand;
     203    int op1 = currentInstruction[2].u.operand;
     204    int op2 = currentInstruction[3].u.operand;
     205    emit_compareUnsigned(dst, op1, op2, Below);
     206}
     207
     208void JIT::emit_op_beloweq(Instruction* currentInstruction)
     209{
     210    int dst = currentInstruction[1].u.operand;
     211    int op1 = currentInstruction[2].u.operand;
     212    int op2 = currentInstruction[3].u.operand;
     213    emit_compareUnsigned(dst, op1, op2, BelowOrEqual);
     214}
     215
     216void JIT::emit_op_jbelow(Instruction* currentInstruction)
     217{
     218    int op1 = currentInstruction[1].u.operand;
     219    int op2 = currentInstruction[2].u.operand;
     220    unsigned target = currentInstruction[3].u.operand;
     221
     222    emit_compareUnsignedAndJump(op1, op2, target, Below);
     223}
     224
     225void JIT::emit_op_jbeloweq(Instruction* currentInstruction)
     226{
     227    int op1 = currentInstruction[1].u.operand;
     228    int op2 = currentInstruction[2].u.operand;
     229    unsigned target = currentInstruction[3].u.operand;
     230
     231    emit_compareUnsignedAndJump(op1, op2, target, BelowOrEqual);
    198232}
    199233
     
    265299}
    266300
     301void JIT::emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition condition)
     302{
     303    if (isOperandConstantInt(op2)) {
     304        emitGetVirtualRegister(op1, regT0);
     305        int32_t op2imm = getOperandConstantInt(op2);
     306        addJump(branch32(condition, regT0, Imm32(op2imm)), target);
     307    } else if (isOperandConstantInt(op1)) {
     308        emitGetVirtualRegister(op2, regT1);
     309        int32_t op1imm = getOperandConstantInt(op1);
     310        addJump(branch32(commute(condition), regT1, Imm32(op1imm)), target);
     311    } else {
     312        emitGetVirtualRegisters(op1, regT0, op2, regT1);
     313        addJump(branch32(condition, regT0, regT1), target);
     314    }
     315}
     316
     317void JIT::emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition condition)
     318{
     319    if (isOperandConstantInt(op2)) {
     320        emitGetVirtualRegister(op1, regT0);
     321        int32_t op2imm = getOperandConstantInt(op2);
     322        compare32(condition, regT0, Imm32(op2imm), regT0);
     323    } else if (isOperandConstantInt(op1)) {
     324        emitGetVirtualRegister(op2, regT0);
     325        int32_t op1imm = getOperandConstantInt(op1);
     326        compare32(commute(condition), regT0, Imm32(op1imm), regT0);
     327    } else {
     328        emitGetVirtualRegisters(op1, regT0, op2, regT1);
     329        compare32(condition, regT0, regT1, regT0);
     330    }
     331    emitTagBool(regT0);
     332    emitPutVirtualRegister(dst);
     333}
     334
    267335void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition condition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter)
    268336{
  • trunk/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp

    r222523 r222564  
    9393}
    9494
     95void JIT::emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition condition)
     96{
     97    if (isOperandConstantInt(op1)) {
     98        emitLoad(op2, regT3, regT2);
     99        addJump(branch32(commute(condition), regT2, Imm32(getConstantOperand(op1).asInt32())), target);
     100    } else if (isOperandConstantInt(op2)) {
     101        emitLoad(op1, regT1, regT0);
     102        addJump(branch32(condition, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
     103    } else {
     104        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
     105        addJump(branch32(condition, regT0, regT2), target);
     106    }
     107}
     108
     109
     110void JIT::emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition condition)
     111{
     112    if (isOperandConstantInt(op1)) {
     113        emitLoad(op2, regT3, regT2);
     114        compare32(commute(condition), regT2, Imm32(getConstantOperand(op1).asInt32()), regT0);
     115    } else if (isOperandConstantInt(op2)) {
     116        emitLoad(op1, regT1, regT0);
     117        compare32(condition, regT0, Imm32(getConstantOperand(op2).asInt32()), regT0);
     118    } else {
     119        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
     120        compare32(condition, regT0, regT2, regT0);
     121    }
     122    emitStoreBool(dst, regT0);
     123}
     124
    95125void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter)
    96126{
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm

    r222523 r222564  
    13991399
    14001400
     1401_llint_op_below:
     1402    traceExecution()
     1403    compareUnsigned(
     1404        macro (left, right, result) cib left, right, result end)
     1405
     1406
     1407_llint_op_beloweq:
     1408    traceExecution()
     1409    compareUnsigned(
     1410        macro (left, right, result) cibeq left, right, result end)
     1411
     1412
    14011413_llint_op_mod:
    14021414    traceExecution()
     
    15761588        macro (left, right, target) bdltun left, right, target end,
    15771589        _llint_slow_path_jngreatereq)
     1590
     1591
     1592_llint_op_jbelow:
     1593    traceExecution()
     1594    compareUnsignedJump(
     1595        macro (left, right, target) bib left, right, target end)
     1596
     1597
     1598_llint_op_jbeloweq:
     1599    traceExecution()
     1600    compareUnsignedJump(
     1601        macro (left, right, target) bibeq left, right, target end)
    15781602
    15791603
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r222523 r222564  
    17951795.opJneqPtrFallThrough:
    17961796    dispatch(constexpr op_jneq_ptr_length)
     1797
     1798
     1799macro compareUnsignedJump(integerCompare)
     1800    loadi 4[PC], t2
     1801    loadi 8[PC], t3
     1802    loadConstantOrVariable(t2, t0, t1)
     1803    loadConstantOrVariable2Reg(t3, t2, t3)
     1804    integerCompare(t1, t3, .jumpTarget)
     1805    dispatch(4)
     1806
     1807.jumpTarget:
     1808    dispatchBranch(12[PC])
     1809end
     1810
     1811
     1812macro compareUnsigned(integerCompareAndSet)
     1813    loadi 12[PC], t2
     1814    loadi 8[PC], t0
     1815    loadConstantOrVariable(t2, t3, t1)
     1816    loadConstantOrVariable2Reg(t0, t2, t0)
     1817    integerCompareAndSet(t0, t1, t0)
     1818    loadi 4[PC], t2
     1819    storei BooleanTag, TagOffset[cfr, t2, 8]
     1820    storei t0, PayloadOffset[cfr, t2, 8]
     1821    dispatch(4)
     1822end
    17971823
    17981824
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r222549 r222564  
    18141814
    18151815
     1816macro compareUnsignedJump(integerCompare)
     1817    loadisFromInstruction(1, t2)
     1818    loadisFromInstruction(2, t3)
     1819    loadConstantOrVariable(t2, t0)
     1820    loadConstantOrVariable(t3, t1)
     1821    integerCompare(t0, t1, .jumpTarget)
     1822    dispatch(4)
     1823
     1824.jumpTarget:
     1825    dispatchIntIndirect(3)
     1826end
     1827
     1828
     1829macro compareUnsigned(integerCompareAndSet)
     1830    traceExecution()
     1831    loadisFromInstruction(3, t0)
     1832    loadisFromInstruction(2, t2)
     1833    loadisFromInstruction(1, t3)
     1834    loadConstantOrVariable(t0, t1)
     1835    loadConstantOrVariable(t2, t0)
     1836    integerCompareAndSet(t0, t1, t0)
     1837    orq ValueFalse, t0
     1838    storeq t0, [cfr, t3, 8]
     1839    dispatch(4)
     1840end
     1841
     1842
    18161843_llint_op_switch_imm:
    18171844    traceExecution()
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r222523 r222564  
    189189        virtual bool isNewTarget() const { return false; }
    190190        virtual bool isBytecodeIntrinsicNode() const { return false; }
     191        virtual bool isBinaryOpNode() const { return false; }
    191192
    192193        virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode);
     
    10651066        ExpressionNode* rhs() { return m_expr2; };
    10661067
    1067     private:
     1068        bool isBinaryOpNode() const override { return true; }
     1069
     1070    private:
     1071        enum class UInt32Result { UInt32, Constant, };
     1072
    10681073        void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression);
    10691074        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     
    10791084    protected:
    10801085        bool m_rightHasAssignments;
     1086        bool m_shouldToUnsignedResult { true };
    10811087    };
    10821088
Note: See TracChangeset for help on using the changeset viewer.