B3 should be able to compile a program with ChillDiv
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Nov 2015 07:21:23 +0000 (07:21 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Nov 2015 07:21:23 +0000 (07:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151114

Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

This change is about a lot more than ChillDiv. I picked that as the next thing to lower
because I knew that it would force me to come up with a sensible idiom for doing
stepwise lowerings that require breaking basic blocks. The idea is that you want to
write a loop that iterates forward over the program, which turns some operations that
currently are just single Values into an entire little sub-CFGs. That requires splitting
the block that contained the original Value. That's tricky if you then want to keep
iterating: the index of the Value you were last looking at has now changed and your
InsertionSets are now invalid.

This introduces an idiom that handles this. It's BlockInsertionSet::splitBefore(). The
idea is that it uses the current block before the split as the continuation after the
split. When you call splitBefore(), you pass it your loop index and your InsertionSet
(if applicable). It makes sure that it changes those auxiliary things in such a way that
you can keep looping.

This uncovered some bugs, since this is the first time that we're compiling cross edges.

Because ChillDiv is really a division, I also had to write a bunch of code to support
the ordinary B3 Div. While doing that, I realized that there was asymmetry to that
constness of the Value constant folding methods, so I fixed that as well.

* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::mul32):
(JSC::MacroAssemblerX86Common::x86ConvertToDoubleWord32):
(JSC::MacroAssemblerX86Common::x86Div32):
(JSC::MacroAssemblerX86Common::neg32):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::mul64):
(JSC::MacroAssemblerX86_64::x86ConvertToQuadWord64):
(JSC::MacroAssemblerX86_64::x86Div64):
(JSC::MacroAssemblerX86_64::neg64):
* assembler/X86Assembler.h:
(JSC::X86Assembler::idivl_r):
(JSC::X86Assembler::idivq_r):
(JSC::X86Assembler::cmpl_rr):
(JSC::X86Assembler::cdq):
(JSC::X86Assembler::cdqq):
(JSC::X86Assembler::fstps):
* b3/B3BasicBlock.cpp:
(JSC::B3::BasicBlock::append):
(JSC::B3::BasicBlock::replaceLast):
(JSC::B3::BasicBlock::appendIntConstant):
(JSC::B3::BasicBlock::replaceSuccessor):
(JSC::B3::BasicBlock::addPredecessor):
(JSC::B3::BasicBlock::replacePredecessor):
(JSC::B3::BasicBlock::updatePredecessors):
(JSC::B3::BasicBlock::dump):
* b3/B3BasicBlock.h:
(JSC::B3::BasicBlock::values):
(JSC::B3::BasicBlock::numPredecessors):
(JSC::B3::BasicBlock::predecessor):
(JSC::B3::BasicBlock::frequency):
* b3/B3BasicBlockInlines.h:
(JSC::B3::BasicBlock::appendNew):
(JSC::B3::BasicBlock::replaceLastWithNew):
(JSC::B3::BasicBlock::numSuccessors):
* b3/B3BasicBlockUtils.h:
(JSC::B3::replacePredecessor):
(JSC::B3::updatePredecessors):
(JSC::B3::resetReachability):
* b3/B3BlockInsertionSet.cpp: Added.
(JSC::B3::BlockInsertionSet::BlockInsertionSet):
(JSC::B3::BlockInsertionSet::~BlockInsertionSet):
(JSC::B3::BlockInsertionSet::insert):
(JSC::B3::BlockInsertionSet::insertBefore):
(JSC::B3::BlockInsertionSet::splitForward):
(JSC::B3::BlockInsertionSet::execute):
* b3/B3BlockInsertionSet.h: Added.
* b3/B3Common.h:
(JSC::B3::isRepresentableAs):
(JSC::B3::chillDiv):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::addConstant):
(JSC::B3::Const32Value::subConstant):
(JSC::B3::Const32Value::divConstant):
(JSC::B3::Const32Value::bitAndConstant):
(JSC::B3::Const32Value::bitOrConstant):
(JSC::B3::Const32Value::bitXorConstant):
(JSC::B3::Const32Value::shlConstant):
(JSC::B3::Const32Value::sShrConstant):
(JSC::B3::Const32Value::zShrConstant):
(JSC::B3::Const32Value::equalConstant):
(JSC::B3::Const32Value::notEqualConstant):
(JSC::B3::Const32Value::lessThanConstant):
(JSC::B3::Const32Value::greaterThanConstant):
(JSC::B3::Const32Value::lessEqualConstant):
(JSC::B3::Const32Value::greaterEqualConstant):
(JSC::B3::Const32Value::aboveConstant):
(JSC::B3::Const32Value::belowConstant):
(JSC::B3::Const32Value::aboveEqualConstant):
(JSC::B3::Const32Value::belowEqualConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::addConstant):
(JSC::B3::Const64Value::subConstant):
(JSC::B3::Const64Value::divConstant):
(JSC::B3::Const64Value::bitAndConstant):
(JSC::B3::Const64Value::bitOrConstant):
(JSC::B3::Const64Value::bitXorConstant):
(JSC::B3::Const64Value::shlConstant):
(JSC::B3::Const64Value::sShrConstant):
(JSC::B3::Const64Value::zShrConstant):
(JSC::B3::Const64Value::equalConstant):
(JSC::B3::Const64Value::notEqualConstant):
(JSC::B3::Const64Value::lessThanConstant):
(JSC::B3::Const64Value::greaterThanConstant):
(JSC::B3::Const64Value::lessEqualConstant):
(JSC::B3::Const64Value::greaterEqualConstant):
(JSC::B3::Const64Value::aboveConstant):
(JSC::B3::Const64Value::belowConstant):
(JSC::B3::Const64Value::aboveEqualConstant):
(JSC::B3::Const64Value::belowEqualConstant):
* b3/B3Const64Value.h:
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::addConstant):
(JSC::B3::ConstDoubleValue::subConstant):
(JSC::B3::ConstDoubleValue::divConstant):
(JSC::B3::ConstDoubleValue::equalConstant):
(JSC::B3::ConstDoubleValue::notEqualConstant):
(JSC::B3::ConstDoubleValue::lessThanConstant):
(JSC::B3::ConstDoubleValue::greaterThanConstant):
(JSC::B3::ConstDoubleValue::lessEqualConstant):
(JSC::B3::ConstDoubleValue::greaterEqualConstant):
* b3/B3ConstDoubleValue.h:
* b3/B3ControlValue.cpp:
(JSC::B3::ControlValue::~ControlValue):
(JSC::B3::ControlValue::replaceSuccessor):
(JSC::B3::ControlValue::convertToJump):
* b3/B3ControlValue.h:
* b3/B3Generate.cpp:
(JSC::B3::generateToAir):
* b3/B3GenericFrequentedBlock.h:
(JSC::B3::GenericFrequentedBlock::block):
(JSC::B3::GenericFrequentedBlock::frequency):
(JSC::B3::GenericFrequentedBlock::dump):
* b3/B3InsertionSet.cpp:
(JSC::B3::InsertionSet::insertIntConstant):
(JSC::B3::InsertionSet::execute):
* b3/B3InsertionSet.h:
* b3/B3LowerMacros.cpp: Added.
(JSC::B3::lowerMacros):
* b3/B3LowerMacros.h: Added.
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Opcode.h:
* b3/B3Procedure.cpp:
(JSC::B3::Procedure::addBlock):
(JSC::B3::Procedure::addIntConstant):
(JSC::B3::Procedure::addBoolConstant):
(JSC::B3::Procedure::resetValueOwners):
* b3/B3Procedure.h:
(JSC::B3::Procedure::takeByproducts):
* b3/B3ReduceStrength.cpp:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::addConstant):
(JSC::B3::Value::subConstant):
(JSC::B3::Value::divConstant):
(JSC::B3::Value::bitAndConstant):
(JSC::B3::Value::bitOrConstant):
(JSC::B3::Value::bitXorConstant):
(JSC::B3::Value::shlConstant):
(JSC::B3::Value::sShrConstant):
(JSC::B3::Value::zShrConstant):
(JSC::B3::Value::equalConstant):
(JSC::B3::Value::notEqualConstant):
(JSC::B3::Value::lessThanConstant):
(JSC::B3::Value::greaterThanConstant):
(JSC::B3::Value::lessEqualConstant):
(JSC::B3::Value::greaterEqualConstant):
(JSC::B3::Value::aboveConstant):
(JSC::B3::Value::belowConstant):
(JSC::B3::Value::aboveEqualConstant):
(JSC::B3::Value::belowEqualConstant):
* b3/B3Value.h:
* b3/air/AirGenerate.cpp:
(JSC::B3::Air::generate):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::isUrshift64Valid):
(JSC::B3::Air::isX86DivHelperValid):
(JSC::B3::Air::isX86ConvertToDoubleWord32Valid):
(JSC::B3::Air::isX86ConvertToDoubleWord64Valid):
(JSC::B3::Air::isX86Div32Valid):
(JSC::B3::Air::isX86Div64Valid):
* b3/air/AirOpcode.opcodes:
* b3/air/AirSimplifyCFG.cpp:
(JSC::B3::Air::simplifyCFG):
* b3/testb3.cpp:
(JSC::B3::testCallFunctionWithHellaDoubleArguments):
(JSC::B3::testChillDiv):
(JSC::B3::testChillDivTwice):
(JSC::B3::testChillDiv64):
(JSC::B3::run):
* dfg/DFGBlockInsertionSet.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithDiv):
(JSC::DFG::SpeculativeJIT::compileArithMod):
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_mod):
* jit/JITArithmetic32_64.cpp:
(JSC::JIT::emit_op_mod):
* wasm/WASMFunctionCompiler.h:
(JSC::WASMFunctionCompiler::buildBinaryI32):

Source/WTF:

Needed to beef up some compiler algorithms. All of the hardening was about making them
work with objects that have move semantics but not copy semantics. This arises in B3
basic block insertion sets.

* wtf/BubbleSort.h:
(WTF::bubbleSort):
* wtf/Insertion.h:
(WTF::Insertion::Insertion):
(WTF::Insertion::index):
(WTF::Insertion::element):
(WTF::Insertion::operator<):
(WTF::executeInsertions):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192295 268f45cc-cd09-0410-ab3c-d52691b4dbfc

47 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/b3/B3BasicBlock.cpp
Source/JavaScriptCore/b3/B3BasicBlock.h
Source/JavaScriptCore/b3/B3BasicBlockInlines.h
Source/JavaScriptCore/b3/B3BasicBlockUtils.h
Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/B3BlockInsertionSet.h [new file with mode: 0644]
Source/JavaScriptCore/b3/B3Common.h
Source/JavaScriptCore/b3/B3Const32Value.cpp
Source/JavaScriptCore/b3/B3Const32Value.h
Source/JavaScriptCore/b3/B3Const64Value.cpp
Source/JavaScriptCore/b3/B3Const64Value.h
Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp
Source/JavaScriptCore/b3/B3ConstDoubleValue.h
Source/JavaScriptCore/b3/B3ControlValue.cpp
Source/JavaScriptCore/b3/B3ControlValue.h
Source/JavaScriptCore/b3/B3Generate.cpp
Source/JavaScriptCore/b3/B3GenericFrequentedBlock.h
Source/JavaScriptCore/b3/B3InsertionSet.cpp
Source/JavaScriptCore/b3/B3InsertionSet.h
Source/JavaScriptCore/b3/B3LowerMacros.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/B3LowerMacros.h [new file with mode: 0644]
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Source/JavaScriptCore/b3/B3Opcode.h
Source/JavaScriptCore/b3/B3Procedure.cpp
Source/JavaScriptCore/b3/B3Procedure.h
Source/JavaScriptCore/b3/B3ReduceStrength.cpp
Source/JavaScriptCore/b3/B3Validate.cpp
Source/JavaScriptCore/b3/B3Value.cpp
Source/JavaScriptCore/b3/B3Value.h
Source/JavaScriptCore/b3/air/AirGenerate.cpp
Source/JavaScriptCore/b3/air/AirInstInlines.h
Source/JavaScriptCore/b3/air/AirOpcode.opcodes
Source/JavaScriptCore/b3/air/AirSimplifyCFG.cpp
Source/JavaScriptCore/b3/testb3.cpp
Source/JavaScriptCore/dfg/DFGBlockInsertionSet.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/jit/JITArithmetic.cpp
Source/JavaScriptCore/jit/JITArithmetic32_64.cpp
Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
Source/WTF/ChangeLog
Source/WTF/wtf/BubbleSort.h
Source/WTF/wtf/Insertion.h

index 1723264..e7b3852 100644 (file)
@@ -1,3 +1,215 @@
+2015-11-10  Filip Pizlo  <fpizlo@apple.com>
+
+        B3 should be able to compile a program with ChillDiv
+        https://bugs.webkit.org/show_bug.cgi?id=151114
+
+        Reviewed by Benjamin Poulain.
+
+        This change is about a lot more than ChillDiv. I picked that as the next thing to lower
+        because I knew that it would force me to come up with a sensible idiom for doing
+        stepwise lowerings that require breaking basic blocks. The idea is that you want to
+        write a loop that iterates forward over the program, which turns some operations that
+        currently are just single Values into an entire little sub-CFGs. That requires splitting
+        the block that contained the original Value. That's tricky if you then want to keep
+        iterating: the index of the Value you were last looking at has now changed and your
+        InsertionSets are now invalid.
+
+        This introduces an idiom that handles this. It's BlockInsertionSet::splitBefore(). The
+        idea is that it uses the current block before the split as the continuation after the
+        split. When you call splitBefore(), you pass it your loop index and your InsertionSet
+        (if applicable). It makes sure that it changes those auxiliary things in such a way that
+        you can keep looping.
+
+        This uncovered some bugs, since this is the first time that we're compiling cross edges.
+
+        Because ChillDiv is really a division, I also had to write a bunch of code to support
+        the ordinary B3 Div. While doing that, I realized that there was asymmetry to that
+        constness of the Value constant folding methods, so I fixed that as well.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::mul32):
+        (JSC::MacroAssemblerX86Common::x86ConvertToDoubleWord32):
+        (JSC::MacroAssemblerX86Common::x86Div32):
+        (JSC::MacroAssemblerX86Common::neg32):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::mul64):
+        (JSC::MacroAssemblerX86_64::x86ConvertToQuadWord64):
+        (JSC::MacroAssemblerX86_64::x86Div64):
+        (JSC::MacroAssemblerX86_64::neg64):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::idivl_r):
+        (JSC::X86Assembler::idivq_r):
+        (JSC::X86Assembler::cmpl_rr):
+        (JSC::X86Assembler::cdq):
+        (JSC::X86Assembler::cdqq):
+        (JSC::X86Assembler::fstps):
+        * b3/B3BasicBlock.cpp:
+        (JSC::B3::BasicBlock::append):
+        (JSC::B3::BasicBlock::replaceLast):
+        (JSC::B3::BasicBlock::appendIntConstant):
+        (JSC::B3::BasicBlock::replaceSuccessor):
+        (JSC::B3::BasicBlock::addPredecessor):
+        (JSC::B3::BasicBlock::replacePredecessor):
+        (JSC::B3::BasicBlock::updatePredecessors):
+        (JSC::B3::BasicBlock::dump):
+        * b3/B3BasicBlock.h:
+        (JSC::B3::BasicBlock::values):
+        (JSC::B3::BasicBlock::numPredecessors):
+        (JSC::B3::BasicBlock::predecessor):
+        (JSC::B3::BasicBlock::frequency):
+        * b3/B3BasicBlockInlines.h:
+        (JSC::B3::BasicBlock::appendNew):
+        (JSC::B3::BasicBlock::replaceLastWithNew):
+        (JSC::B3::BasicBlock::numSuccessors):
+        * b3/B3BasicBlockUtils.h:
+        (JSC::B3::replacePredecessor):
+        (JSC::B3::updatePredecessors):
+        (JSC::B3::resetReachability):
+        * b3/B3BlockInsertionSet.cpp: Added.
+        (JSC::B3::BlockInsertionSet::BlockInsertionSet):
+        (JSC::B3::BlockInsertionSet::~BlockInsertionSet):
+        (JSC::B3::BlockInsertionSet::insert):
+        (JSC::B3::BlockInsertionSet::insertBefore):
+        (JSC::B3::BlockInsertionSet::splitForward):
+        (JSC::B3::BlockInsertionSet::execute):
+        * b3/B3BlockInsertionSet.h: Added.
+        * b3/B3Common.h:
+        (JSC::B3::isRepresentableAs):
+        (JSC::B3::chillDiv):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::addConstant):
+        (JSC::B3::Const32Value::subConstant):
+        (JSC::B3::Const32Value::divConstant):
+        (JSC::B3::Const32Value::bitAndConstant):
+        (JSC::B3::Const32Value::bitOrConstant):
+        (JSC::B3::Const32Value::bitXorConstant):
+        (JSC::B3::Const32Value::shlConstant):
+        (JSC::B3::Const32Value::sShrConstant):
+        (JSC::B3::Const32Value::zShrConstant):
+        (JSC::B3::Const32Value::equalConstant):
+        (JSC::B3::Const32Value::notEqualConstant):
+        (JSC::B3::Const32Value::lessThanConstant):
+        (JSC::B3::Const32Value::greaterThanConstant):
+        (JSC::B3::Const32Value::lessEqualConstant):
+        (JSC::B3::Const32Value::greaterEqualConstant):
+        (JSC::B3::Const32Value::aboveConstant):
+        (JSC::B3::Const32Value::belowConstant):
+        (JSC::B3::Const32Value::aboveEqualConstant):
+        (JSC::B3::Const32Value::belowEqualConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::addConstant):
+        (JSC::B3::Const64Value::subConstant):
+        (JSC::B3::Const64Value::divConstant):
+        (JSC::B3::Const64Value::bitAndConstant):
+        (JSC::B3::Const64Value::bitOrConstant):
+        (JSC::B3::Const64Value::bitXorConstant):
+        (JSC::B3::Const64Value::shlConstant):
+        (JSC::B3::Const64Value::sShrConstant):
+        (JSC::B3::Const64Value::zShrConstant):
+        (JSC::B3::Const64Value::equalConstant):
+        (JSC::B3::Const64Value::notEqualConstant):
+        (JSC::B3::Const64Value::lessThanConstant):
+        (JSC::B3::Const64Value::greaterThanConstant):
+        (JSC::B3::Const64Value::lessEqualConstant):
+        (JSC::B3::Const64Value::greaterEqualConstant):
+        (JSC::B3::Const64Value::aboveConstant):
+        (JSC::B3::Const64Value::belowConstant):
+        (JSC::B3::Const64Value::aboveEqualConstant):
+        (JSC::B3::Const64Value::belowEqualConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3ConstDoubleValue.cpp:
+        (JSC::B3::ConstDoubleValue::addConstant):
+        (JSC::B3::ConstDoubleValue::subConstant):
+        (JSC::B3::ConstDoubleValue::divConstant):
+        (JSC::B3::ConstDoubleValue::equalConstant):
+        (JSC::B3::ConstDoubleValue::notEqualConstant):
+        (JSC::B3::ConstDoubleValue::lessThanConstant):
+        (JSC::B3::ConstDoubleValue::greaterThanConstant):
+        (JSC::B3::ConstDoubleValue::lessEqualConstant):
+        (JSC::B3::ConstDoubleValue::greaterEqualConstant):
+        * b3/B3ConstDoubleValue.h:
+        * b3/B3ControlValue.cpp:
+        (JSC::B3::ControlValue::~ControlValue):
+        (JSC::B3::ControlValue::replaceSuccessor):
+        (JSC::B3::ControlValue::convertToJump):
+        * b3/B3ControlValue.h:
+        * b3/B3Generate.cpp:
+        (JSC::B3::generateToAir):
+        * b3/B3GenericFrequentedBlock.h:
+        (JSC::B3::GenericFrequentedBlock::block):
+        (JSC::B3::GenericFrequentedBlock::frequency):
+        (JSC::B3::GenericFrequentedBlock::dump):
+        * b3/B3InsertionSet.cpp:
+        (JSC::B3::InsertionSet::insertIntConstant):
+        (JSC::B3::InsertionSet::execute):
+        * b3/B3InsertionSet.h:
+        * b3/B3LowerMacros.cpp: Added.
+        (JSC::B3::lowerMacros):
+        * b3/B3LowerMacros.h: Added.
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3Opcode.h:
+        * b3/B3Procedure.cpp:
+        (JSC::B3::Procedure::addBlock):
+        (JSC::B3::Procedure::addIntConstant):
+        (JSC::B3::Procedure::addBoolConstant):
+        (JSC::B3::Procedure::resetValueOwners):
+        * b3/B3Procedure.h:
+        (JSC::B3::Procedure::takeByproducts):
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::addConstant):
+        (JSC::B3::Value::subConstant):
+        (JSC::B3::Value::divConstant):
+        (JSC::B3::Value::bitAndConstant):
+        (JSC::B3::Value::bitOrConstant):
+        (JSC::B3::Value::bitXorConstant):
+        (JSC::B3::Value::shlConstant):
+        (JSC::B3::Value::sShrConstant):
+        (JSC::B3::Value::zShrConstant):
+        (JSC::B3::Value::equalConstant):
+        (JSC::B3::Value::notEqualConstant):
+        (JSC::B3::Value::lessThanConstant):
+        (JSC::B3::Value::greaterThanConstant):
+        (JSC::B3::Value::lessEqualConstant):
+        (JSC::B3::Value::greaterEqualConstant):
+        (JSC::B3::Value::aboveConstant):
+        (JSC::B3::Value::belowConstant):
+        (JSC::B3::Value::aboveEqualConstant):
+        (JSC::B3::Value::belowEqualConstant):
+        * b3/B3Value.h:
+        * b3/air/AirGenerate.cpp:
+        (JSC::B3::Air::generate):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::isUrshift64Valid):
+        (JSC::B3::Air::isX86DivHelperValid):
+        (JSC::B3::Air::isX86ConvertToDoubleWord32Valid):
+        (JSC::B3::Air::isX86ConvertToDoubleWord64Valid):
+        (JSC::B3::Air::isX86Div32Valid):
+        (JSC::B3::Air::isX86Div64Valid):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirSimplifyCFG.cpp:
+        (JSC::B3::Air::simplifyCFG):
+        * b3/testb3.cpp:
+        (JSC::B3::testCallFunctionWithHellaDoubleArguments):
+        (JSC::B3::testChillDiv):
+        (JSC::B3::testChillDivTwice):
+        (JSC::B3::testChillDiv64):
+        (JSC::B3::run):
+        * dfg/DFGBlockInsertionSet.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithDiv):
+        (JSC::DFG::SpeculativeJIT::compileArithMod):
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_mod):
+        * jit/JITArithmetic32_64.cpp:
+        (JSC::JIT::emit_op_mod):
+        * wasm/WASMFunctionCompiler.h:
+        (JSC::WASMFunctionCompiler::buildBinaryI32):
+
 2015-11-10  Benjamin Poulain  <bpoulain@apple.com>
 
         Air should allocate registers
index 81c11c7..d525125 100644 (file)
                0F338E141BF0276C0013C88F /* B3ValueKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F338E081BF0276C0013C88F /* B3ValueKey.cpp */; };
                0F338E151BF0276C0013C88F /* B3ValueKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F338E091BF0276C0013C88F /* B3ValueKey.h */; };
                0F338E161BF0276C0013C88F /* B3ValueKeyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F338E0A1BF0276C0013C88F /* B3ValueKeyInlines.h */; };
+               0F338E1B1BF286EA0013C88F /* B3BlockInsertionSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F338E171BF286EA0013C88F /* B3BlockInsertionSet.cpp */; };
+               0F338E1C1BF286EA0013C88F /* B3BlockInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F338E181BF286EA0013C88F /* B3BlockInsertionSet.h */; };
+               0F338E1D1BF286EA0013C88F /* B3LowerMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F338E191BF286EA0013C88F /* B3LowerMacros.cpp */; };
+               0F338E1E1BF286EA0013C88F /* B3LowerMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F338E1A1BF286EA0013C88F /* B3LowerMacros.h */; };
                0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */; };
                0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F34B14816D4200E001CDA5A /* DFGUseKind.h */; };
                0F38B01117CF078000B144D3 /* LLIntEntrypoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F38B00F17CF077F00B144D3 /* LLIntEntrypoint.cpp */; };
                0F338E081BF0276C0013C88F /* B3ValueKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3ValueKey.cpp; path = b3/B3ValueKey.cpp; sourceTree = "<group>"; };
                0F338E091BF0276C0013C88F /* B3ValueKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3ValueKey.h; path = b3/B3ValueKey.h; sourceTree = "<group>"; };
                0F338E0A1BF0276C0013C88F /* B3ValueKeyInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3ValueKeyInlines.h; path = b3/B3ValueKeyInlines.h; sourceTree = "<group>"; };
+               0F338E171BF286EA0013C88F /* B3BlockInsertionSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3BlockInsertionSet.cpp; path = b3/B3BlockInsertionSet.cpp; sourceTree = "<group>"; };
+               0F338E181BF286EA0013C88F /* B3BlockInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3BlockInsertionSet.h; path = b3/B3BlockInsertionSet.h; sourceTree = "<group>"; };
+               0F338E191BF286EA0013C88F /* B3LowerMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3LowerMacros.cpp; path = b3/B3LowerMacros.cpp; sourceTree = "<group>"; };
+               0F338E1A1BF286EA0013C88F /* B3LowerMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3LowerMacros.h; path = b3/B3LowerMacros.h; sourceTree = "<group>"; };
                0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGUseKind.cpp; path = dfg/DFGUseKind.cpp; sourceTree = "<group>"; };
                0F34B14816D4200E001CDA5A /* DFGUseKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGUseKind.h; path = dfg/DFGUseKind.h; sourceTree = "<group>"; };
                0F38B00F17CF077F00B144D3 /* LLIntEntrypoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntEntrypoint.cpp; path = llint/LLIntEntrypoint.cpp; sourceTree = "<group>"; };
                                0FEC84B71BDACDAC0080FF74 /* B3BasicBlock.h */,
                                0FEC84B81BDACDAC0080FF74 /* B3BasicBlockInlines.h */,
                                0FEC84B91BDACDAC0080FF74 /* B3BasicBlockUtils.h */,
+                               0F338E171BF286EA0013C88F /* B3BlockInsertionSet.cpp */,
+                               0F338E181BF286EA0013C88F /* B3BlockInsertionSet.h */,
                                0FEC84BA1BDACDAC0080FF74 /* B3BlockWorklist.h */,
                                0F338DF71BE96AA80013C88F /* B3CCallValue.cpp */,
                                0F338DF81BE96AA80013C88F /* B3CCallValue.h */,
                                0FEC85B41BE1462F0080FF74 /* B3InsertionSet.cpp */,
                                0FEC85B51BE1462F0080FF74 /* B3InsertionSet.h */,
                                0FEC85B61BE1462F0080FF74 /* B3InsertionSetInlines.h */,
+                               0F338E191BF286EA0013C88F /* B3LowerMacros.cpp */,
+                               0F338E1A1BF286EA0013C88F /* B3LowerMacros.h */,
                                0FEC84D31BDACDAC0080FF74 /* B3LowerToAir.cpp */,
                                0FEC84D41BDACDAC0080FF74 /* B3LowerToAir.h */,
                                0FEC84D51BDACDAC0080FF74 /* B3MemoryValue.cpp */,
                                0FEC85381BDACDAC0080FF74 /* B3SwitchCase.h in Headers */,
                                0FEC853A1BDACDAC0080FF74 /* B3SwitchValue.h in Headers */,
                                0F4570411BE584CA0062A629 /* B3TimingScope.h in Headers */,
+                               0F338E1E1BF286EA0013C88F /* B3LowerMacros.h in Headers */,
                                0FEC853C1BDACDAC0080FF74 /* B3Type.h in Headers */,
                                0FEC853E1BDACDAC0080FF74 /* B3UpsilonValue.h in Headers */,
                                0FEC85401BDACDAC0080FF74 /* B3UseCounts.h in Headers */,
                                C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */,
                                C218D1401655CFD50062BB81 /* CopyWorkList.h in Headers */,
                                C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */,
+                               0F338E1C1BF286EA0013C88F /* B3BlockInsertionSet.h in Headers */,
                                C4F4B6F31A05C944005CAB76 /* cpp_generator_templates.py in Headers */,
                                5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */,
                                9959E92B1BD17FA4001AA413 /* cssmin.py in Headers */,
                                147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */,
                                14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */,
                                149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
+                               0F338E1D1BF286EA0013C88F /* B3LowerMacros.cpp in Sources */,
                                0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */,
                                2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */,
                                0FC712DE17CD8779008CC93C /* DeferredCompilationCallback.cpp in Sources */,
                                0FEA0A1E1708B00700BB722C /* FTLAbstractHeapRepository.cpp in Sources */,
                                0F485327187DFDEC0083B687 /* FTLAvailableRecovery.cpp in Sources */,
                                0FEA0A09170513DB00BB722C /* FTLCapabilities.cpp in Sources */,
+                               0F338E1B1BF286EA0013C88F /* B3BlockInsertionSet.cpp in Sources */,
                                0FEA0A271709623B00BB722C /* FTLCommonValues.cpp in Sources */,
                                0FEA0A0B170513DB00BB722C /* FTLCompile.cpp in Sources */,
                                0FE95F7918B5694700B531FB /* FTLDataSection.cpp in Sources */,
index 25e7d82..5a2679c 100644 (file)
@@ -247,6 +247,30 @@ public:
         m_assembler.imull_i32r(src, imm.m_value, dest);
     }
 
+    void x86ConvertToDoubleWord32()
+    {
+        m_assembler.cdq();
+    }
+
+    void x86ConvertToDoubleWord32(RegisterID eax, RegisterID edx)
+    {
+        ASSERT_UNUSED(eax, eax == X86Registers::eax);
+        ASSERT_UNUSED(edx, edx == X86Registers::edx);
+        x86ConvertToDoubleWord32();
+    }
+
+    void x86Div32(RegisterID denominator)
+    {
+        m_assembler.idivl_r(denominator);
+    }
+
+    void x86Div32(RegisterID eax, RegisterID edx, RegisterID denominator)
+    {
+        ASSERT_UNUSED(eax, eax == X86Registers::eax);
+        ASSERT_UNUSED(edx, edx == X86Registers::edx);
+        x86Div32(denominator);
+    }
+
     void neg32(RegisterID srcDest)
     {
         m_assembler.negl_r(srcDest);
index 8337764..2fa568c 100644 (file)
@@ -386,6 +386,30 @@ public:
         m_assembler.imulq_rr(src, dest);
     }
     
+    void x86ConvertToQuadWord64()
+    {
+        m_assembler.cqo();
+    }
+
+    void x86ConvertToQuadWord64(RegisterID rax, RegisterID rdx)
+    {
+        ASSERT_UNUSED(rax, rax == X86Registers::eax);
+        ASSERT_UNUSED(rdx, rdx == X86Registers::edx);
+        x86ConvertToQuadWord64();
+    }
+
+    void x86Div64(RegisterID denominator)
+    {
+        m_assembler.idivq_r(denominator);
+    }
+
+    void x86Div64(RegisterID rax, RegisterID rdx, RegisterID denominator)
+    {
+        ASSERT_UNUSED(rax, rax == X86Registers::eax);
+        ASSERT_UNUSED(rdx, rdx == X86Registers::edx);
+        x86Div64(denominator);
+    }
+
     void neg64(RegisterID dest)
     {
         m_assembler.negq_r(dest);
index bf975c7..374cfaa 100644 (file)
@@ -962,6 +962,13 @@ public:
         m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst);
     }
 
+#if CPU(X86_64)
+    void idivq_r(RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst);
+    }
+#endif // CPU(X86_64)
+
     // Comparisons:
 
     void cmpl_rr(RegisterID src, RegisterID dst)
@@ -1294,6 +1301,13 @@ public:
         m_formatter.oneByteOp(OP_CDQ);
     }
 
+#if CPU(X86_64)
+    void cqo()
+    {
+        m_formatter.oneByteOp64(OP_CDQ);
+    }
+#endif
+
     void fstps(int offset, RegisterID base)
     {
         m_formatter.oneByteOp(OP_ESCAPE_D9, ESCAPE_D9_FSTP_singleReal, base, offset);
index a7e5629..501266f 100644 (file)
 
 #if ENABLE(B3_JIT)
 
+#include "B3BasicBlockInlines.h"
 #include "B3BasicBlockUtils.h"
+#include "B3ControlValue.h"
 #include "B3Procedure.h"
-#include "B3Value.h"
+#include "B3ValueInlines.h"
 #include <wtf/ListDump.h>
 
 namespace JSC { namespace B3 {
@@ -52,6 +54,29 @@ void BasicBlock::append(Value* value)
     m_values.append(value);
 }
 
+void BasicBlock::replaceLast(Procedure& proc, Value* value)
+{
+    proc.deleteValue(last());
+    last() = value;
+}
+
+Value* BasicBlock::appendIntConstant(Procedure& proc, Origin origin, Type type, int64_t value)
+{
+    Value* result = proc.addIntConstant(origin, type, value);
+    append(result);
+    return result;
+}
+
+Value* BasicBlock::appendIntConstant(Procedure& proc, Value* likeValue, int64_t value)
+{
+    return appendIntConstant(proc, likeValue->origin(), likeValue->type(), value);
+}
+
+bool BasicBlock::replaceSuccessor(BasicBlock* from, BasicBlock* to)
+{
+    return last()->as<ControlValue>()->replaceSuccessor(from, to);
+}
+
 bool BasicBlock::addPredecessor(BasicBlock* block)
 {
     return B3::addPredecessor(this, block);
@@ -67,6 +92,11 @@ bool BasicBlock::replacePredecessor(BasicBlock* from, BasicBlock* to)
     return B3::replacePredecessor(this, from, to);
 }
 
+void BasicBlock::updatePredecessorsAfter()
+{
+    B3::updatePredecessorsAfter(this);
+}
+
 void BasicBlock::dump(PrintStream& out) const
 {
     out.print(dumpPrefix, m_index);
index 3d62a10..d28f6af 100644 (file)
 #if ENABLE(B3_JIT)
 
 #include "B3FrequentedBlock.h"
+#include "B3Origin.h"
 #include "B3SuccessorCollection.h"
+#include "B3Type.h"
 #include <wtf/Vector.h>
 
 namespace JSC { namespace B3 {
 
+class BlockInsertionSet;
 class InsertionSet;
 class Procedure;
 class Value;
@@ -68,10 +71,17 @@ public:
     ValueList& values() { return m_values; }
 
     JS_EXPORT_PRIVATE void append(Value*);
+    JS_EXPORT_PRIVATE void replaceLast(Procedure&, Value*);
 
     template<typename ValueType, typename... Arguments>
     ValueType* appendNew(Procedure&, Arguments...);
 
+    Value* appendIntConstant(Procedure&, Origin, Type, int64_t value);
+    Value* appendIntConstant(Procedure&, Value* likeValue, int64_t value);
+    
+    template<typename ValueType, typename... Arguments>
+    ValueType* replaceLastWithNew(Procedure&, Arguments...);
+
     unsigned numSuccessors() const;
     const FrequentedBlock& successor(unsigned index) const;
     FrequentedBlock& successor(unsigned index);
@@ -83,6 +93,8 @@ public:
     SuccessorCollection<BasicBlock, SuccessorList> successorBlocks();
     SuccessorCollection<const BasicBlock, const SuccessorList> successorBlocks() const;
 
+    bool replaceSuccessor(BasicBlock* from, BasicBlock* to);
+
     unsigned numPredecessors() const { return m_predecessors.size(); }
     BasicBlock* predecessor(unsigned index) const { return m_predecessors[index]; }
     BasicBlock*& predecessor(unsigned index) { return m_predecessors[index]; }
@@ -94,12 +106,16 @@ public:
     bool removePredecessor(BasicBlock*);
     bool replacePredecessor(BasicBlock* from, BasicBlock* to);
 
+    // Update predecessors starting with the successors of this block.
+    void updatePredecessorsAfter();
+
     double frequency() const { return m_frequency; }
 
     void dump(PrintStream&) const;
     void deepDump(PrintStream&) const;
 
 private:
+    friend class BlockInsertionSet;
     friend class InsertionSet;
     friend class Procedure;
     
index b9fdd17..efbb9e1 100644 (file)
@@ -42,6 +42,14 @@ ValueType* BasicBlock::appendNew(Procedure& procedure, Arguments... arguments)
     return result;
 }
 
+template<typename ValueType, typename... Arguments>
+ValueType* BasicBlock::replaceLastWithNew(Procedure& procedure, Arguments... arguments)
+{
+    ValueType* result = procedure.add<ValueType>(arguments...);
+    replaceLast(procedure, result);
+    return result;
+}
+
 inline unsigned BasicBlock::numSuccessors() const
 {
     return last()->as<ControlValue>()->numSuccessors();
index e5ec948..54b66b0 100644 (file)
@@ -71,6 +71,20 @@ bool replacePredecessor(BasicBlock* block, BasicBlock* from, BasicBlock* to)
     return changed;
 }
 
+template<typename BasicBlock>
+void updatePredecessorsAfter(BasicBlock* root)
+{
+    Vector<BasicBlock*, 16> worklist;
+    worklist.append(root);
+    while (!worklist.isEmpty()) {
+        BasicBlock* block = worklist.takeLast();
+        for (BasicBlock* successor : block->successorBlocks()) {
+            if (addPredecessor(successor, block))
+                worklist.append(successor);
+        }
+    }
+}
+
 // This recomputes predecessors and removes blocks that aren't reachable.
 template<typename BasicBlock, typename DeleteFunctor>
 void resetReachability(
@@ -82,14 +96,7 @@ void resetReachability(
             block->predecessors().resize(0);
     }
 
-    GraphNodeWorklist<BasicBlock*, IndexSet<BasicBlock>> worklist;
-    worklist.push(blocks[0].get());
-    while (BasicBlock* block = worklist.pop()) {
-        for (BasicBlock* successor : block->successorBlocks()) {
-            addPredecessor(successor, block);
-            worklist.push(successor);
-        }
-    }
+    updatePredecessorsAfter(blocks[0].get());
 
     for (unsigned i = 1; i < blocks.size(); ++i) {
         if (!blocks[i])
diff --git a/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp b/Source/JavaScriptCore/b3/B3BlockInsertionSet.cpp
new file mode 100644 (file)
index 0000000..4e2ef33
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "B3BlockInsertionSet.h"
+
+#if ENABLE(B3_JIT)
+
+#include "B3BasicBlockInlines.h"
+#include "B3InsertionSet.h"
+#include "B3ProcedureInlines.h"
+#include <wtf/BubbleSort.h>
+
+namespace JSC { namespace B3 {
+
+BlockInsertionSet::BlockInsertionSet(Procedure &proc)
+    : m_proc(proc)
+{
+}
+
+BlockInsertionSet::~BlockInsertionSet() { }
+
+void BlockInsertionSet::insert(BlockInsertion&& insertion)
+{
+    m_insertions.append(WTF::move(insertion));
+}
+
+BasicBlock* BlockInsertionSet::insert(unsigned index, double frequency)
+{
+    std::unique_ptr<BasicBlock> block(new BasicBlock(UINT_MAX, frequency));
+    BasicBlock* result = block.get();
+    insert(BlockInsertion(index, WTF::move(block)));
+    return result;
+}
+
+BasicBlock* BlockInsertionSet::insertBefore(BasicBlock* before, double frequency)
+{
+    return insert(before->index(), frequency == frequency ? frequency : before->frequency());
+}
+
+BasicBlock* BlockInsertionSet::splitForward(
+    BasicBlock* block, unsigned& valueIndex, InsertionSet* insertionSet, double frequency)
+{
+    Value* value = block->at(valueIndex);
+
+    // Create a new block that will go just before 'block', and make it contain everything prior
+    // to 'valueIndex'.
+    BasicBlock* result = insertBefore(block, frequency);
+    result->m_values.resize(valueIndex + 1);
+    for (unsigned i = valueIndex; i--;)
+        result->m_values[i] = block->m_values[i];
+
+    // Make the new block jump to 'block'.
+    result->m_values[valueIndex] =
+        m_proc.add<ControlValue>(Jump, value->origin(), FrequentedBlock(block));
+
+    // If we had inserted things into 'block' before this, execute those insertions now.
+    if (insertionSet)
+        insertionSet->execute(result);
+
+    // Remove everything prior to 'valueIndex' from 'block', since those things are now in the
+    // new block.
+    block->m_values.remove(0, valueIndex);
+
+    // This is being used in a forward loop over 'block'. Update the index of the loop so that
+    // it can continue to the next block.
+    valueIndex = 0;
+
+    // Fixup the predecessors of 'block'. They now must jump to the new block.
+    result->predecessors() = WTF::move(block->predecessors());
+    block->addPredecessor(result);
+    for (BasicBlock* predecessor : result->predecessors())
+        predecessor->replaceSuccessor(block, result);
+
+    return result;
+}
+
+bool BlockInsertionSet::execute()
+{
+    if (m_insertions.isEmpty())
+        return false;
+    
+    // We allow insertions to be given to us in any order. So, we need to sort them before
+    // running WTF::executeInsertions. We strongly prefer a stable sort and we want it to be
+    // fast, so we use bubble sort.
+    bubbleSort(m_insertions.begin(), m_insertions.end());
+
+    executeInsertions(m_proc.m_blocks, m_insertions);
+    
+    // Prune out empty entries. This isn't strictly necessary but it's
+    // healthy to keep the block list from growing.
+    m_proc.m_blocks.removeAllMatching(
+        [&] (std::unique_ptr<BasicBlock>& blockPtr) -> bool {
+            return !blockPtr;
+        });
+    
+    // Make sure that the blocks know their new indices.
+    for (unsigned i = 0; i < m_proc.m_blocks.size(); ++i)
+        m_proc.m_blocks[i]->m_index = i;
+    
+    return true;
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
diff --git a/Source/JavaScriptCore/b3/B3BlockInsertionSet.h b/Source/JavaScriptCore/b3/B3BlockInsertionSet.h
new file mode 100644 (file)
index 0000000..63649e5
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef B3BlockInsertionSet_h
+#define B3BlockInsertionSet_h
+
+#if ENABLE(B3_JIT)
+
+#include "B3Procedure.h"
+#include <wtf/Insertion.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace B3 {
+
+class InsertionSet;
+
+typedef WTF::Insertion<std::unique_ptr<BasicBlock>> BlockInsertion;
+
+class BlockInsertionSet {
+public:
+    BlockInsertionSet(Procedure&);
+    ~BlockInsertionSet();
+    
+    void insert(BlockInsertion&&);
+
+    // Insert a new block at a given index.
+    BasicBlock* insert(unsigned index, double frequency = PNaN);
+
+    // Inserts a new block before the given block. Usually you will not pass the frequency
+    // argument. Passing PNaN causes us to just use the frequency of the 'before' block. That's
+    // usually what you want.
+    BasicBlock* insertBefore(BasicBlock* before, double frequency = PNaN);
+
+    // A helper to split a block when forward iterating over it. It creates a new block to hold
+    // everything before the instruction at valueIndex. The current block is left with
+    // everything at and after valueIndex. If the optional InsertionSet is provided, it will get
+    // executed on the newly created block - this makes sense if you had previously inserted
+    // things into the original block, since the newly created block will be indexed identically
+    // to hold this block was indexed for all values prior to valueIndex. After this runs, it
+    // sets valueIndex to zero. This allows you to use this method for things like:
+    //
+    // for (unsigned valueIndex = 0; valueIndex < block->size(); ++valueIndex) {
+    //     Value* value = block->at(valueIndex);
+    //     if (value->opcode() == Foo) {
+    //         BasicBlock* predecessor =
+    //             m_blockInsertionSet.splitForward(block, valueIndex, &m_insertionSet);
+    //         ... // Now you can append to predecessor, insert new blocks before 'block', and
+    //         ... // you can use m_insertionSet to insert more thing before 'value'.
+    //         predecessor->updatePredecessorsAfter();
+    //     }
+    // }
+    //
+    // Note how usually this idiom ends in a all to updatePredecessorsAftter(), which ensures
+    // that the predecessors involved in any of the new control flow that you've created are up
+    // to date.
+    BasicBlock* splitForward(
+        BasicBlock*, unsigned& valueIndex, InsertionSet* = nullptr,
+        double frequency = PNaN);
+    
+    bool execute();
+
+private:
+    Procedure& m_proc;
+    Vector<BlockInsertion, 8> m_insertions;
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3BlockInsertionSet_h
+
index e77a60d..5066d73 100644 (file)
@@ -94,6 +94,24 @@ inline bool isRepresentableAs(double value)
     return isRepresentableAsImpl<ResultType, double, int64_t>(value);
 }
 
+inline int32_t chillDiv(int32_t num, int32_t den)
+{
+    if (!den)
+        return 0;
+    if (den == -1 && num == std::numeric_limits<int32_t>::min())
+        return num;
+    return num / den;
+}
+
+inline int64_t chillDiv(int64_t num, int64_t den)
+{
+    if (!den)
+        return 0;
+    if (den == -1 && num == std::numeric_limits<int64_t>::min())
+        return num;
+    return num / den;
+}
+
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index ca9ac7c..16d2830 100644 (file)
@@ -47,126 +47,133 @@ Value* Const32Value::addConstant(Procedure& proc, int32_t other) const
     return proc.add<Const32Value>(origin(), m_value + other);
 }
 
-Value* Const32Value::addConstant(Procedure& proc, Value* other) const
+Value* Const32Value::addConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value + other->asInt32());
 }
 
-Value* Const32Value::subConstant(Procedure& proc, Value* other) const
+Value* Const32Value::subConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value - other->asInt32());
 }
 
-Value* Const32Value::bitAndConstant(Procedure& proc, Value* other) const
+Value* Const32Value::divConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), chillDiv(m_value, other->asInt32()));
+}
+
+Value* Const32Value::bitAndConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value & other->asInt32());
 }
 
-Value* Const32Value::bitOrConstant(Procedure& proc, Value* other) const
+Value* Const32Value::bitOrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value | other->asInt32());
 }
 
-Value* Const32Value::bitXorConstant(Procedure& proc, Value* other) const
+Value* Const32Value::bitXorConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value ^ other->asInt32());
 }
 
-Value* Const32Value::shlConstant(Procedure& proc, Value* other) const
+Value* Const32Value::shlConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value << (other->asInt32() & 31));
 }
 
-Value* Const32Value::sShrConstant(Procedure& proc, Value* other) const
+Value* Const32Value::sShrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), m_value >> (other->asInt32() & 31));
 }
 
-Value* Const32Value::zShrConstant(Procedure& proc, Value* other) const
+Value* Const32Value::zShrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const32Value>(origin(), static_cast<int32_t>(static_cast<uint32_t>(m_value) >> (other->asInt32() & 31)));
 }
 
-TriState Const32Value::equalConstant(Value* other) const
+TriState Const32Value::equalConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value == other->asInt32());
 }
 
-TriState Const32Value::notEqualConstant(Value* other) const
+TriState Const32Value::notEqualConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value != other->asInt32());
 }
 
-TriState Const32Value::lessThanConstant(Value* other) const
+TriState Const32Value::lessThanConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value < other->asInt32());
 }
 
-TriState Const32Value::greaterThanConstant(Value* other) const
+TriState Const32Value::greaterThanConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value > other->asInt32());
 }
 
-TriState Const32Value::lessEqualConstant(Value* other) const
+TriState Const32Value::lessEqualConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value <= other->asInt32());
 }
 
-TriState Const32Value::greaterEqualConstant(Value* other) const
+TriState Const32Value::greaterEqualConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(m_value >= other->asInt32());
 }
 
-TriState Const32Value::aboveConstant(Value* other) const
+TriState Const32Value::aboveConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(static_cast<uint32_t>(m_value) > static_cast<uint32_t>(other->asInt32()));
 }
 
-TriState Const32Value::belowConstant(Value* other) const
+TriState Const32Value::belowConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(static_cast<uint32_t>(m_value) < static_cast<uint32_t>(other->asInt32()));
 }
 
-TriState Const32Value::aboveEqualConstant(Value* other) const
+TriState Const32Value::aboveEqualConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
     return triState(static_cast<uint32_t>(m_value) >= static_cast<uint32_t>(other->asInt32()));
 }
 
-TriState Const32Value::belowEqualConstant(Value* other) const
+TriState Const32Value::belowEqualConstant(const Value* other) const
 {
     if (!other->hasInt32())
         return MixedTriState;
index 8b4f32c..ad64cb5 100644 (file)
@@ -42,25 +42,26 @@ public:
 
     Value* negConstant(Procedure&) const override;
     Value* addConstant(Procedure&, int32_t other) const override;
-    Value* addConstant(Procedure&, Value* other) const override;
-    Value* subConstant(Procedure&, Value* other) const override;
-    Value* bitAndConstant(Procedure&, Value* other) const override;
-    Value* bitOrConstant(Procedure&, Value* other) const override;
-    Value* bitXorConstant(Procedure&, Value* other) const override;
-    Value* shlConstant(Procedure&, Value* other) const override;
-    Value* sShrConstant(Procedure&, Value* other) const override;
-    Value* zShrConstant(Procedure&, Value* other) const override;
+    Value* addConstant(Procedure&, const Value* other) const override;
+    Value* subConstant(Procedure&, const Value* other) const override;
+    Value* divConstant(Procedure&, const Value* other) const override;
+    Value* bitAndConstant(Procedure&, const Value* other) const override;
+    Value* bitOrConstant(Procedure&, const Value* other) const override;
+    Value* bitXorConstant(Procedure&, const Value* other) const override;
+    Value* shlConstant(Procedure&, const Value* other) const override;
+    Value* sShrConstant(Procedure&, const Value* other) const override;
+    Value* zShrConstant(Procedure&, const Value* other) const override;
 
-    TriState equalConstant(Value* other) const override;
-    TriState notEqualConstant(Value* other) const override;
-    TriState lessThanConstant(Value* other) const override;
-    TriState greaterThanConstant(Value* other) const override;
-    TriState lessEqualConstant(Value* other) const override;
-    TriState greaterEqualConstant(Value* other) const override;
-    TriState aboveConstant(Value* other) const override;
-    TriState belowConstant(Value* other) const override;
-    TriState aboveEqualConstant(Value* other) const override;
-    TriState belowEqualConstant(Value* other) const override;
+    TriState equalConstant(const Value* other) const override;
+    TriState notEqualConstant(const Value* other) const override;
+    TriState lessThanConstant(const Value* other) const override;
+    TriState greaterThanConstant(const Value* other) const override;
+    TriState lessEqualConstant(const Value* other) const override;
+    TriState greaterEqualConstant(const Value* other) const override;
+    TriState aboveConstant(const Value* other) const override;
+    TriState belowConstant(const Value* other) const override;
+    TriState aboveEqualConstant(const Value* other) const override;
+    TriState belowEqualConstant(const Value* other) const override;
 
 protected:
     JS_EXPORT_PRIVATE void dumpMeta(CommaPrinter&, PrintStream&) const override;
index c1fe906..e9ca7bb 100644 (file)
@@ -47,126 +47,133 @@ Value* Const64Value::addConstant(Procedure& proc, int32_t other) const
     return proc.add<Const64Value>(origin(), m_value + static_cast<int64_t>(other));
 }
 
-Value* Const64Value::addConstant(Procedure& proc, Value* other) const
+Value* Const64Value::addConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value + other->asInt64());
 }
 
-Value* Const64Value::subConstant(Procedure& proc, Value* other) const
+Value* Const64Value::subConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value - other->asInt64());
 }
 
-Value* Const64Value::bitAndConstant(Procedure& proc, Value* other) const
+Value* Const64Value::divConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasInt64())
+        return nullptr;
+    return proc.add<Const64Value>(origin(), chillDiv(m_value, other->asInt64()));
+}
+
+Value* Const64Value::bitAndConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value & other->asInt64());
 }
 
-Value* Const64Value::bitOrConstant(Procedure& proc, Value* other) const
+Value* Const64Value::bitOrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value | other->asInt64());
 }
 
-Value* Const64Value::bitXorConstant(Procedure& proc, Value* other) const
+Value* Const64Value::bitXorConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt64())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value ^ other->asInt64());
 }
 
-Value* Const64Value::shlConstant(Procedure& proc, Value* other) const
+Value* Const64Value::shlConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value << (other->asInt32() & 63));
 }
 
-Value* Const64Value::sShrConstant(Procedure& proc, Value* other) const
+Value* Const64Value::sShrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const64Value>(origin(), m_value >> (other->asInt32() & 63));
 }
 
-Value* Const64Value::zShrConstant(Procedure& proc, Value* other) const
+Value* Const64Value::zShrConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasInt32())
         return nullptr;
     return proc.add<Const64Value>(origin(), static_cast<int64_t>(static_cast<uint64_t>(m_value) >> (other->asInt32() & 63)));
 }
 
-TriState Const64Value::equalConstant(Value* other) const
+TriState Const64Value::equalConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value == other->asInt64());
 }
 
-TriState Const64Value::notEqualConstant(Value* other) const
+TriState Const64Value::notEqualConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value != other->asInt64());
 }
 
-TriState Const64Value::lessThanConstant(Value* other) const
+TriState Const64Value::lessThanConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value < other->asInt64());
 }
 
-TriState Const64Value::greaterThanConstant(Value* other) const
+TriState Const64Value::greaterThanConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value > other->asInt64());
 }
 
-TriState Const64Value::lessEqualConstant(Value* other) const
+TriState Const64Value::lessEqualConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value <= other->asInt64());
 }
 
-TriState Const64Value::greaterEqualConstant(Value* other) const
+TriState Const64Value::greaterEqualConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(m_value >= other->asInt64());
 }
 
-TriState Const64Value::aboveConstant(Value* other) const
+TriState Const64Value::aboveConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(static_cast<uint64_t>(m_value) > static_cast<uint64_t>(other->asInt64()));
 }
 
-TriState Const64Value::belowConstant(Value* other) const
+TriState Const64Value::belowConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(static_cast<uint64_t>(m_value) < static_cast<uint64_t>(other->asInt64()));
 }
 
-TriState Const64Value::aboveEqualConstant(Value* other) const
+TriState Const64Value::aboveEqualConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
     return triState(static_cast<uint64_t>(m_value) >= static_cast<uint64_t>(other->asInt64()));
 }
 
-TriState Const64Value::belowEqualConstant(Value* other) const
+TriState Const64Value::belowEqualConstant(const Value* other) const
 {
     if (!other->hasInt64())
         return MixedTriState;
index 73cee18..1768451 100644 (file)
@@ -42,25 +42,26 @@ public:
 
     Value* negConstant(Procedure&) const override;
     Value* addConstant(Procedure&, int32_t other) const override;
-    Value* addConstant(Procedure&, Value* other) const override;
-    Value* subConstant(Procedure&, Value* other) const override;
-    Value* bitAndConstant(Procedure&, Value* other) const override;
-    Value* bitOrConstant(Procedure&, Value* other) const override;
-    Value* bitXorConstant(Procedure&, Value* other) const override;
-    Value* shlConstant(Procedure&, Value* other) const override;
-    Value* sShrConstant(Procedure&, Value* other) const override;
-    Value* zShrConstant(Procedure&, Value* other) const override;
+    Value* addConstant(Procedure&, const Value* other) const override;
+    Value* subConstant(Procedure&, const Value* other) const override;
+    Value* divConstant(Procedure&, const Value* other) const override;
+    Value* bitAndConstant(Procedure&, const Value* other) const override;
+    Value* bitOrConstant(Procedure&, const Value* other) const override;
+    Value* bitXorConstant(Procedure&, const Value* other) const override;
+    Value* shlConstant(Procedure&, const Value* other) const override;
+    Value* sShrConstant(Procedure&, const Value* other) const override;
+    Value* zShrConstant(Procedure&, const Value* other) const override;
 
-    TriState equalConstant(Value* other) const override;
-    TriState notEqualConstant(Value* other) const override;
-    TriState lessThanConstant(Value* other) const override;
-    TriState greaterThanConstant(Value* other) const override;
-    TriState lessEqualConstant(Value* other) const override;
-    TriState greaterEqualConstant(Value* other) const override;
-    TriState aboveConstant(Value* other) const override;
-    TriState belowConstant(Value* other) const override;
-    TriState aboveEqualConstant(Value* other) const override;
-    TriState belowEqualConstant(Value* other) const override;
+    TriState equalConstant(const Value* other) const override;
+    TriState notEqualConstant(const Value* other) const override;
+    TriState lessThanConstant(const Value* other) const override;
+    TriState greaterThanConstant(const Value* other) const override;
+    TriState lessEqualConstant(const Value* other) const override;
+    TriState greaterEqualConstant(const Value* other) const override;
+    TriState aboveConstant(const Value* other) const override;
+    TriState belowConstant(const Value* other) const override;
+    TriState aboveEqualConstant(const Value* other) const override;
+    TriState belowEqualConstant(const Value* other) const override;
 
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
index 434e26f..8291325 100644 (file)
@@ -47,56 +47,63 @@ Value* ConstDoubleValue::addConstant(Procedure& proc, int32_t other) const
     return proc.add<ConstDoubleValue>(origin(), m_value + static_cast<double>(other));
 }
 
-Value* ConstDoubleValue::addConstant(Procedure& proc, Value* other) const
+Value* ConstDoubleValue::addConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasDouble())
         return nullptr;
     return proc.add<ConstDoubleValue>(origin(), m_value + other->asDouble());
 }
 
-Value* ConstDoubleValue::subConstant(Procedure& proc, Value* other) const
+Value* ConstDoubleValue::subConstant(Procedure& proc, const Value* other) const
 {
     if (!other->hasDouble())
         return nullptr;
     return proc.add<ConstDoubleValue>(origin(), m_value - other->asDouble());
 }
 
-TriState ConstDoubleValue::equalConstant(Value* other) const
+Value* ConstDoubleValue::divConstant(Procedure& proc, const Value* other) const
+{
+    if (!other->hasDouble())
+        return nullptr;
+    return proc.add<ConstDoubleValue>(origin(), m_value / other->asDouble());
+}
+
+TriState ConstDoubleValue::equalConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
     return triState(m_value == other->asDouble());
 }
 
-TriState ConstDoubleValue::notEqualConstant(Value* other) const
+TriState ConstDoubleValue::notEqualConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
     return triState(m_value != other->asDouble());
 }
 
-TriState ConstDoubleValue::lessThanConstant(Value* other) const
+TriState ConstDoubleValue::lessThanConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
     return triState(m_value < other->asDouble());
 }
 
-TriState ConstDoubleValue::greaterThanConstant(Value* other) const
+TriState ConstDoubleValue::greaterThanConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
     return triState(m_value > other->asDouble());
 }
 
-TriState ConstDoubleValue::lessEqualConstant(Value* other) const
+TriState ConstDoubleValue::lessEqualConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
     return triState(m_value <= other->asDouble());
 }
 
-TriState ConstDoubleValue::greaterEqualConstant(Value* other) const
+TriState ConstDoubleValue::greaterEqualConstant(const Value* other) const
 {
     if (!other->hasDouble())
         return MixedTriState;
index f09f232..27162e9 100644 (file)
@@ -40,17 +40,18 @@ public:
     
     double value() const { return m_value; }
 
-    Value* negConstant(Procedure& proc) const override;
-    Value* addConstant(Procedure& proc, int32_t other) const override;
-    Value* addConstant(Procedure& proc, Value* other) const override;
-    Value* subConstant(Procedure& proc, Value* other) const override;
+    Value* negConstant(Procedure&) const override;
+    Value* addConstant(Procedure&, int32_t other) const override;
+    Value* addConstant(Procedure&, const Value* other) const override;
+    Value* subConstant(Procedure&, const Value* other) const override;
+    Value* divConstant(Procedure&, const Value* other) const override;
 
-    TriState equalConstant(Value* other) const override;
-    TriState notEqualConstant(Value* other) const override;
-    TriState lessThanConstant(Value* other) const override;
-    TriState greaterThanConstant(Value* other) const override;
-    TriState lessEqualConstant(Value* other) const override;
-    TriState greaterEqualConstant(Value* other) const override;
+    TriState equalConstant(const Value* other) const override;
+    TriState notEqualConstant(const Value* other) const override;
+    TriState lessThanConstant(const Value* other) const override;
+    TriState greaterThanConstant(const Value* other) const override;
+    TriState lessEqualConstant(const Value* other) const override;
+    TriState greaterEqualConstant(const Value* other) const override;
 
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
index 02970d3..393fdcf 100644 (file)
@@ -36,7 +36,22 @@ ControlValue::~ControlValue()
 {
 }
 
-void ControlValue::convertToJump(const FrequentedBlock& destination)
+bool ControlValue::replaceSuccessor(BasicBlock* from, BasicBlock* to)
+{
+    bool result = false;
+    for (FrequentedBlock& successor : m_successors) {
+        if (successor.block() == from) {
+            successor.block() = to;
+            result = true;
+
+            // Keep looping because it's valid for a successor to be mentioned multiple times,
+            // like if multiple switch cases have the same target.
+        }
+    }
+    return result;
+}
+
+void ControlValue::convertToJump(BasicBlock* destination)
 {
     unsigned index = this->index();
     Origin origin = this->origin();
@@ -44,7 +59,7 @@ void ControlValue::convertToJump(const FrequentedBlock& destination)
 
     this->ControlValue::~ControlValue();
 
-    new (this) ControlValue(index, Jump, origin, destination);
+    new (this) ControlValue(index, Jump, origin, FrequentedBlock(destination));
 
     this->owner = owner;
 }
index f0d4d5b..24b82c0 100644 (file)
@@ -64,6 +64,8 @@ public:
     const SuccessorList& successors() const { return m_successors; }
     SuccessorList& successors() { return m_successors; }
 
+    bool replaceSuccessor(BasicBlock* from, BasicBlock* to);
+
     const FrequentedBlock& taken() const
     {
         ASSERT(opcode() == Jump || opcode() == Branch);
@@ -85,7 +87,7 @@ public:
         return successor(1);
     }
 
-    void convertToJump(const FrequentedBlock& destination);
+    void convertToJump(BasicBlock* destination);
 
 protected:
     JS_EXPORT_PRIVATE void dumpMeta(CommaPrinter&, PrintStream&) const override;
index 57c6082..00c5f6b 100644 (file)
@@ -32,6 +32,7 @@
 #include "AirGenerate.h"
 #include "AirInstInlines.h"
 #include "B3Common.h"
+#include "B3LowerMacros.h"
 #include "B3LowerToAir.h"
 #include "B3MoveConstants.h"
 #include "B3Procedure.h"
@@ -66,6 +67,8 @@ void generateToAir(Procedure& procedure, Air::Code& code)
         dataLog(procedure);
     }
 
+    lowerMacros(procedure);
+
     reduceStrength(procedure);
     
     // FIXME: Add more optimizations here.
index ae7f50e..992d915 100644 (file)
@@ -65,6 +65,7 @@ public:
     BasicBlock* block() const { return m_block; }
     BasicBlock*& block() { return m_block; }
     FrequencyClass frequency() const { return m_frequency; }
+    FrequencyClass& frequency() { return m_frequency; }
 
     void dump(PrintStream& out) const
     {
index 51f82f9..6347db7 100644 (file)
 #if ENABLE(B3_JIT)
 
 #include "B3BasicBlock.h"
+#include "B3ProcedureInlines.h"
+#include "B3ValueInlines.h"
 #include <wtf/BubbleSort.h>
 
 namespace JSC { namespace B3 {
 
+Value* InsertionSet::insertIntConstant(size_t index, Origin origin, Type type, int64_t value)
+{
+    return insertValue(index, m_procedure.addIntConstant(origin, type, value));
+}
+
+Value* InsertionSet::insertIntConstant(size_t index, Value* likeValue, int64_t value)
+{
+    return insertIntConstant(index, likeValue->origin(), likeValue->type(), value);
+}
+
 void InsertionSet::execute(BasicBlock* block)
 {
     bubbleSort(m_insertions.begin(), m_insertions.end());
index cdb3e1a..c0a021f 100644 (file)
@@ -28,6 +28,8 @@
 
 #if ENABLE(B3_JIT)
 
+#include "B3Origin.h"
+#include "B3Type.h"
 #include <wtf/Insertion.h>
 #include <wtf/Vector.h>
 
@@ -62,6 +64,9 @@ public:
     template<typename ValueType, typename... Arguments>
     Value* insert(size_t index, Arguments... arguments);
 
+    Value* insertIntConstant(size_t index, Origin, Type, int64_t value);
+    Value* insertIntConstant(size_t index, Value* likeValue, int64_t value);
+
     void execute(BasicBlock*);
 
 private:
diff --git a/Source/JavaScriptCore/b3/B3LowerMacros.cpp b/Source/JavaScriptCore/b3/B3LowerMacros.cpp
new file mode 100644 (file)
index 0000000..17aca90
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "B3LowerMacros.h"
+
+#if ENABLE(B3_JIT)
+
+#include "B3BasicBlockInlines.h"
+#include "B3BlockInsertionSet.h"
+#include "B3ControlValue.h"
+#include "B3InsertionSetInlines.h"
+#include "B3PhaseScope.h"
+#include "B3ProcedureInlines.h"
+#include "B3UpsilonValue.h"
+#include "B3ValueInlines.h"
+
+namespace JSC { namespace B3 {
+
+namespace {
+
+class LowerMacros {
+public:
+    LowerMacros(Procedure& proc)
+        : m_proc(proc)
+        , m_blockInsertionSet(proc)
+        , m_insertionSet(proc)
+    {
+    }
+
+    bool run()
+    {
+        for (BasicBlock* block : m_proc) {
+            m_block = block;
+            processCurrentBlock();
+        }
+        m_changed |= m_blockInsertionSet.execute();
+        if (m_changed)
+            m_proc.resetReachability();
+        return m_changed;
+    }
+    
+private:
+    void processCurrentBlock()
+    {
+        for (m_index = 0; m_index < m_block->size(); ++m_index) {
+            m_value = m_block->at(m_index);
+            switch (m_value->opcode()) {
+            case ChillDiv: {
+                // ARM supports this instruction natively.
+                if (isARM64())
+                    break;
+
+                m_changed = true;
+
+                // We implement "res = ChillDiv(num, den)" as follows:
+                //
+                //     if (den + 1 <=_unsigned 1) {
+                //         if (!den) {
+                //             res = 0;
+                //             goto done;
+                //         }
+                //         if (num == -2147483648) {
+                //             res = num;
+                //             goto done;
+                //         }
+                //     }
+                //     res = num / dev;
+                // done:
+
+                Value* num = m_value->child(0);
+                Value* den = m_value->child(1);
+
+                Value* one =
+                    m_insertionSet.insertIntConstant(m_index, m_value, 1);
+                Value* isDenOK = m_insertionSet.insert<Value>(
+                    m_index, Above, m_value->origin(),
+                    m_insertionSet.insert<Value>(m_index, Add, m_value->origin(), den, one),
+                    one);
+
+                BasicBlock* before =
+                    m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
+
+                BasicBlock* normalDivCase = m_blockInsertionSet.insertBefore(m_block);
+                BasicBlock* shadyDenCase = m_blockInsertionSet.insertBefore(m_block);
+                BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
+                BasicBlock* neg1DenCase = m_blockInsertionSet.insertBefore(m_block);
+                BasicBlock* intMinCase = m_blockInsertionSet.insertBefore(m_block);
+
+                before->replaceLastWithNew<ControlValue>(
+                    m_proc, Branch, m_value->origin(), isDenOK,
+                    FrequentedBlock(normalDivCase, FrequencyClass::Normal),
+                    FrequentedBlock(shadyDenCase, FrequencyClass::Rare));
+
+                UpsilonValue* normalResult = normalDivCase->appendNew<UpsilonValue>(
+                    m_proc, m_value->origin(),
+                    normalDivCase->appendNew<Value>(m_proc, Div, m_value->origin(), num, den));
+                normalDivCase->appendNew<ControlValue>(
+                    m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
+
+                shadyDenCase->appendNew<ControlValue>(
+                    m_proc, Branch, m_value->origin(), den,
+                    FrequentedBlock(neg1DenCase, FrequencyClass::Normal),
+                    FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
+
+                UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
+                    m_proc, m_value->origin(),
+                    zeroDenCase->appendIntConstant(m_proc, m_value, 0));
+                zeroDenCase->appendNew<ControlValue>(
+                    m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
+
+                int64_t badNumeratorConst;
+                switch (m_value->type()) {
+                case Int32:
+                    badNumeratorConst = std::numeric_limits<int32_t>::min();
+                    break;
+                case Int64:
+                    badNumeratorConst = std::numeric_limits<int64_t>::min();
+                    break;
+                default:
+                    ASSERT_NOT_REACHED();
+                    badNumeratorConst = 0;
+                }
+
+                Value* badNumerator =
+                    neg1DenCase->appendIntConstant(m_proc, m_value, badNumeratorConst);
+
+                neg1DenCase->appendNew<ControlValue>(
+                    m_proc, Branch, m_value->origin(),
+                    neg1DenCase->appendNew<Value>(
+                        m_proc, Equal, m_value->origin(), num, badNumerator),
+                    FrequentedBlock(intMinCase, FrequencyClass::Rare),
+                    FrequentedBlock(normalDivCase, FrequencyClass::Normal));
+
+                UpsilonValue* intMinResult = intMinCase->appendNew<UpsilonValue>(
+                    m_proc, m_value->origin(), badNumerator);
+                intMinCase->appendNew<ControlValue>(
+                    m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
+
+                Value* phi = m_insertionSet.insert<Value>(
+                    m_index, Phi, m_value->type(), m_value->origin());
+                normalResult->setPhi(phi);
+                zeroResult->setPhi(phi);
+                intMinResult->setPhi(phi);
+
+                m_value->replaceWithIdentity(phi);
+                before->updatePredecessorsAfter();
+                break;
+            }
+
+            // FIXME: Implement Switch.
+            // https://bugs.webkit.org/show_bug.cgi?id=151115
+
+            default:
+                break;
+            }
+        }
+        m_insertionSet.execute(m_block);
+    }
+    
+    Procedure& m_proc;
+    BlockInsertionSet m_blockInsertionSet;
+    InsertionSet m_insertionSet;
+    BasicBlock* m_block;
+    unsigned m_index;
+    Value* m_value;
+    bool m_changed { false };
+};
+
+bool lowerMacrosImpl(Procedure& proc)
+{
+    LowerMacros lowerMacros(proc);
+    return lowerMacros.run();
+}
+
+} // anonymous namespace
+
+bool lowerMacros(Procedure& proc)
+{
+    PhaseScope phaseScope(proc, "lowerMacros");
+    bool result = lowerMacrosImpl(proc);
+    if (shouldValidateIR())
+        RELEASE_ASSERT(!lowerMacrosImpl(proc));
+    return result;
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
diff --git a/Source/JavaScriptCore/b3/B3LowerMacros.h b/Source/JavaScriptCore/b3/B3LowerMacros.h
new file mode 100644 (file)
index 0000000..71fdfa1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef B3LowerMacros_h
+#define B3LowerMacros_h
+
+#if ENABLE(B3_JIT)
+
+namespace JSC { namespace B3 {
+
+class Procedure;
+
+// Lowers high-level operations that it's easier to deal with once they are broken up. Currently
+// this includes Switch and ChillDiv.
+
+bool lowerMacros(Procedure&);
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3LowerMacros_h
+
index e13cc4b..e1228f4 100644 (file)
@@ -1233,6 +1233,40 @@ private:
             return;
         }
 
+        case Div: {
+            if (isInt(m_value->type())) {
+                Tmp eax = Tmp(X86Registers::eax);
+                Tmp edx = Tmp(X86Registers::edx);
+
+                Air::Opcode convertToDoubleWord;
+                Air::Opcode div;
+                switch (m_value->type()) {
+                case Int32:
+                    convertToDoubleWord = X86ConvertToDoubleWord32;
+                    div = X86Div32;
+                    break;
+                case Int64:
+                    convertToDoubleWord = X86ConvertToQuadWord64;
+                    div = X86Div64;
+                    break;
+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                    return;
+                }
+                
+                append(Move, tmp(m_value->child(0)), eax);
+                append(convertToDoubleWord, eax, edx);
+                append(div, eax, edx, tmp(m_value->child(1)));
+                append(Move, eax, tmp(m_value));
+                return;
+            }
+
+            // FIXME: Support doubles.
+            // https://bugs.webkit.org/show_bug.cgi?id=150991
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+
         case BitAnd: {
             appendBinOp<And32, And64, Air::Oops, Commutative>(
                 m_value->child(0), m_value->child(1));
index 2e8718b..4ab2e46 100644 (file)
@@ -69,7 +69,7 @@ enum Opcode : int16_t {
     Add,
     Sub,
     Mul,
-    Div,
+    Div, // All bets are off as to what will happen when you execute this for -2^31/-1 and x/0.
 
     // Integer math.
     ChillDiv, // doesn't trap ever, behaves like JS (x/y)|0.
index fbfa527..521568b 100644 (file)
@@ -55,22 +55,27 @@ BasicBlock* Procedure::addBlock(double frequency)
     return result;
 }
 
-Value* Procedure::addIntConstant(Type type, int64_t value)
+Value* Procedure::addIntConstant(Origin origin, Type type, int64_t value)
 {
     switch (type) {
     case Int32:
-        return add<Const32Value>(Origin(), static_cast<int32_t>(value));
+        return add<Const32Value>(origin, static_cast<int32_t>(value));
     case Int64:
-        return add<Const64Value>(Origin(), value);
+        return add<Const64Value>(origin, value);
     case Double:
-        return add<ConstDoubleValue>(Origin(), static_cast<double>(value));
+        return add<ConstDoubleValue>(origin, static_cast<double>(value));
     default:
         RELEASE_ASSERT_NOT_REACHED();
         return nullptr;
     }
 }
 
-Value* Procedure::addBoolConstant(TriState triState)
+Value* Procedure::addIntConstant(Value* likeValue, int64_t value)
+{
+    return addIntConstant(likeValue->origin(), likeValue->type(), value);
+}
+
+Value* Procedure::addBoolConstant(Origin origin, TriState triState)
 {
     int32_t value = 0;
     switch (triState) {
@@ -84,7 +89,7 @@ Value* Procedure::addBoolConstant(TriState triState)
         return nullptr;
     }
 
-    return addIntConstant(Int32, value);
+    return addIntConstant(origin, Int32, value);
 }
 
 void Procedure::resetValueOwners()
index 3bf7a6e..a742a46 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(B3_JIT)
 
+#include "B3Origin.h"
 #include "B3Type.h"
 #include "PureNaN.h"
 #include <wtf/Bag.h>
@@ -40,6 +41,7 @@
 namespace JSC { namespace B3 {
 
 class BasicBlock;
+class BlockInsertionSet;
 class OpaqueByproducts;
 class Value;
 
@@ -56,10 +58,11 @@ public:
     template<typename ValueType, typename... Arguments>
     ValueType* add(Arguments...);
 
-    Value* addIntConstant(Type, int64_t value);
+    Value* addIntConstant(Origin, Type, int64_t value);
+    Value* addIntConstant(Value*, int64_t value);
 
     // Returns null for MixedTriState.
-    Value* addBoolConstant(TriState);
+    Value* addBoolConstant(Origin, TriState);
 
     void resetValueOwners();
     void resetReachability();
@@ -216,6 +219,8 @@ public:
     std::unique_ptr<OpaqueByproducts> takeByproducts() { return WTF::move(m_byproducts); }
 
 private:
+    friend class BlockInsertionSet;
+    
     JS_EXPORT_PRIVATE size_t addValueIndex();
     
     Vector<std::unique_ptr<BasicBlock>> m_blocks;
index 46a8448..e7096d2 100644 (file)
@@ -186,6 +186,16 @@ private:
 
             break;
 
+        case Div:
+        case ChillDiv:
+            // Turn this: Div(constant1, constant2)
+            // Into this: constant1 / constant2
+            // Note that this uses ChillDiv semantics. That's fine, because the rules for Div
+            // are strictly weaker: it has corner cases where it's allowed to do anything it
+            // likes.
+            replaceWithNewValue(m_value->child(0)->divConstant(m_proc, m_value->child(1)));
+            break;
+
         case BitAnd:
             handleCommutativity();
 
@@ -318,7 +328,7 @@ private:
             // Turn this: BitXor(valueX, valueX)
             // Into this: zero-constant.
             if (m_value->child(0) == m_value->child(1)) {
-                replaceWithNewValue(m_proc.addIntConstant(m_value->type(), 0));
+                replaceWithNewValue(m_proc.addIntConstant(m_value, 0));
                 break;
             }
 
@@ -446,7 +456,9 @@ private:
             // Turn this: Equal(const1, const2)
             // Into this: const1 == const2
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->equalConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->equalConstant(m_value->child(1))));
             break;
             
         case NotEqual:
@@ -473,7 +485,9 @@ private:
             // Turn this: NotEqual(const1, const2)
             // Into this: const1 != const2
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->notEqualConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->notEqualConstant(m_value->child(1))));
             break;
 
         case LessThan:
@@ -481,42 +495,58 @@ private:
             // https://bugs.webkit.org/show_bug.cgi?id=150958
 
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->lessThanConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->lessThanConstant(m_value->child(1))));
             break;
 
         case GreaterThan:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->greaterThanConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->greaterThanConstant(m_value->child(1))));
             break;
 
         case LessEqual:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->lessEqualConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->lessEqualConstant(m_value->child(1))));
             break;
 
         case GreaterEqual:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->greaterEqualConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->greaterEqualConstant(m_value->child(1))));
             break;
 
         case Above:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->aboveConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->aboveConstant(m_value->child(1))));
             break;
 
         case Below:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->belowConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->belowConstant(m_value->child(1))));
             break;
 
         case AboveEqual:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->aboveEqualConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->aboveEqualConstant(m_value->child(1))));
             break;
 
         case BelowEqual:
             replaceWithNewValue(
-                m_proc.addBoolConstant(m_value->child(0)->belowEqualConstant(m_value->child(1))));
+                m_proc.addBoolConstant(
+                    m_value->origin(),
+                    m_value->child(0)->belowEqualConstant(m_value->child(1))));
             break;
 
         case Branch: {
@@ -553,7 +583,7 @@ private:
             // Into this: Jump(else)
             if (triState == FalseTriState) {
                 branch->taken().block()->removePredecessor(m_block);
-                branch->convertToJump(branch->notTaken());
+                branch->convertToJump(branch->notTaken().block());
                 m_changedCFG = true;
                 break;
             }
@@ -562,7 +592,7 @@ private:
             // Into this: Jump(then)
             if (triState == TrueTriState) {
                 branch->notTaken().block()->removePredecessor(m_block);
-                branch->convertToJump(branch->taken());
+                branch->convertToJump(branch->taken().block());
                 m_changedCFG = true;
                 break;
             }
@@ -631,6 +661,11 @@ private:
 
     void simplifyCFG()
     {
+        if (verbose) {
+            dataLog("Before simplifyCFG:\n");
+            dataLog(m_proc);
+        }
+        
         // We have three easy simplification rules:
         //
         // 1) If a successor is a block that just jumps to another block, then jump directly to
@@ -651,6 +686,9 @@ private:
         // iterations needed to kill a lot of code.
 
         for (BasicBlock* block : m_proc) {
+            if (verbose)
+                dataLog("Considering block ", *block, ":\n");
+
             checkPredecessorValidity();
 
             // We don't care about blocks that don't have successors.
@@ -664,7 +702,15 @@ private:
                     && successor->last()->opcode() == Jump) {
                     BasicBlock* newSuccessor = successor->successorBlock(0);
                     if (newSuccessor != successor) {
-                        newSuccessor->replacePredecessor(successor, block);
+                        if (verbose) {
+                            dataLog(
+                                "Replacing ", pointerDump(block), "->", pointerDump(successor),
+                                " with ", pointerDump(block), "->", pointerDump(newSuccessor),
+                                "\n");
+                        }
+                        // Note that we do not do replacePredecessor() because the block we're
+                        // skipping will still have newSuccessor as its successor.
+                        newSuccessor->addPredecessor(block);
                         successor = newSuccessor;
                         m_changedCFG = true;
                     }
@@ -679,14 +725,18 @@ private:
                 if (!effects.mustExecute()) {
                     // All of the successors must be the same.
                     bool allSame = true;
-                    FrequentedBlock firstSuccessor = block->successor(0);
+                    BasicBlock* firstSuccessor = block->successorBlock(0);
                     for (unsigned i = 1; i < block->numSuccessors(); ++i) {
-                        if (block->successorBlock(i) != firstSuccessor.block()) {
+                        if (block->successorBlock(i) != firstSuccessor) {
                             allSame = false;
                             break;
                         }
                     }
                     if (allSame) {
+                        if (verbose) {
+                            dataLog(
+                                "Changing ", pointerDump(block), "'s terminal to a Jump.\n");
+                        }
                         block->last()->as<ControlValue>()->convertToJump(firstSuccessor);
                         m_changedCFG = true;
                     }
@@ -719,6 +769,12 @@ private:
                     // Ensure that predecessors of block's new successors know what's up.
                     for (BasicBlock* newSuccessor : block->successorBlocks())
                         newSuccessor->replacePredecessor(successor, block);
+
+                    if (verbose) {
+                        dataLog(
+                            "Merged ", pointerDump(block), "->", pointerDump(successor), "\n");
+                    }
+                    
                     m_changedCFG = true;
                 }
             }
index 469e9d2..b70ea02 100644 (file)
@@ -80,8 +80,10 @@ public:
         }
 
         for (Value* value : valueInProc) {
-            for (Value* child : value->children())
+            for (Value* child : value->children()) {
+                VALIDATE(child, ("At ", *value));
                 VALIDATE(valueInProc.contains(child), ("At ", *value, "->", pointerDump(child)));
+            }
         }
 
         HashMap<BasicBlock*, HashSet<BasicBlock*>> allPredecessors;
index bb4de14..22c016f 100644 (file)
@@ -124,92 +124,97 @@ Value* Value::addConstant(Procedure&, int32_t) const
     return nullptr;
 }
 
-Value* Value::addConstant(Procedure&, Value*) const
+Value* Value::addConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::subConstant(Procedure&, Value*) const
+Value* Value::subConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::bitAndConstant(Procedure&, Value*) const
+Value* Value::divConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::bitOrConstant(Procedure&, Value*) const
+Value* Value::bitAndConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::bitXorConstant(Procedure&, Value*) const
+Value* Value::bitOrConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::shlConstant(Procedure&, Value*) const
+Value* Value::bitXorConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::sShrConstant(Procedure&, Value*) const
+Value* Value::shlConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-Value* Value::zShrConstant(Procedure&, Value*) const
+Value* Value::sShrConstant(Procedure&, const Value*) const
 {
     return nullptr;
 }
 
-TriState Value::equalConstant(Value*) const
+Value* Value::zShrConstant(Procedure&, const Value*) const
+{
+    return nullptr;
+}
+
+TriState Value::equalConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::notEqualConstant(Value*) const
+TriState Value::notEqualConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::lessThanConstant(Value*) const
+TriState Value::lessThanConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::greaterThanConstant(Value*) const
+TriState Value::greaterThanConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::lessEqualConstant(Value*) const
+TriState Value::lessEqualConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::greaterEqualConstant(Value*) const
+TriState Value::greaterEqualConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::aboveConstant(Value*) const
+TriState Value::aboveConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::belowConstant(Value*) const
+TriState Value::belowConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::aboveEqualConstant(Value*) const
+TriState Value::aboveEqualConstant(const Value*) const
 {
     return MixedTriState;
 }
 
-TriState Value::belowEqualConstant(Value*) const
+TriState Value::belowEqualConstant(const Value*) const
 {
     return MixedTriState;
 }
index 04eb376..760b188 100644 (file)
@@ -111,25 +111,26 @@ public:
     
     virtual Value* negConstant(Procedure&) const;
     virtual Value* addConstant(Procedure&, int32_t other) const;
-    virtual Value* addConstant(Procedure&, Value* other) const;
-    virtual Value* subConstant(Procedure&, Value* other) const;
-    virtual Value* bitAndConstant(Procedure&, Value* other) const;
-    virtual Value* bitOrConstant(Procedure&, Value* other) const;
-    virtual Value* bitXorConstant(Procedure&, Value* other) const;
-    virtual Value* shlConstant(Procedure&, Value* other) const;
-    virtual Value* sShrConstant(Procedure&, Value* other) const;
-    virtual Value* zShrConstant(Procedure&, Value* other) const;
+    virtual Value* addConstant(Procedure&, const Value* other) const;
+    virtual Value* subConstant(Procedure&, const Value* other) const;
+    virtual Value* divConstant(Procedure&, const Value* other) const; // This chooses ChillDiv semantics for integers.
+    virtual Value* bitAndConstant(Procedure&, const Value* other) const;
+    virtual Value* bitOrConstant(Procedure&, const Value* other) const;
+    virtual Value* bitXorConstant(Procedure&, const Value* other) const;
+    virtual Value* shlConstant(Procedure&, const Value* other) const;
+    virtual Value* sShrConstant(Procedure&, const Value* other) const;
+    virtual Value* zShrConstant(Procedure&, const Value* other) const;
     
-    virtual TriState equalConstant(Value* other) const;
-    virtual TriState notEqualConstant(Value* other) const;
-    virtual TriState lessThanConstant(Value* other) const;
-    virtual TriState greaterThanConstant(Value* other) const;
-    virtual TriState lessEqualConstant(Value* other) const;
-    virtual TriState greaterEqualConstant(Value* other) const;
-    virtual TriState aboveConstant(Value* other) const;
-    virtual TriState belowConstant(Value* other) const;
-    virtual TriState aboveEqualConstant(Value* other) const;
-    virtual TriState belowEqualConstant(Value* other) const;
+    virtual TriState equalConstant(const Value* other) const;
+    virtual TriState notEqualConstant(const Value* other) const;
+    virtual TriState lessThanConstant(const Value* other) const;
+    virtual TriState greaterThanConstant(const Value* other) const;
+    virtual TriState lessEqualConstant(const Value* other) const;
+    virtual TriState greaterEqualConstant(const Value* other) const;
+    virtual TriState aboveConstant(const Value* other) const;
+    virtual TriState belowConstant(const Value* other) const;
+    virtual TriState aboveEqualConstant(const Value* other) const;
+    virtual TriState belowEqualConstant(const Value* other) const;
 
     // If the value is a comparison then this returns the inverted form of that comparison, if
     // possible. It can be impossible for double comparisons, where for example LessThan and
index edb89b1..b1d14a2 100644 (file)
@@ -121,6 +121,7 @@ void generate(Code& code, CCallHelpers& jit)
 
     for (BasicBlock* block : code) {
         blockJumps[block].link(&jit);
+        blockLabels[block] = jit.label();
         ASSERT(block->size() >= 1);
         for (unsigned i = 0; i < block->size() - 1; ++i) {
             CCallHelpers::Jump jump = block->at(i).generate(jit, context);
@@ -140,8 +141,6 @@ void generate(Code& code, CCallHelpers& jit)
         }
         
         CCallHelpers::Jump jump = block->last().generate(jit, context);
-        for (Inst& inst : *block)
-            jump = inst.generate(jit, context);
         switch (block->numSuccessors()) {
         case 0:
             ASSERT(!jump.isSet());
index 8901115..cd07255 100644 (file)
@@ -135,6 +135,36 @@ inline bool isUrshift64Valid(const Inst& inst)
     return isShiftValid(inst);
 }
 
+inline bool isX86DivHelperValid(const Inst& inst)
+{
+#if CPU(X86) || CPU(X86_64)
+    return inst.args[0] == Tmp(X86Registers::eax)
+        && inst.args[1] == Tmp(X86Registers::edx);
+#else
+    return false;
+#endif
+}
+
+inline bool isX86ConvertToDoubleWord32Valid(const Inst& inst)
+{
+    return isX86DivHelperValid(inst);
+}
+
+inline bool isX86ConvertToQuadWord64Valid(const Inst& inst)
+{
+    return isX86DivHelperValid(inst);
+}
+
+inline bool isX86Div32Valid(const Inst& inst)
+{
+    return isX86DivHelperValid(inst);
+}
+
+inline bool isX86Div64Valid(const Inst& inst)
+{
+    return isX86DivHelperValid(inst);
+}
+
 } } } // namespace JSC::B3::Air
 
 #endif // ENABLE(B3_JIT)
index 5f3a556..6965ab6 100644 (file)
@@ -96,6 +96,22 @@ Neg32 UD:G
 Neg64 UD:G
     Tmp
 
+Mul32 U:G, UD:G
+    Tmp, Tmp
+    Addr, Tmp
+
+X86ConvertToDoubleWord32 U:G, D:G
+    Tmp*, Tmp*
+
+X86ConvertToQuadWord64 U:G, D:G
+    Tmp*, Tmp*
+
+X86Div32 UD:G, UD:G, U:G
+    Tmp*, Tmp*, Tmp
+
+X86Div64 UD:G, UD:G, U:G
+    Tmp*, Tmp*, Tmp
+
 Lea UA:G, D:G
     Addr, Tmp
 
@@ -157,10 +173,6 @@ Xor64 U:G, UD:G
     Tmp, Addr
     Imm, Tmp
 
-Mul32 U:G, UD:G
-    Tmp, Tmp
-    Addr, Tmp
-
 # Note that Move operates over the full register size, which is either 32-bit or 64-bit depending on
 # the platform. I'm not entirely sure that this is a good thing; it might be better to just have a
 # Move64 instruction. OTOH, our MacroAssemblers already have this notion of "move()" that basically
index 1cd8b76..1eed982 100644 (file)
@@ -86,7 +86,9 @@ bool simplifyCFG(Code& code)
                                 "Replacing ", pointerDump(block), "->", pointerDump(successor),
                                 " with ", pointerDump(block), "->", pointerDump(newSuccessor), "\n");
                         }
-                        newSuccessor->replacePredecessor(successor, block);
+                        // Note that we do not do replacePredecessor() because the block we're
+                        // skipping will still have newSuccessor as its successor.
+                        newSuccessor->addPredecessor(block);
                         successor = newSuccessor;
                         changed = true;
                     }
@@ -112,6 +114,7 @@ bool simplifyCFG(Code& code)
                             dataLog("Changing ", pointerDump(block), "'s terminal to a Jump.\n");
                         block->last() = Inst(Jump, block->last().origin);
                         block->successors().resize(1);
+                        block->successors()[0].frequency() = FrequencyClass::Normal;
                         changed = true;
                     }
                 }
index 33192d5..d23ea0e 100644 (file)
@@ -2859,6 +2859,108 @@ void testCallFunctionWithHellaDoubleArguments()
     CHECK(compileAndRun<double>(proc) == functionWithHellaDoubleArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
 }
 
+void testChillDiv(int num, int den, int res)
+{
+    // Test non-constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+        CHECK(compileAndRun<int>(proc, num, den) == res);
+    }
+
+    // Test constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Const32Value>(proc, Origin(), num),
+                root->appendNew<Const32Value>(proc, Origin(), den)));
+        
+        CHECK(compileAndRun<int>(proc) == res);
+    }
+}
+
+void testChillDivTwice(int num1, int den1, int num2, int den2, int res)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)))));
+    
+    CHECK(compileAndRun<int>(proc, num1, den1, num2, den2) == res);
+}
+
+void testChillDiv64(int64_t num, int64_t den, int64_t res)
+{
+    if (!is64Bit())
+        return;
+
+    // Test non-constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        
+        CHECK(compileAndRun<int64_t>(proc, num, den) == res);
+    }
+
+    // Test constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Const64Value>(proc, Origin(), num),
+                root->appendNew<Const64Value>(proc, Origin(), den)));
+        
+        CHECK(compileAndRun<int64_t>(proc) == res);
+    }
+}
+
 #define RUN(test) do {                          \
         if (!shouldRun(#test))                  \
             break;                              \
@@ -3337,6 +3439,26 @@ void run(const char* filter)
     RUN(testCallSimpleDouble(1, 2));
     RUN(testCallFunctionWithHellaDoubleArguments());
 
+    RUN(testChillDiv(4, 2, 2));
+    RUN(testChillDiv(1, 0, 0));
+    RUN(testChillDiv(0, 0, 0));
+    RUN(testChillDiv(1, -1, -1));
+    RUN(testChillDiv(-2147483647 - 1, 0, 0));
+    RUN(testChillDiv(-2147483647 - 1, 1, -2147483647 - 1));
+    RUN(testChillDiv(-2147483647 - 1, -1, -2147483647 - 1));
+    RUN(testChillDiv(-2147483647 - 1, 2, -1073741824));
+    RUN(testChillDiv64(4, 2, 2));
+    RUN(testChillDiv64(1, 0, 0));
+    RUN(testChillDiv64(0, 0, 0));
+    RUN(testChillDiv64(1, -1, -1));
+    RUN(testChillDiv64(-9223372036854775807ll - 1, 0, 0));
+    RUN(testChillDiv64(-9223372036854775807ll - 1, 1, -9223372036854775807ll - 1));
+    RUN(testChillDiv64(-9223372036854775807ll - 1, -1, -9223372036854775807ll - 1));
+    RUN(testChillDiv64(-9223372036854775807ll - 1, 2, -4611686018427387904));
+    RUN(testChillDivTwice(4, 2, 6, 2, 5));
+    RUN(testChillDivTwice(4, 0, 6, 2, 3));
+    RUN(testChillDivTwice(4, 2, 6, 0, 2));
+
     if (tasks.isEmpty())
         usage();
 
index 0bdee20..03cab12 100644 (file)
@@ -45,7 +45,7 @@ public:
     void insert(size_t index, PassRefPtr<BasicBlock>);
     BasicBlock* insert(size_t index, float executionCount);
     BasicBlock* insertBefore(BasicBlock* before, float executionCount);
-    
+
     bool execute();
 
 private:
index e44d72f..e2f99c4 100755 (executable)
@@ -3399,8 +3399,8 @@ void SpeculativeJIT::compileArithDiv(Node* node)
         }
             
         m_jit.move(op1GPR, eax.gpr());
-        m_jit.assembler().cdq();
-        m_jit.assembler().idivl_r(op2GPR);
+        m_jit.x86ConvertToDoubleWord32();
+        m_jit.x86Div32(op2GPR);
             
         if (op2TempGPR != InvalidGPRReg)
             unlock(op2TempGPR);
@@ -3555,8 +3555,8 @@ void SpeculativeJIT::compileArithMod(Node* node)
 
                 m_jit.move(op1Gpr, eax.gpr());
                 m_jit.move(TrustedImm32(divisor), scratchGPR);
-                m_jit.assembler().cdq();
-                m_jit.assembler().idivl_r(scratchGPR);
+                m_jit.x86ConvertToDoubleWord32();
+                m_jit.x86Div32(scratchGPR);
                 if (shouldCheckNegativeZero(node->arithMode())) {
                     JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
                     speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
@@ -3646,8 +3646,8 @@ void SpeculativeJIT::compileArithMod(Node* node)
         }
             
         m_jit.move(op1GPR, eax.gpr());
-        m_jit.assembler().cdq();
-        m_jit.assembler().idivl_r(op2GPR);
+        m_jit.x86ConvertToDoubleWord32();
+        m_jit.x86Div32(op2GPR);
             
         if (op2TempGPR != InvalidGPRReg)
             unlock(op2TempGPR);
index 91bba03..d13a11b 100644 (file)
@@ -623,8 +623,8 @@ void JIT::emit_op_mod(Instruction* currentInstruction)
     Jump denominatorNotNeg1 = branch32(NotEqual, ecx, TrustedImm32(-1));
     addSlowCase(branch32(Equal, regT0, TrustedImm32(-2147483647-1)));
     denominatorNotNeg1.link(this);
-    m_assembler.cdq();
-    m_assembler.idivl_r(ecx);
+    x86ConvertToDoubleWord32();
+    x86Div32(ecx);
     Jump numeratorPositive = branch32(GreaterThanOrEqual, regT4, TrustedImm32(0));
     addSlowCase(branchTest32(Zero, edx));
     numeratorPositive.link(this);
index e2d2c10..f79beaa 100644 (file)
@@ -858,8 +858,8 @@ void JIT::emit_op_mod(Instruction* currentInstruction)
     Jump denominatorNotNeg1 = branch32(NotEqual, regT2, TrustedImm32(-1));
     addSlowCase(branch32(Equal, regT0, TrustedImm32(-2147483647-1)));
     denominatorNotNeg1.link(this);
-    m_assembler.cdq();
-    m_assembler.idivl_r(regT2);
+    x86ConvertToDoubleWord32();
+    x86Div32(regT2);
     Jump numeratorPositive = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0));
     addSlowCase(branchTest32(Zero, regT1));
     numeratorPositive.link(this);
index dde1957..a82927a 100644 (file)
@@ -763,8 +763,8 @@ public:
             ASSERT(GPRInfo::regT0 == X86Registers::eax);
             move(GPRInfo::regT1, X86Registers::ecx);
             if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
-                m_assembler.cdq();
-                m_assembler.idivl_r(X86Registers::ecx);
+                x86ConvertToDoubleWord32();
+                x86Div32(X86Registers::ecx);
             } else {
                 ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod);
                 xor32(X86Registers::edx, X86Registers::edx);
index 65ac9a9..6625060 100644 (file)
@@ -1,3 +1,23 @@
+2015-11-10  Filip Pizlo  <fpizlo@apple.com>
+
+        B3 should be able to compile a program with ChillDiv
+        https://bugs.webkit.org/show_bug.cgi?id=151114
+
+        Reviewed by Benjamin Poulain.
+
+        Needed to beef up some compiler algorithms. All of the hardening was about making them
+        work with objects that have move semantics but not copy semantics. This arises in B3
+        basic block insertion sets.
+
+        * wtf/BubbleSort.h:
+        (WTF::bubbleSort):
+        * wtf/Insertion.h:
+        (WTF::Insertion::Insertion):
+        (WTF::Insertion::index):
+        (WTF::Insertion::element):
+        (WTF::Insertion::operator<):
+        (WTF::executeInsertions):
+
 2015-11-10  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Use CROSS_PLATFORM_CONTEXT_MENUS
index 0dbae4c..86bbca2 100644 (file)
@@ -89,8 +89,8 @@ void bubbleSort(IteratorType begin, IteratorType end)
 {
     bubbleSort(
         begin, end,
-        [] (typename std::iterator_traits<IteratorType>::value_type left,
-            typename std::iterator_traits<IteratorType>::value_type right) -> bool {
+        [] (const typename std::iterator_traits<IteratorType>::value_type& left,
+            const typename std::iterator_traits<IteratorType>::value_type& right) -> bool {
             return left < right;
         });
 }
index c4e136d..65f3bff 100644 (file)
@@ -32,15 +32,17 @@ template<typename T>
 class Insertion {
 public:
     Insertion() { }
-    
-    Insertion(size_t index, T element)
+
+    template<typename U>
+    Insertion(size_t index, U&& element)
         : m_index(index)
-        , m_element(element)
+        , m_element(std::forward<U>(element))
     {
     }
     
     size_t index() const { return m_index; }
-    T element() const { return m_element; }
+    const T& element() const { return m_element; }
+    T& element() { return m_element; }
     
     bool operator<(const Insertion& other) const
     {
@@ -66,8 +68,8 @@ void executeInsertions(TargetVectorType& target, InsertionVectorType& insertions
         size_t firstIndex = insertions[indexInInsertions].index() + indexInInsertions;
         size_t indexOffset = indexInInsertions + 1;
         for (size_t i = lastIndex; --i > firstIndex;)
-            target[i] = target[i - indexOffset];
-        target[firstIndex] = insertions[indexInInsertions].element();
+            target[i] = WTF::move(target[i - indexOffset]);
+        target[firstIndex] = WTF::move(insertions[indexInInsertions].element());
         lastIndex = firstIndex;
     }
     insertions.resize(0);