Changeset 222518 in webkit
- Timestamp:
- Sep 26, 2017 1:32:18 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 36 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r222428 r222518 1 2017-09-26 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 1 29 2017-09-23 Keith Miller <keith_miller@apple.com> 2 30 -
trunk/Source/JavaScriptCore/ChangeLog
r222499 r222518 1 2017-09-26 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 1 132 2017-09-24 Keith Miller <keith_miller@apple.com> 2 133 -
trunk/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
r221196 r222518 361 361 362 362 template<class Block> 363 void 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 372 template<class Block> 363 373 void BytecodeDumper<Block>::printGetByIdOp(PrintStream& out, int location, const typename Block::Instruction*& it) 364 374 { … … 835 845 break; 836 846 } 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 } 837 855 case op_inc: { 838 856 int r0 = (++it)->u.operand; … … 1198 1216 } 1199 1217 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"); 1205 1219 break; 1206 1220 } 1207 1221 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"); 1213 1223 break; 1214 1224 } 1215 1225 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"); 1221 1227 break; 1222 1228 } 1223 1229 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"); 1229 1231 break; 1230 1232 } 1231 1233 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"); 1237 1235 break; 1238 1236 } 1239 1237 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"); 1245 1239 break; 1246 1240 } 1247 1241 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"); 1253 1243 break; 1254 1244 } 1255 1245 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"); 1261 1255 break; 1262 1256 } -
trunk/Source/JavaScriptCore/bytecode/BytecodeDumper.h
r218794 r222518 68 68 void printBinaryOp(PrintStream& out, int location, const Instruction*& it, const char* op); 69 69 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); 70 71 void printGetByIdOp(PrintStream& out, int location, const Instruction*& it); 71 72 void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&); -
trunk/Source/JavaScriptCore/bytecode/BytecodeList.json
r221196 r222518 33 33 { "name" : "op_greater", "length" : 4 }, 34 34 { "name" : "op_greatereq", "length" : 4 }, 35 { "name" : "op_below", "length" : 4 }, 36 { "name" : "op_beloweq", "length" : 4 }, 35 37 { "name" : "op_inc", "length" : 2 }, 36 38 { "name" : "op_dec", "length" : 2 }, … … 112 114 { "name" : "op_jngreater", "length" : 4 }, 113 115 { "name" : "op_jngreatereq", "length" : 4 }, 116 { "name" : "op_jbelow", "length" : 4 }, 117 { "name" : "op_jbeloweq", "length" : 4 }, 114 118 { "name" : "op_loop_hint", "length" : 1 }, 115 119 { "name" : "op_switch_imm", "length" : 4 }, -
trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
r221472 r222518 86 86 case op_jngreatereq: 87 87 case op_jless: 88 case op_jbelow: 89 case op_jbeloweq: 88 90 case op_set_function_name: 89 91 case op_log_shadow_chicken_tail: { … … 238 240 case op_greater: 239 241 case op_greatereq: 242 case op_below: 243 case op_beloweq: 240 244 case op_nstricteq: 241 245 case op_stricteq: … … 344 348 case op_jngreater: 345 349 case op_jngreatereq: 350 case op_jbelow: 351 case op_jbeloweq: 346 352 case op_loop_hint: 347 353 case op_switch_imm: … … 464 470 case op_greater: 465 471 case op_greatereq: 472 case op_below: 473 case op_beloweq: 466 474 case op_neq_null: 467 475 case op_eq_null: -
trunk/Source/JavaScriptCore/bytecode/Opcode.h
r217840 r222518 152 152 case op_jngreater: 153 153 case op_jngreatereq: 154 case op_jbelow: 155 case op_jbeloweq: 154 156 case op_switch_imm: 155 157 case op_switch_char: -
trunk/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h
r218412 r222518 56 56 case op_jngreater: 57 57 case op_jngreatereq: 58 case op_jbelow: 59 case op_jbeloweq: 58 60 function(current[3].u.operand); 59 61 break; -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r222473 r222518 1365 1365 void BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label& target) 1366 1366 { 1367 if (m_lastOpcodeID == op_less) {1367 auto fuseCompareAndJump = [&] (OpcodeID jumpID) { 1368 1368 int dstIndex; 1369 1369 int src1Index; … … 1376 1376 1377 1377 size_t begin = instructions().size(); 1378 emitOpcode( op_jless);1378 emitOpcode(jumpID); 1379 1379 instructions().append(src1Index); 1380 1380 instructions().append(src2Index); 1381 1381 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)) 1382 1389 return; 1383 }1384 1390 } 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)) 1399 1392 return; 1400 }1401 1393 } 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)) 1416 1395 return; 1417 }1418 1396 } 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)) 1433 1398 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; 1435 1405 } else if (m_lastOpcodeID == op_eq_null && target.isForward()) { 1436 1406 int dstIndex; … … 1474 1444 void BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label& target) 1475 1445 { 1476 if (m_lastOpcodeID == op_less && target.isForward()) {1446 auto fuseCompareAndJump = [&] (OpcodeID jumpID, bool replaceOperands) { 1477 1447 int dstIndex; 1478 1448 int src1Index; … … 1485 1455 1486 1456 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); 1488 1461 instructions().append(src1Index); 1489 1462 instructions().append(src2Index); 1490 1463 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)) 1491 1471 return; 1492 }1493 1472 } 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)) 1508 1474 return; 1509 }1510 1475 } 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)) 1525 1477 return; 1526 }1527 1478 } 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)) 1542 1480 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; 1544 1487 } else if (m_lastOpcodeID == op_not) { 1545 1488 int dstIndex; -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r222473 r222518 1982 1982 OpcodeID opcodeID = this->opcodeID(); 1983 1983 1984 if (opcodeID == op_less || opcodeID == op_lesseq || opcodeID == op_greater || opcodeID == op_greatereq) { 1985 enum class UInt32Result { 1986 UInt32, 1987 Constant, 1988 }; 1989 auto isUInt32 = [&] (ExpressionNode* node) -> std::optional<UInt32Result> { 1990 if (node->isBinaryOpNode() && static_cast<BinaryOpNode*>(node)->opcodeID() == op_urshift) 1991 return UInt32Result::UInt32; 1992 if (node->isNumber() && static_cast<NumberNode*>(node)->isIntegerNode()) { 1993 int32_t value = static_cast<int32_t>(static_cast<IntegerNode*>(node)->value()); 1994 if (value >= 0) 1995 return UInt32Result::Constant; 1996 } 1997 return std::nullopt; 1998 }; 1999 auto leftResult = isUInt32(m_expr1); 2000 auto rightResult = isUInt32(m_expr2); 2001 if ((leftResult && rightResult) && (leftResult.value() == UInt32Result::UInt32 || rightResult.value() == UInt32Result::UInt32)) { 2002 auto* left = m_expr1; 2003 auto* right = m_expr2; 2004 if (left->isBinaryOpNode()) { 2005 ASSERT(static_cast<BinaryOpNode*>(left)->opcodeID() == op_urshift); 2006 static_cast<BinaryOpNode*>(left)->m_shouldToUnsignedResult = false; 2007 } 2008 if (right->isBinaryOpNode()) { 2009 ASSERT(static_cast<BinaryOpNode*>(right)->opcodeID() == op_urshift); 2010 static_cast<BinaryOpNode*>(right)->m_shouldToUnsignedResult = false; 2011 } 2012 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); 2013 RefPtr<RegisterID> src2 = generator.emitNode(right); 2014 generator.emitExpressionInfo(position(), position(), position()); 2015 2016 // Since the both sides only accept Int32, replacing operands is not observable to users. 2017 bool replaceOperands = false; 2018 OpcodeID resultOp = opcodeID; 2019 switch (opcodeID) { 2020 case op_less: 2021 resultOp = op_below; 2022 break; 2023 case op_lesseq: 2024 resultOp = op_beloweq; 2025 break; 2026 case op_greater: 2027 resultOp = op_below; 2028 replaceOperands = true; 2029 break; 2030 case op_greatereq: 2031 resultOp = op_beloweq; 2032 replaceOperands = true; 2033 break; 2034 default: 2035 RELEASE_ASSERT_NOT_REACHED(); 2036 } 2037 OperandTypes operandTypes(left->resultDescriptor(), right->resultDescriptor()); 2038 if (replaceOperands) { 2039 std::swap(src1, src2); 2040 operandTypes = OperandTypes(right->resultDescriptor(), left->resultDescriptor()); 2041 } 2042 return generator.emitBinaryOp(resultOp, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), operandTypes); 2043 } 2044 } 2045 1984 2046 if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { 1985 2047 generator.emitExpressionInfo(position(), position(), position()); … … 2017 2079 } 2018 2080 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); 2081 if (m_shouldToUnsignedResult) { 2082 if (opcodeID == op_urshift && dst != generator.ignoredResult()) 2083 return generator.emitUnaryOp(op_unsigned, result, result); 2084 } 2021 2085 return result; 2022 2086 } -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r222143 r222518 1408 1408 break; 1409 1409 } 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 1411 1452 case CompareLess: 1412 1453 case CompareLessEq: -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r222384 r222518 4750 4750 } 4751 4751 4752 case op_below: { 4753 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 4754 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 4755 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelow, op1, op2)); 4756 NEXT_OPCODE(op_below); 4757 } 4758 4759 case op_beloweq: { 4760 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 4761 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 4762 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelowEq, op1, op2)); 4763 NEXT_OPCODE(op_beloweq); 4764 } 4765 4752 4766 case op_eq: { 4753 4767 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); … … 5195 5209 LAST_OPCODE(op_jngreatereq); 5196 5210 } 5197 5211 5212 case op_jbelow: { 5213 unsigned relativeOffset = currentInstruction[3].u.operand; 5214 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 5215 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 5216 Node* condition = addToGraph(CompareBelow, op1, op2); 5217 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbelow))), condition); 5218 LAST_OPCODE(op_jbelow); 5219 } 5220 5221 case op_jbeloweq: { 5222 unsigned relativeOffset = currentInstruction[3].u.operand; 5223 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 5224 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 5225 Node* condition = addToGraph(CompareBelowEq, op1, op2); 5226 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbeloweq))), condition); 5227 LAST_OPCODE(op_jbeloweq); 5228 } 5229 5198 5230 case op_switch_imm: { 5199 5231 SwitchData& data = *m_graph.m_switchData.add(); -
trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
r221080 r222518 152 152 case op_greater: 153 153 case op_greatereq: 154 case op_below: 155 case op_beloweq: 154 156 case op_eq: 155 157 case op_eq_null: … … 193 195 case op_jngreater: 194 196 case op_jngreatereq: 197 case op_jbelow: 198 case op_jbeloweq: 195 199 case op_loop_hint: 196 200 case op_check_traps: -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r222143 r222518 1487 1487 def(PureValue(node)); 1488 1488 return; 1489 1490 case CompareBelow: 1491 case CompareBelowEq: 1492 def(PureValue(node)); 1493 return; 1489 1494 1490 1495 case CompareEq: -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r222143 r222518 144 144 case CompareGreater: 145 145 case CompareGreaterEq: 146 case CompareBelow: 147 case CompareBelowEq: 146 148 case CompareEq: 147 149 case CompareStrictEq: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r222143 r222518 143 143 else { 144 144 node->setArithMode(Arith::DoOverflow); 145 node->clearFlags(NodeMustGenerate);146 145 node->setResult(enableInt52() ? NodeResultInt52 : NodeResultDouble); 147 146 } … … 1571 1570 case GetTypedArrayByteOffset: { 1572 1571 fixEdge<KnownCellUse>(node->child1()); 1572 break; 1573 } 1574 1575 case CompareBelow: 1576 case CompareBelowEq: { 1577 fixEdge<Int32Use>(node->child1()); 1578 fixEdge<Int32Use>(node->child2()); 1573 1579 break; 1574 1580 } -
trunk/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
r221954 r222518 1141 1141 terminal->child1().node(), m_zero, Relationship::NotEqual, 0); 1142 1142 } else { 1143 // FIXME: Handle CompareBelow and CompareBelowEq. 1143 1144 Node* compare = terminal->child1().node(); 1144 1145 switch (compare->op()) { -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r222143 r222518 122 122 macro(ValueToInt32, NodeResultInt32) \ 123 123 /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\ 124 macro(UInt32ToNumber, NodeResultNumber | NodeMustGenerate) \124 macro(UInt32ToNumber, NodeResultNumber) \ 125 125 /* Converts booleans to numbers but passes everything else through. */\ 126 126 macro(BooleanToNumber, NodeResultJS) \ … … 287 287 macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \ 288 288 macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \ 289 macro(CompareBelow, NodeResultBoolean) \ 290 macro(CompareBelowEq, NodeResultBoolean) \ 289 291 macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \ 290 292 macro(CompareStrictEq, NodeResultBoolean) \ -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r222143 r222518 819 819 case CompareGreater: 820 820 case CompareGreaterEq: 821 case CompareBelow: 822 case CompareBelowEq: 821 823 case CompareEq: 822 824 case CompareStrictEq: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r222143 r222518 267 267 case CompareGreater: 268 268 case CompareGreaterEq: 269 case CompareBelow: 270 case CompareBelowEq: 269 271 case CompareEq: 270 272 case CompareStrictEq: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r222143 r222518 5711 5711 } 5712 5712 5713 void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition) 5714 { 5715 compileInt32Compare(node, condition); 5716 } 5717 5713 5718 bool SpeculativeJIT::compileStrictEq(Node* node) 5714 5719 { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r222143 r222518 2721 2721 2722 2722 bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ); 2723 void compileCompareUnsigned(Node*, MacroAssembler::RelationalCondition); 2723 2724 bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ); 2724 2725 void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r222143 r222518 2521 2521 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq)) 2522 2522 return; 2523 break; 2524 2525 case CompareBelow: 2526 compileCompareUnsigned(node, JITCompiler::Below); 2527 break; 2528 2529 case CompareBelowEq: 2530 compileCompareUnsigned(node, JITCompiler::BelowOrEqual); 2523 2531 break; 2524 2532 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r222384 r222518 2663 2663 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq)) 2664 2664 return; 2665 break; 2666 2667 case CompareBelow: 2668 compileCompareUnsigned(node, JITCompiler::Below); 2669 break; 2670 2671 case CompareBelowEq: 2672 compileCompareUnsigned(node, JITCompiler::BelowOrEqual); 2665 2673 break; 2666 2674 -
trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
r221769 r222518 266 266 break; 267 267 } 268 269 case CompareEq: 270 case CompareLess: 271 case CompareLessEq: 272 case CompareGreater: 273 case CompareGreaterEq: { 274 if (m_node->isBinaryUseKind(Int32Use)) { 275 enum class UInt32Result { UInt32, Constant }; 276 auto isUInt32 = [&] (Edge& edge) -> std::optional<UInt32Result> { 277 if (edge->op() == UInt32ToNumber) 278 return UInt32Result::UInt32; 279 if (edge->isInt32Constant()) { 280 if (edge->asInt32() >= 0) 281 return UInt32Result::Constant; 282 } 283 return std::nullopt; 284 }; 285 286 auto child1Result = isUInt32(m_node->child1()); 287 auto child2Result = isUInt32(m_node->child2()); 288 if ((child1Result && child2Result) && (child1Result.value() == UInt32Result::UInt32 || child2Result.value() == UInt32Result::UInt32)) { 289 NodeType op = m_node->op(); 290 bool replaceOperands = false; 291 switch (m_node->op()) { 292 case CompareEq: 293 op = CompareEq; 294 break; 295 case CompareLess: 296 op = CompareBelow; 297 break; 298 case CompareLessEq: 299 op = CompareBelowEq; 300 break; 301 case CompareGreater: 302 op = CompareBelow; 303 replaceOperands = true; 304 break; 305 case CompareGreaterEq: 306 op = CompareBelowEq; 307 replaceOperands = true; 308 break; 309 default: 310 RELEASE_ASSERT_NOT_REACHED(); 311 } 312 313 auto extractChild = [&] (Edge& edge) { 314 if (edge->op() == UInt32ToNumber) 315 return edge->child1().node(); 316 return edge.node(); 317 }; 318 319 m_node->setOp(op); 320 m_node->child1() = Edge(extractChild(m_node->child1()), Int32Use); 321 m_node->child2() = Edge(extractChild(m_node->child2()), Int32Use); 322 if (replaceOperands) 323 std::swap(m_node->child1(), m_node->child2()); 324 m_changed = true; 325 } 326 } 327 break; 328 } 268 329 269 330 case Flush: { -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r222060 r222518 268 268 case CompareGreater: 269 269 case CompareGreaterEq: 270 case CompareBelow: 271 case CompareBelowEq: 270 272 case CompareEq: 271 273 case CompareStrictEq: -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r222143 r222518 285 285 case CompareGreater: 286 286 case CompareGreaterEq: 287 case CompareBelow: 288 case CompareBelowEq: 287 289 case CompareStrictEq: 288 290 case DefineDataProperty: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r222384 r222518 933 933 compileCompareGreaterEq(); 934 934 break; 935 case CompareBelow: 936 compileCompareBelow(); 937 break; 938 case CompareBelowEq: 939 compileCompareBelowEq(); 940 break; 935 941 case CompareEqPtr: 936 942 compileCompareEqPtr(); … … 6338 6344 operationCompareStringGreaterEq, 6339 6345 operationCompareGreaterEq); 6346 } 6347 6348 void compileCompareBelow() 6349 { 6350 setBoolean(m_out.below(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); 6351 } 6352 6353 void compileCompareBelowEq() 6354 { 6355 setBoolean(m_out.belowOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); 6340 6356 } 6341 6357 -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r221822 r222518 302 302 DEFINE_OP(op_eq) 303 303 DEFINE_OP(op_eq_null) 304 DEFINE_OP(op_below) 305 DEFINE_OP(op_beloweq) 304 306 DEFINE_OP(op_try_get_by_id) 305 307 case op_get_array_length: … … 332 334 DEFINE_OP(op_jngreater) 333 335 DEFINE_OP(op_jngreatereq) 336 DEFINE_OP(op_jbelow) 337 DEFINE_OP(op_jbeloweq) 334 338 DEFINE_OP(op_jtrue) 335 339 DEFINE_OP(op_loop_hint) -
trunk/Source/JavaScriptCore/jit/JIT.h
r221196 r222518 461 461 462 462 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); 463 465 void emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&); 464 466 … … 500 502 void emit_op_eq(Instruction*); 501 503 void emit_op_eq_null(Instruction*); 504 void emit_op_below(Instruction*); 505 void emit_op_beloweq(Instruction*); 502 506 void emit_op_try_get_by_id(Instruction*); 503 507 void emit_op_get_by_id(Instruction*); … … 530 534 void emit_op_jngreater(Instruction*); 531 535 void emit_op_jngreatereq(Instruction*); 536 void emit_op_jbelow(Instruction*); 537 void emit_op_jbeloweq(Instruction*); 532 538 void emit_op_jtrue(Instruction*); 533 539 void emit_op_loop_hint(Instruction*); -
trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp
r206392 r222518 196 196 197 197 emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrUnordered, operationCompareGreaterEq, true, iter); 198 } 199 200 void 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 208 void 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 216 void 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 225 void 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); 198 232 } 199 233 … … 265 299 } 266 300 301 void 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 317 void 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 267 335 void 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) 268 336 { -
trunk/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp
r198364 r222518 93 93 } 94 94 95 void 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 110 void 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 95 125 void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter) 96 126 { -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r222136 r222518 1399 1399 1400 1400 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 1401 1413 _llint_op_mod: 1402 1414 traceExecution() … … 1576 1588 macro (left, right, target) bdltun left, right, target end, 1577 1589 _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) 1578 1602 1579 1603 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r222136 r222518 1795 1795 .opJneqPtrFallThrough: 1796 1796 dispatch(constexpr op_jneq_ptr_length) 1797 1798 1799 macro 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]) 1809 end 1810 1811 1812 macro 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) 1822 end 1797 1823 1798 1824 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r222136 r222518 1814 1814 1815 1815 1816 macro 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) 1826 end 1827 1828 1829 macro 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) 1840 end 1841 1842 1816 1843 _llint_op_switch_imm: 1817 1844 traceExecution() -
trunk/Source/JavaScriptCore/parser/Nodes.h
r221622 r222518 189 189 virtual bool isNewTarget() const { return false; } 190 190 virtual bool isBytecodeIntrinsicNode() const { return false; } 191 virtual bool isBinaryOpNode() const { return false; } 191 192 192 193 virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode); … … 1065 1066 ExpressionNode* rhs() { return m_expr2; }; 1066 1067 1068 bool isBinaryOpNode() const override { return true; } 1069 1067 1070 private: 1068 1071 void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression); … … 1079 1082 protected: 1080 1083 bool m_rightHasAssignments; 1084 bool m_shouldToUnsignedResult { true }; 1081 1085 }; 1082 1086
Note: See TracChangeset
for help on using the changeset viewer.