Changeset 223318 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Oct 14, 2017, 8:35:48 AM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r223274 r223318 1 2017-10-14 Yusuke Suzuki <[email protected]> 2 3 Reland "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 We reland this patch without DFGStrengthReduction change to see what causes 9 regression in the iOS bot. 10 11 Sometimes, we would like to have UInt32 operations in JS. While VM does 12 not support UInt32 nicely, VM supports efficient Int32 operations. As long 13 as signedness does not matter, we can just perform Int32 operations instead 14 and recognize its bit pattern as UInt32. 15 16 But of course, some operations respect signedness. The most frequently 17 used one is comparison. Octane/zlib performs UInt32 comparison by performing 18 `val >>> 0`. It emits op_urshift and op_unsigned. op_urshift produces 19 UInt32 in Int32 form. And op_unsigned will generate Double value if 20 the generated Int32 is < 0 (which should be UInt32). 21 22 There is a chance for optimization. The given code pattern is the following. 23 24 op_unsigned(op_urshift(@1)) lessThan:< op_unsigned(op_urshift(@2)) 25 26 This can be converted to the following. 27 28 op_urshift(@1) below:< op_urshift(@2) 29 30 The above conversion is nice since 31 32 1. We can avoid op_unsigned. This could be unsignedness check in DFG. Since 33 this check depends on the value of Int32, dropping this check is not as easy as 34 removing Int32 edge filters. 35 36 2. We can perform unsigned comparison in Int32 form. We do not need to convert 37 them to DoubleRep. 38 39 Since the above comparison exists in Octane/zlib's *super* hot path, dropping 40 op_unsigned offers huge win. 41 42 At first, my patch attempts to convert the above thing in DFG pipeline. 43 However it poses several problems. 44 45 1. MovHint is not well removed. It makes UInt32ToNumber (which is for op_unsigned) live. 46 2. UInt32ToNumber could cause an OSR exit. So if we have the following nodes, 47 48 2: UInt32ToNumber(@0) 49 3: MovHint(@2, xxx) 50 4: UInt32ToNumber(@1) 51 5: MovHint(@1, xxx) 52 53 we could drop @5's MovHint. But @3 is difficult since @4 can exit. 54 55 So, instead, we start introducing a simple optimization in the bytecode compiler. 56 It performs pattern matching for op_urshift and comparison to drop op_unsigned. 57 We adds op_below and op_above families to bytecodes. They only accept Int32 and 58 perform unsigned comparison. 59 60 This offers 4% performance improvement in Octane/zlib. 61 62 baseline patched 63 64 zlib x2 431.07483+-16.28434 414.33407+-9.38375 might be 1.0404x faster 65 66 * bytecode/BytecodeDumper.cpp: 67 (JSC::BytecodeDumper<Block>::printCompareJump): 68 (JSC::BytecodeDumper<Block>::dumpBytecode): 69 * bytecode/BytecodeDumper.h: 70 * bytecode/BytecodeList.json: 71 * bytecode/BytecodeUseDef.h: 72 (JSC::computeUsesForBytecodeOffset): 73 (JSC::computeDefsForBytecodeOffset): 74 * bytecode/Opcode.h: 75 (JSC::isBranch): 76 * bytecode/PreciseJumpTargetsInlines.h: 77 (JSC::extractStoredJumpTargetsForBytecodeOffset): 78 * bytecompiler/BytecodeGenerator.cpp: 79 (JSC::BytecodeGenerator::emitJumpIfTrue): 80 (JSC::BytecodeGenerator::emitJumpIfFalse): 81 * bytecompiler/NodesCodegen.cpp: 82 (JSC::BinaryOpNode::emitBytecode): 83 * dfg/DFGAbstractInterpreterInlines.h: 84 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 85 * dfg/DFGByteCodeParser.cpp: 86 (JSC::DFG::ByteCodeParser::parseBlock): 87 * dfg/DFGCapabilities.cpp: 88 (JSC::DFG::capabilityLevel): 89 * dfg/DFGClobberize.h: 90 (JSC::DFG::clobberize): 91 * dfg/DFGDoesGC.cpp: 92 (JSC::DFG::doesGC): 93 * dfg/DFGFixupPhase.cpp: 94 (JSC::DFG::FixupPhase::fixupNode): 95 * dfg/DFGIntegerRangeOptimizationPhase.cpp: 96 * dfg/DFGNodeType.h: 97 * dfg/DFGPredictionPropagationPhase.cpp: 98 * dfg/DFGSafeToExecute.h: 99 (JSC::DFG::safeToExecute): 100 * dfg/DFGSpeculativeJIT.cpp: 101 (JSC::DFG::SpeculativeJIT::compileCompareUnsigned): 102 * dfg/DFGSpeculativeJIT.h: 103 * dfg/DFGSpeculativeJIT32_64.cpp: 104 (JSC::DFG::SpeculativeJIT::compile): 105 * dfg/DFGSpeculativeJIT64.cpp: 106 (JSC::DFG::SpeculativeJIT::compile): 107 * dfg/DFGValidate.cpp: 108 * ftl/FTLCapabilities.cpp: 109 (JSC::FTL::canCompile): 110 * ftl/FTLLowerDFGToB3.cpp: 111 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 112 (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelow): 113 (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelowEq): 114 * jit/JIT.cpp: 115 (JSC::JIT::privateCompileMainPass): 116 * jit/JIT.h: 117 * jit/JITArithmetic.cpp: 118 (JSC::JIT::emit_op_below): 119 (JSC::JIT::emit_op_beloweq): 120 (JSC::JIT::emit_op_jbelow): 121 (JSC::JIT::emit_op_jbeloweq): 122 (JSC::JIT::emit_compareUnsignedAndJump): 123 (JSC::JIT::emit_compareUnsigned): 124 * jit/JITArithmetic32_64.cpp: 125 (JSC::JIT::emit_compareUnsignedAndJump): 126 (JSC::JIT::emit_compareUnsigned): 127 * llint/LowLevelInterpreter.asm: 128 * llint/LowLevelInterpreter32_64.asm: 129 * llint/LowLevelInterpreter64.asm: 130 * parser/Nodes.h: 131 (JSC::ExpressionNode::isBinaryOpNode const): 132 1 133 2017-10-12 Yusuke Suzuki <[email protected]> 2 134 -
trunk/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
r222689 r223318 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
r222689 r223318 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
r222901 r223318 37 37 { "name" : "op_greater", "length" : 4 }, 38 38 { "name" : "op_greatereq", "length" : 4 }, 39 { "name" : "op_below", "length" : 4 }, 40 { "name" : "op_beloweq", "length" : 4 }, 39 41 { "name" : "op_inc", "length" : 2 }, 40 42 { "name" : "op_dec", "length" : 2 }, … … 116 118 { "name" : "op_jngreater", "length" : 4 }, 117 119 { "name" : "op_jngreatereq", "length" : 4 }, 120 { "name" : "op_jbelow", "length" : 4 }, 121 { "name" : "op_jbeloweq", "length" : 4 }, 118 122 { "name" : "op_loop_hint", "length" : 1 }, 119 123 { "name" : "op_switch_imm", "length" : 4 }, -
trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
r222689 r223318 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
r222689 r223318 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
r222689 r223318 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
r222895 r223318 1367 1367 void BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label& target) 1368 1368 { 1369 if (m_lastOpcodeID == op_less) {1369 auto fuseCompareAndJump = [&] (OpcodeID jumpID) { 1370 1370 int dstIndex; 1371 1371 int src1Index; … … 1378 1378 1379 1379 size_t begin = instructions().size(); 1380 emitOpcode( op_jless);1380 emitOpcode(jumpID); 1381 1381 instructions().append(src1Index); 1382 1382 instructions().append(src2Index); 1383 1383 instructions().append(target.bind(begin, instructions().size())); 1384 return true; 1385 } 1386 return false; 1387 }; 1388 1389 if (m_lastOpcodeID == op_less) { 1390 if (fuseCompareAndJump(op_jless)) 1384 1391 return; 1385 }1386 1392 } else if (m_lastOpcodeID == op_lesseq) { 1387 int dstIndex; 1388 int src1Index; 1389 int src2Index; 1390 1391 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1392 1393 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1394 rewindBinaryOp(); 1395 1396 size_t begin = instructions().size(); 1397 emitOpcode(op_jlesseq); 1398 instructions().append(src1Index); 1399 instructions().append(src2Index); 1400 instructions().append(target.bind(begin, instructions().size())); 1393 if (fuseCompareAndJump(op_jlesseq)) 1401 1394 return; 1402 }1403 1395 } else if (m_lastOpcodeID == op_greater) { 1404 int dstIndex; 1405 int src1Index; 1406 int src2Index; 1407 1408 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1409 1410 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1411 rewindBinaryOp(); 1412 1413 size_t begin = instructions().size(); 1414 emitOpcode(op_jgreater); 1415 instructions().append(src1Index); 1416 instructions().append(src2Index); 1417 instructions().append(target.bind(begin, instructions().size())); 1396 if (fuseCompareAndJump(op_jgreater)) 1418 1397 return; 1419 }1420 1398 } else if (m_lastOpcodeID == op_greatereq) { 1421 int dstIndex; 1422 int src1Index; 1423 int src2Index; 1424 1425 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1426 1427 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1428 rewindBinaryOp(); 1429 1430 size_t begin = instructions().size(); 1431 emitOpcode(op_jgreatereq); 1432 instructions().append(src1Index); 1433 instructions().append(src2Index); 1434 instructions().append(target.bind(begin, instructions().size())); 1399 if (fuseCompareAndJump(op_jgreatereq)) 1435 1400 return; 1436 } 1401 } else if (m_lastOpcodeID == op_below) { 1402 if (fuseCompareAndJump(op_jbelow)) 1403 return; 1404 } else if (m_lastOpcodeID == op_beloweq) { 1405 if (fuseCompareAndJump(op_jbeloweq)) 1406 return; 1437 1407 } else if (m_lastOpcodeID == op_eq_null && target.isForward()) { 1438 1408 int dstIndex; … … 1476 1446 void BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label& target) 1477 1447 { 1478 if (m_lastOpcodeID == op_less && target.isForward()) {1448 auto fuseCompareAndJump = [&] (OpcodeID jumpID, bool replaceOperands) { 1479 1449 int dstIndex; 1480 1450 int src1Index; … … 1487 1457 1488 1458 size_t begin = instructions().size(); 1489 emitOpcode(op_jnless); 1459 emitOpcode(jumpID); 1460 // Since op_below and op_beloweq only accepts Int32, replacing operands is not observable to users. 1461 if (replaceOperands) 1462 std::swap(src1Index, src2Index); 1490 1463 instructions().append(src1Index); 1491 1464 instructions().append(src2Index); 1492 1465 instructions().append(target.bind(begin, instructions().size())); 1466 return true; 1467 } 1468 return false; 1469 }; 1470 1471 if (m_lastOpcodeID == op_less && target.isForward()) { 1472 if (fuseCompareAndJump(op_jnless, false)) 1493 1473 return; 1494 }1495 1474 } else if (m_lastOpcodeID == op_lesseq && target.isForward()) { 1496 int dstIndex; 1497 int src1Index; 1498 int src2Index; 1499 1500 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1501 1502 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1503 rewindBinaryOp(); 1504 1505 size_t begin = instructions().size(); 1506 emitOpcode(op_jnlesseq); 1507 instructions().append(src1Index); 1508 instructions().append(src2Index); 1509 instructions().append(target.bind(begin, instructions().size())); 1475 if (fuseCompareAndJump(op_jnlesseq, false)) 1510 1476 return; 1511 }1512 1477 } else if (m_lastOpcodeID == op_greater && target.isForward()) { 1513 int dstIndex; 1514 int src1Index; 1515 int src2Index; 1516 1517 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1518 1519 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1520 rewindBinaryOp(); 1521 1522 size_t begin = instructions().size(); 1523 emitOpcode(op_jngreater); 1524 instructions().append(src1Index); 1525 instructions().append(src2Index); 1526 instructions().append(target.bind(begin, instructions().size())); 1478 if (fuseCompareAndJump(op_jngreater, false)) 1527 1479 return; 1528 }1529 1480 } else if (m_lastOpcodeID == op_greatereq && target.isForward()) { 1530 int dstIndex; 1531 int src1Index; 1532 int src2Index; 1533 1534 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 1535 1536 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 1537 rewindBinaryOp(); 1538 1539 size_t begin = instructions().size(); 1540 emitOpcode(op_jngreatereq); 1541 instructions().append(src1Index); 1542 instructions().append(src2Index); 1543 instructions().append(target.bind(begin, instructions().size())); 1481 if (fuseCompareAndJump(op_jngreatereq, false)) 1544 1482 return; 1545 } 1483 } else if (m_lastOpcodeID == op_below && target.isForward()) { 1484 if (fuseCompareAndJump(op_jbeloweq, true)) 1485 return; 1486 } else if (m_lastOpcodeID == op_beloweq && target.isForward()) { 1487 if (fuseCompareAndJump(op_jbelow, true)) 1488 return; 1546 1489 } else if (m_lastOpcodeID == op_not) { 1547 1490 int dstIndex; -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r223232 r223318 1989 1989 OpcodeID opcodeID = this->opcodeID(); 1990 1990 1991 if (opcodeID == op_less || opcodeID == op_lesseq || opcodeID == op_greater || opcodeID == op_greatereq) { 1992 auto isUInt32 = [&] (ExpressionNode* node) -> std::optional<UInt32Result> { 1993 if (node->isBinaryOpNode() && static_cast<BinaryOpNode*>(node)->opcodeID() == op_urshift) 1994 return UInt32Result::UInt32; 1995 if (node->isNumber() && static_cast<NumberNode*>(node)->isIntegerNode()) { 1996 int32_t value = static_cast<int32_t>(static_cast<IntegerNode*>(node)->value()); 1997 if (value >= 0) 1998 return UInt32Result::Constant; 1999 } 2000 return std::nullopt; 2001 }; 2002 auto leftResult = isUInt32(m_expr1); 2003 auto rightResult = isUInt32(m_expr2); 2004 if ((leftResult && rightResult) && (leftResult.value() == UInt32Result::UInt32 || rightResult.value() == UInt32Result::UInt32)) { 2005 auto* left = m_expr1; 2006 auto* right = m_expr2; 2007 if (left->isBinaryOpNode()) { 2008 ASSERT(static_cast<BinaryOpNode*>(left)->opcodeID() == op_urshift); 2009 static_cast<BinaryOpNode*>(left)->m_shouldToUnsignedResult = false; 2010 } 2011 if (right->isBinaryOpNode()) { 2012 ASSERT(static_cast<BinaryOpNode*>(right)->opcodeID() == op_urshift); 2013 static_cast<BinaryOpNode*>(right)->m_shouldToUnsignedResult = false; 2014 } 2015 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); 2016 RefPtr<RegisterID> src2 = generator.emitNode(right); 2017 generator.emitExpressionInfo(position(), position(), position()); 2018 2019 // Since the both sides only accept Int32, replacing operands is not observable to users. 2020 bool replaceOperands = false; 2021 OpcodeID resultOp = opcodeID; 2022 switch (opcodeID) { 2023 case op_less: 2024 resultOp = op_below; 2025 break; 2026 case op_lesseq: 2027 resultOp = op_beloweq; 2028 break; 2029 case op_greater: 2030 resultOp = op_below; 2031 replaceOperands = true; 2032 break; 2033 case op_greatereq: 2034 resultOp = op_beloweq; 2035 replaceOperands = true; 2036 break; 2037 default: 2038 RELEASE_ASSERT_NOT_REACHED(); 2039 } 2040 OperandTypes operandTypes(left->resultDescriptor(), right->resultDescriptor()); 2041 if (replaceOperands) { 2042 std::swap(src1, src2); 2043 operandTypes = OperandTypes(right->resultDescriptor(), left->resultDescriptor()); 2044 } 2045 return generator.emitBinaryOp(resultOp, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), operandTypes); 2046 } 2047 } 2048 1991 2049 if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { 1992 2050 generator.emitExpressionInfo(position(), position(), position()); … … 2024 2082 } 2025 2083 RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor())); 2026 if (opcodeID == op_urshift && dst != generator.ignoredResult()) 2027 return generator.emitUnaryOp(op_unsigned, result, result); 2084 if (m_shouldToUnsignedResult) { 2085 if (opcodeID == op_urshift && dst != generator.ignoredResult()) 2086 return generator.emitUnaryOp(op_unsigned, result, result); 2087 } 2028 2088 return result; 2029 2089 } -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r222689 r223318 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
r223159 r223318 4635 4635 } 4636 4636 4637 case op_below: { 4638 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 4639 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 4640 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelow, op1, op2)); 4641 NEXT_OPCODE(op_below); 4642 } 4643 4644 case op_beloweq: { 4645 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 4646 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 4647 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelowEq, op1, op2)); 4648 NEXT_OPCODE(op_beloweq); 4649 } 4650 4637 4651 case op_eq: { 4638 4652 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); … … 5080 5094 LAST_OPCODE(op_jngreatereq); 5081 5095 } 5082 5096 5097 case op_jbelow: { 5098 unsigned relativeOffset = currentInstruction[3].u.operand; 5099 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 5100 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 5101 Node* condition = addToGraph(CompareBelow, op1, op2); 5102 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbelow))), condition); 5103 LAST_OPCODE(op_jbelow); 5104 } 5105 5106 case op_jbeloweq: { 5107 unsigned relativeOffset = currentInstruction[3].u.operand; 5108 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 5109 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 5110 Node* condition = addToGraph(CompareBelowEq, op1, op2); 5111 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbeloweq))), condition); 5112 LAST_OPCODE(op_jbeloweq); 5113 } 5114 5083 5115 case op_switch_imm: { 5084 5116 SwitchData& data = *m_graph.m_switchData.add(); -
trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
r222689 r223318 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
r222689 r223318 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
r222689 r223318 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
r222689 r223318 143 143 else { 144 144 node->setArithMode(Arith::DoOverflow); 145 node->clearFlags(NodeMustGenerate);146 145 node->setResult(enableInt52() ? NodeResultInt52 : NodeResultDouble); 147 146 } … … 1595 1594 case GetTypedArrayByteOffset: { 1596 1595 fixEdge<KnownCellUse>(node->child1()); 1596 break; 1597 } 1598 1599 case CompareBelow: 1600 case CompareBelowEq: { 1601 fixEdge<Int32Use>(node->child1()); 1602 fixEdge<Int32Use>(node->child2()); 1597 1603 break; 1598 1604 } -
trunk/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
r223047 r223318 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
r222689 r223318 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
r222689 r223318 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
r222689 r223318 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
r222827 r223318 5730 5730 } 5731 5731 5732 void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition) 5733 { 5734 compileInt32Compare(node, condition); 5735 } 5736 5732 5737 bool SpeculativeJIT::compileStrictEq(Node* node) 5733 5738 { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r223047 r223318 2741 2741 2742 2742 bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ); 2743 void compileCompareUnsigned(Node*, MacroAssembler::RelationalCondition); 2743 2744 bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ); 2744 2745 void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r222689 r223318 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
r222827 r223318 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/DFGValidate.cpp
r222689 r223318 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
r222689 r223318 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
r223239 r223318 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(); … … 6404 6410 operationCompareStringGreaterEq, 6405 6411 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()))); 6406 6422 } 6407 6423 -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r223002 r223318 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
r222689 r223318 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
r222689 r223318 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
r222689 r223318 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
r223002 r223318 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
r223002 r223318 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
r223002 r223318 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
r223232 r223318 191 191 virtual bool isImportMeta() const { return false; } 192 192 virtual bool isBytecodeIntrinsicNode() const { return false; } 193 virtual bool isBinaryOpNode() const { return false; } 193 194 194 195 virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode); … … 1086 1087 ExpressionNode* rhs() { return m_expr2; }; 1087 1088 1088 private: 1089 bool isBinaryOpNode() const override { return true; } 1090 1091 private: 1092 enum class UInt32Result { UInt32, Constant, }; 1093 1089 1094 void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression); 1090 1095 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; … … 1100 1105 protected: 1101 1106 bool m_rightHasAssignments; 1107 bool m_shouldToUnsignedResult { true }; 1102 1108 }; 1103 1109
Note:
See TracChangeset
for help on using the changeset viewer.