Changeset 91099 in webkit
- Timestamp:
- Jul 15, 2011 1:14:27 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r91095 r91099 1 2011-07-15 Filip Pizlo <fpizlo@apple.com> 2 3 DFG JIT is inconsistent about fusing branches and speculating 4 integer comparisons for branches. 5 https://bugs.webkit.org/show_bug.cgi?id=64573 6 7 Reviewed by Gavin Barraclough. 8 9 This patch moves some of NonSpeculativeJIT's functionality up into the 10 JITCodeGenerator superclass so that it can be used from both JITs. Now, 11 in cases where the speculative JIT doesn't want to speculate but still 12 wants to emit good code, it can reliably emit the same code sequence as 13 the non-speculative JIT. This patch also extends the non-speculative 14 JIT's compare optimizations to include compare/branch fusing, and 15 extends the speculative JIT's compare optimizations to cover StrictEqual. 16 17 * dfg/DFGJITCodeGenerator.cpp: 18 (JSC::DFG::JITCodeGenerator::isKnownInteger): 19 (JSC::DFG::JITCodeGenerator::isKnownNumeric): 20 (JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranch): 21 (JSC::DFG::JITCodeGenerator::nonSpeculativeCompare): 22 * dfg/DFGJITCodeGenerator.h: 23 (JSC::DFG::JITCodeGenerator::detectPeepHoleBranch): 24 * dfg/DFGNonSpeculativeJIT.cpp: 25 (JSC::DFG::NonSpeculativeJIT::compile): 26 * dfg/DFGNonSpeculativeJIT.h: 27 * dfg/DFGOperations.cpp: 28 * dfg/DFGSpeculativeJIT.cpp: 29 (JSC::DFG::SpeculativeJIT::compare): 30 (JSC::DFG::SpeculativeJIT::compile): 31 * dfg/DFGSpeculativeJIT.h: 32 * wtf/Platform.h: 33 1 34 2011-07-14 Gavin Barraclough <barraclough@apple.com> 2 35 -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp
r91041 r91099 326 326 } 327 327 328 bool JITCodeGenerator::isKnownInteger(NodeIndex nodeIndex) 329 { 330 if (isInt32Constant(nodeIndex)) 331 return true; 332 333 GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()]; 334 335 DataFormat registerFormat = info.registerFormat(); 336 if (registerFormat != DataFormatNone) 337 return (registerFormat | DataFormatJS) == DataFormatJSInteger; 338 339 DataFormat spillFormat = info.spillFormat(); 340 if (spillFormat != DataFormatNone) 341 return (spillFormat | DataFormatJS) == DataFormatJSInteger; 342 343 ASSERT(isConstant(nodeIndex)); 344 return false; 345 } 346 347 bool JITCodeGenerator::isKnownNumeric(NodeIndex nodeIndex) 348 { 349 if (isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex)) 350 return true; 351 352 GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()]; 353 354 DataFormat registerFormat = info.registerFormat(); 355 if (registerFormat != DataFormatNone) 356 return (registerFormat | DataFormatJS) == DataFormatJSInteger 357 || (registerFormat | DataFormatJS) == DataFormatJSDouble; 358 359 DataFormat spillFormat = info.spillFormat(); 360 if (spillFormat != DataFormatNone) 361 return (spillFormat | DataFormatJS) == DataFormatJSInteger 362 || (spillFormat | DataFormatJS) == DataFormatJSDouble; 363 364 ASSERT(isConstant(nodeIndex)); 365 return false; 366 } 367 328 368 JITCompiler::Call JITCodeGenerator::cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, NodeType nodeType) 329 369 { … … 467 507 468 508 m_jit.addMethodGet(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction); 509 } 510 511 void JITCodeGenerator::nonSpeculativePeepholeBranch(Node& node, NodeIndex branchNodeIndex, MacroAssembler::RelationalCondition cond, Z_DFGOperation_EJJ helperFunction) 512 { 513 Node& branchNode = m_jit.graph()[branchNodeIndex]; 514 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset()); 515 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset()); 516 517 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero; 518 519 // The branch instruction will branch to the taken block. 520 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through. 521 if (taken == (m_block + 1)) { 522 cond = JITCompiler::invert(cond); 523 callResultCondition = JITCompiler::Zero; 524 BlockIndex tmp = taken; 525 taken = notTaken; 526 notTaken = tmp; 527 } 528 529 JSValueOperand arg1(this, node.child1()); 530 JSValueOperand arg2(this, node.child2()); 531 GPRReg arg1GPR = arg1.gpr(); 532 GPRReg arg2GPR = arg2.gpr(); 533 534 GPRTemporary result(this, arg2); 535 GPRReg resultGPR = result.gpr(); 536 537 JITCompiler::JumpList slowPath; 538 539 if (!isKnownInteger(node.child1())) 540 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg1GPR, GPRInfo::tagTypeNumberRegister)); 541 if (!isKnownInteger(node.child2())) 542 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister)); 543 544 addBranch(m_jit.branch32(cond, arg1GPR, arg2GPR), taken); 545 546 if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) { 547 addBranch(m_jit.jump(), notTaken); 548 549 slowPath.link(&m_jit); 550 551 silentSpillAllRegisters(resultGPR); 552 setupStubArguments(arg1GPR, arg2GPR); 553 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 554 appendCallWithExceptionCheck(helperFunction); 555 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 556 silentFillAllRegisters(resultGPR); 557 558 addBranch(m_jit.branchTest8(callResultCondition, resultGPR), taken); 559 } 560 561 if (notTaken != (m_block + 1)) 562 addBranch(m_jit.jump(), notTaken); 563 } 564 565 bool JITCodeGenerator::nonSpeculativeCompare(Node& node, MacroAssembler::RelationalCondition cond, Z_DFGOperation_EJJ helperFunction) 566 { 567 NodeIndex branchNodeIndex = detectPeepHoleBranch(); 568 if (branchNodeIndex != NoNode) { 569 ASSERT(node.adjustedRefCount() == 1); 570 571 nonSpeculativePeepholeBranch(node, branchNodeIndex, cond, helperFunction); 572 573 use(node.child1()); 574 use(node.child2()); 575 m_compileIndex = branchNodeIndex; 576 577 return true; 578 } 579 580 JSValueOperand arg1(this, node.child1()); 581 JSValueOperand arg2(this, node.child2()); 582 GPRReg arg1GPR = arg1.gpr(); 583 GPRReg arg2GPR = arg2.gpr(); 584 585 GPRTemporary result(this, arg2); 586 GPRReg resultGPR = result.gpr(); 587 588 JITCompiler::JumpList slowPath; 589 590 if (!isKnownInteger(node.child1())) 591 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg1GPR, GPRInfo::tagTypeNumberRegister)); 592 if (!isKnownInteger(node.child2())) 593 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister)); 594 595 m_jit.compare32(cond, arg1GPR, arg2GPR, resultGPR); 596 597 if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) { 598 JITCompiler::Jump haveResult = m_jit.jump(); 599 600 slowPath.link(&m_jit); 601 602 silentSpillAllRegisters(resultGPR); 603 setupStubArguments(arg1GPR, arg2GPR); 604 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 605 appendCallWithExceptionCheck(helperFunction); 606 m_jit.move(GPRInfo::returnValueGPR, resultGPR); 607 silentFillAllRegisters(resultGPR); 608 609 m_jit.andPtr(TrustedImm32(1), resultGPR); 610 611 haveResult.link(&m_jit); 612 } 613 614 m_jit.or32(TrustedImm32(ValueFalse), resultGPR); 615 616 jsValueResult(resultGPR, m_compileIndex); 617 618 return false; 469 619 } 470 620 -
trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
r91041 r91099 413 413 } 414 414 415 bool isKnownInteger(NodeIndex); 416 bool isKnownNumeric(NodeIndex); 417 415 418 // Checks/accessors for constant values. 416 419 bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); } … … 532 535 } 533 536 537 // Returns the node index of the branch node if peephole is okay, NoNode otherwise. 538 NodeIndex detectPeepHoleBranch() 539 { 540 NodeIndex lastNodeIndex = m_jit.graph().m_blocks[m_block]->end - 1; 541 542 // Check that no intervening nodes will be generated. 543 for (NodeIndex index = m_compileIndex + 1; index < lastNodeIndex; ++index) { 544 if (m_jit.graph()[index].shouldGenerate()) 545 return NoNode; 546 } 547 548 // Check if the lastNode is a branch on this node. 549 Node& lastNode = m_jit.graph()[lastNodeIndex]; 550 return lastNode.op == Branch && lastNode.child1() == m_compileIndex ? lastNodeIndex : NoNode; 551 } 552 534 553 JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), NodeType = GetById); 535 554 void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); 536 555 void cachedGetMethod(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); 556 557 void nonSpeculativePeepholeBranch(Node&, NodeIndex branchNodeIndex, MacroAssembler::RelationalCondition, Z_DFGOperation_EJJ helperFunction); 558 bool nonSpeculativeCompare(Node&, MacroAssembler::RelationalCondition, Z_DFGOperation_EJJ helperFunction); 537 559 538 560 void emitBranch(Node&); -
trunk/Source/JavaScriptCore/dfg/DFGNonSpeculativeJIT.cpp
r91041 r91099 121 121 } 122 122 123 bool NonSpeculativeJIT::isKnownInteger(NodeIndex nodeIndex)124 {125 if (isInt32Constant(nodeIndex))126 return true;127 128 GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()];129 130 DataFormat registerFormat = info.registerFormat();131 if (registerFormat != DataFormatNone)132 return (registerFormat | DataFormatJS) == DataFormatJSInteger;133 134 DataFormat spillFormat = info.spillFormat();135 if (spillFormat != DataFormatNone)136 return (spillFormat | DataFormatJS) == DataFormatJSInteger;137 138 ASSERT(isConstant(nodeIndex));139 return false;140 }141 142 bool NonSpeculativeJIT::isKnownNumeric(NodeIndex nodeIndex)143 {144 if (isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex))145 return true;146 147 GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()];148 149 DataFormat registerFormat = info.registerFormat();150 if (registerFormat != DataFormatNone)151 return (registerFormat | DataFormatJS) == DataFormatJSInteger152 || (registerFormat | DataFormatJS) == DataFormatJSDouble;153 154 DataFormat spillFormat = info.spillFormat();155 if (spillFormat != DataFormatNone)156 return (spillFormat | DataFormatJS) == DataFormatJSInteger157 || (spillFormat | DataFormatJS) == DataFormatJSDouble;158 159 ASSERT(isConstant(nodeIndex));160 return false;161 }162 163 123 void NonSpeculativeJIT::knownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute) 164 124 { … … 343 303 } 344 304 345 void NonSpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition cond, Z_DFGOperation_EJJ helperFunction)346 {347 // FIXME: should do some peephole to fuse compare/branch348 349 JSValueOperand arg1(this, node.child1());350 JSValueOperand arg2(this, node.child2());351 GPRReg arg1GPR = arg1.gpr();352 GPRReg arg2GPR = arg2.gpr();353 354 GPRTemporary result(this, arg2);355 GPRReg resultGPR = result.gpr();356 357 JITCompiler::JumpList slowPath;358 359 if (!isKnownInteger(node.child1()))360 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg1GPR, GPRInfo::tagTypeNumberRegister));361 if (!isKnownInteger(node.child2()))362 slowPath.append(m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister));363 364 m_jit.compare32(cond, arg1GPR, arg2GPR, resultGPR);365 366 JITCompiler::Jump haveResult = m_jit.jump();367 368 slowPath.link(&m_jit);369 370 silentSpillAllRegisters(resultGPR);371 setupStubArguments(arg1GPR, arg2GPR);372 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);373 appendCallWithExceptionCheck(helperFunction);374 m_jit.move(GPRInfo::returnValueGPR, resultGPR);375 silentFillAllRegisters(resultGPR);376 377 m_jit.andPtr(TrustedImm32(static_cast<int32_t>(1)), resultGPR);378 379 haveResult.link(&m_jit);380 381 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);382 jsValueResult(resultGPR, m_compileIndex);383 }384 385 305 void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, Node& node) 386 306 { … … 734 654 735 655 case CompareLess: 736 compare(node, MacroAssembler::LessThan, operationCompareLess); 656 if (nonSpeculativeCompare(node, MacroAssembler::LessThan, operationCompareLess)) 657 return; 737 658 break; 738 659 739 660 case CompareLessEq: 740 compare(node, MacroAssembler::LessThanOrEqual, operationCompareLessEq); 661 if (nonSpeculativeCompare(node, MacroAssembler::LessThanOrEqual, operationCompareLessEq)) 662 return; 741 663 break; 742 664 743 665 case CompareGreater: 744 compare(node, MacroAssembler::GreaterThan, operationCompareGreater); 666 if (nonSpeculativeCompare(node, MacroAssembler::GreaterThan, operationCompareGreater)) 667 return; 745 668 break; 746 669 747 670 case CompareGreaterEq: 748 compare(node, MacroAssembler::GreaterThanOrEqual, operationCompareGreaterEq); 671 if (nonSpeculativeCompare(node, MacroAssembler::GreaterThanOrEqual, operationCompareGreaterEq)) 672 return; 749 673 break; 750 674 751 675 case CompareEq: 752 compare(node, MacroAssembler::Equal, operationCompareEq); 676 if (nonSpeculativeCompare(node, MacroAssembler::Equal, operationCompareEq)) 677 return; 753 678 break; 754 679 755 680 case CompareStrictEq: 756 compare(node, MacroAssembler::Equal, operationCompareStrictEq); 681 if (nonSpeculativeCompare(node, MacroAssembler::Equal, operationCompareStrictEq)) 682 return; 757 683 break; 758 684 -
trunk/Source/JavaScriptCore/dfg/DFGNonSpeculativeJIT.h
r90371 r91099 83 83 void compile(SpeculationCheckIndexIterator&, BasicBlock&); 84 84 85 bool isKnownInteger(NodeIndex);86 bool isKnownNumeric(NodeIndex);87 88 85 // These methods are used to plant calls out to C++ 89 86 // helper routines to convert between types. … … 103 100 void knownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute); 104 101 void basicArithOp(NodeType op, Node&); 105 void compare(Node&, MacroAssembler::RelationalCondition, Z_DFGOperation_EJJ);106 102 107 103 EntryLocationVector m_entryLocations; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r91095 r91099 425 425 compilePeepHoleIntegerBranch(node, branchNodeIndex, condition); 426 426 else 427 compilePeepHoleCall(node, branchNodeIndex, operation);427 nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation); 428 428 429 429 use(node.child1()); … … 798 798 break; 799 799 800 case CompareStrictEq: { 801 SpeculateIntegerOperand op1(this, node.child1()); 802 SpeculateIntegerOperand op2(this, node.child2()); 803 GPRTemporary result(this, op1, op2); 804 805 m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr()); 806 807 // If we add a DataFormatBool, we should use it here. 808 m_jit.or32(TrustedImm32(ValueFalse), result.gpr()); 809 jsValueResult(result.gpr(), m_compileIndex); 810 break; 811 } 800 case CompareStrictEq: 801 if (compare(node, JITCompiler::Equal, operationCompareStrictEq)) 802 return; 803 break; 812 804 813 805 case GetByVal: { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r91022 r91099 140 140 void initializeVariableTypes(); 141 141 142 // Returns the node index of the branch node if peephole is okay, NoNode otherwise.143 NodeIndex detectPeepHoleBranch()144 {145 NodeIndex lastNodeIndex = m_jit.graph().m_blocks[m_block]->end - 1;146 147 // Check that no intervening nodes will be generated.148 for (NodeIndex index = m_compileIndex + 1; index < lastNodeIndex; ++index) {149 if (m_jit.graph()[index].shouldGenerate())150 return NoNode;151 }152 153 // Check if the lastNode is a branch on this node.154 Node& lastNode = m_jit.graph()[lastNodeIndex];155 return lastNode.op == Branch && lastNode.child1() == m_compileIndex ? lastNodeIndex : NoNode;156 }157 158 142 bool isInteger(NodeIndex nodeIndex) 159 143 {
Note: See TracChangeset
for help on using the changeset viewer.