Changeset 192072 in webkit
- Timestamp:
- Nov 5, 2015 1:51:05 PM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 29 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r192064 r192072 1 2015-11-05 Filip Pizlo <fpizlo@apple.com> 2 3 B3->Air lowering should have a story for compare-branch fusion 4 https://bugs.webkit.org/show_bug.cgi?id=150721 5 6 Reviewed by Geoffrey Garen. 7 8 This adds comprehensive support for compares and compare/branch fusion to B3. The fusion is 9 super aggressive. It can even handle things like Branch(LessThan(Load8S(...), constant)). It 10 can even handle flipping the operands to the branch, and flipping the comparison condition, 11 if it enables a more efficient instruction. This happens when there is asymmetry in the 12 admitted argument kinds. For example, Branch32 will only accept an Imm as a second operand. 13 If we do a LessThan(constant, load) then we will generate it as: 14 15 Branch32 GreaterThan, (addr), $imm 16 17 This also supports compiling and fusing tests, and to some extent, compiling and fusing 18 double compares. Though we cannot test doubles yet because we don't have enough support for 19 that. 20 21 This also supports fusing compare/branches in Checks. We basically get that for free. 22 23 Because I wanted to fuse comparisons with sub-32-bit loads, I added support for those loads 24 directly, too. 25 26 The tests are now getting super big, so I made testb3 run tests in parallel. 27 28 Finally, this slightly changes the semantics of Branch and Check. Previously they would have 29 accepted a double to branch on. I found that this is awkward. It's especially awkward since 30 we want to be explicit about when a double zero constant is materialized. So, from now on, we 31 require that to branch on a double being non-zero, you have to do Branch(NotEqual(value, 0)). 32 33 * assembler/MacroAssembler.h: 34 (JSC::MacroAssembler::invert): 35 (JSC::MacroAssembler::isInvertible): 36 (JSC::MacroAssembler::flip): 37 (JSC::MacroAssembler::isSigned): 38 (JSC::MacroAssembler::isUnsigned): 39 * assembler/MacroAssemblerX86Common.h: 40 (JSC::MacroAssemblerX86Common::test32): 41 (JSC::MacroAssemblerX86Common::invert): 42 * b3/B3CheckSpecial.cpp: 43 (JSC::B3::CheckSpecial::Key::Key): 44 (JSC::B3::CheckSpecial::Key::dump): 45 (JSC::B3::CheckSpecial::CheckSpecial): 46 (JSC::B3::CheckSpecial::~CheckSpecial): 47 * b3/B3CheckSpecial.h: 48 (JSC::B3::CheckSpecial::Key::Key): 49 (JSC::B3::CheckSpecial::Key::operator==): 50 (JSC::B3::CheckSpecial::Key::operator!=): 51 (JSC::B3::CheckSpecial::Key::operator bool): 52 (JSC::B3::CheckSpecial::Key::opcode): 53 (JSC::B3::CheckSpecial::Key::numArgs): 54 (JSC::B3::CheckSpecial::Key::isHashTableDeletedValue): 55 (JSC::B3::CheckSpecial::Key::hash): 56 (JSC::B3::CheckSpecialKeyHash::hash): 57 (JSC::B3::CheckSpecialKeyHash::equal): 58 * b3/B3Const32Value.cpp: 59 (JSC::B3::Const32Value::zShrConstant): 60 (JSC::B3::Const32Value::equalConstant): 61 (JSC::B3::Const32Value::notEqualConstant): 62 (JSC::B3::Const32Value::lessThanConstant): 63 (JSC::B3::Const32Value::greaterThanConstant): 64 (JSC::B3::Const32Value::lessEqualConstant): 65 (JSC::B3::Const32Value::greaterEqualConstant): 66 (JSC::B3::Const32Value::aboveConstant): 67 (JSC::B3::Const32Value::belowConstant): 68 (JSC::B3::Const32Value::aboveEqualConstant): 69 (JSC::B3::Const32Value::belowEqualConstant): 70 (JSC::B3::Const32Value::dumpMeta): 71 * b3/B3Const32Value.h: 72 * b3/B3Const64Value.cpp: 73 (JSC::B3::Const64Value::zShrConstant): 74 (JSC::B3::Const64Value::equalConstant): 75 (JSC::B3::Const64Value::notEqualConstant): 76 (JSC::B3::Const64Value::lessThanConstant): 77 (JSC::B3::Const64Value::greaterThanConstant): 78 (JSC::B3::Const64Value::lessEqualConstant): 79 (JSC::B3::Const64Value::greaterEqualConstant): 80 (JSC::B3::Const64Value::aboveConstant): 81 (JSC::B3::Const64Value::belowConstant): 82 (JSC::B3::Const64Value::aboveEqualConstant): 83 (JSC::B3::Const64Value::belowEqualConstant): 84 (JSC::B3::Const64Value::dumpMeta): 85 * b3/B3Const64Value.h: 86 * b3/B3ConstDoubleValue.cpp: 87 (JSC::B3::ConstDoubleValue::subConstant): 88 (JSC::B3::ConstDoubleValue::equalConstant): 89 (JSC::B3::ConstDoubleValue::notEqualConstant): 90 (JSC::B3::ConstDoubleValue::lessThanConstant): 91 (JSC::B3::ConstDoubleValue::greaterThanConstant): 92 (JSC::B3::ConstDoubleValue::lessEqualConstant): 93 (JSC::B3::ConstDoubleValue::greaterEqualConstant): 94 (JSC::B3::ConstDoubleValue::dumpMeta): 95 * b3/B3ConstDoubleValue.h: 96 * b3/B3LowerToAir.cpp: 97 (JSC::B3::Air::LowerToAir::LowerToAir): 98 (JSC::B3::Air::LowerToAir::run): 99 (JSC::B3::Air::LowerToAir::shouldCopyPropagate): 100 (JSC::B3::Air::LowerToAir::ArgPromise::ArgPromise): 101 (JSC::B3::Air::LowerToAir::ArgPromise::tmp): 102 (JSC::B3::Air::LowerToAir::ArgPromise::operator bool): 103 (JSC::B3::Air::LowerToAir::ArgPromise::kind): 104 (JSC::B3::Air::LowerToAir::ArgPromise::peek): 105 (JSC::B3::Air::LowerToAir::ArgPromise::consume): 106 (JSC::B3::Air::LowerToAir::tmp): 107 (JSC::B3::Air::LowerToAir::tmpPromise): 108 (JSC::B3::Air::LowerToAir::canBeInternal): 109 (JSC::B3::Air::LowerToAir::addr): 110 (JSC::B3::Air::LowerToAir::loadPromise): 111 (JSC::B3::Air::LowerToAir::imm): 112 (JSC::B3::Air::LowerToAir::appendBinOp): 113 (JSC::B3::Air::LowerToAir::tryAppendStoreUnOp): 114 (JSC::B3::Air::LowerToAir::tryAppendStoreBinOp): 115 (JSC::B3::Air::LowerToAir::createGenericCompare): 116 (JSC::B3::Air::LowerToAir::createBranch): 117 (JSC::B3::Air::LowerToAir::createCompare): 118 (JSC::B3::Air::LowerToAir::tryLoad): 119 (JSC::B3::Air::LowerToAir::tryLoad8S): 120 (JSC::B3::Air::LowerToAir::tryLoad8Z): 121 (JSC::B3::Air::LowerToAir::tryLoad16S): 122 (JSC::B3::Air::LowerToAir::tryLoad16Z): 123 (JSC::B3::Air::LowerToAir::tryAdd): 124 (JSC::B3::Air::LowerToAir::tryStackSlot): 125 (JSC::B3::Air::LowerToAir::tryEqual): 126 (JSC::B3::Air::LowerToAir::tryNotEqual): 127 (JSC::B3::Air::LowerToAir::tryLessThan): 128 (JSC::B3::Air::LowerToAir::tryGreaterThan): 129 (JSC::B3::Air::LowerToAir::tryLessEqual): 130 (JSC::B3::Air::LowerToAir::tryGreaterEqual): 131 (JSC::B3::Air::LowerToAir::tryAbove): 132 (JSC::B3::Air::LowerToAir::tryBelow): 133 (JSC::B3::Air::LowerToAir::tryAboveEqual): 134 (JSC::B3::Air::LowerToAir::tryBelowEqual): 135 (JSC::B3::Air::LowerToAir::tryPatchpoint): 136 (JSC::B3::Air::LowerToAir::tryCheck): 137 (JSC::B3::Air::LowerToAir::tryBranch): 138 (JSC::B3::Air::LowerToAir::loadAddr): Deleted. 139 * b3/B3LoweringMatcher.patterns: 140 * b3/B3Opcode.cpp: 141 (JSC::B3::invertedCompare): 142 * b3/B3Opcode.h: 143 (JSC::B3::isCheckMath): 144 * b3/B3Procedure.cpp: 145 (JSC::B3::Procedure::addBlock): 146 (JSC::B3::Procedure::addIntConstant): 147 (JSC::B3::Procedure::addBoolConstant): 148 (JSC::B3::Procedure::resetValueOwners): 149 * b3/B3Procedure.h: 150 * b3/B3ReduceStrength.cpp: 151 * b3/B3Validate.cpp: 152 * b3/B3Value.cpp: 153 (JSC::B3::Value::zShrConstant): 154 (JSC::B3::Value::equalConstant): 155 (JSC::B3::Value::notEqualConstant): 156 (JSC::B3::Value::lessThanConstant): 157 (JSC::B3::Value::greaterThanConstant): 158 (JSC::B3::Value::lessEqualConstant): 159 (JSC::B3::Value::greaterEqualConstant): 160 (JSC::B3::Value::aboveConstant): 161 (JSC::B3::Value::belowConstant): 162 (JSC::B3::Value::aboveEqualConstant): 163 (JSC::B3::Value::belowEqualConstant): 164 (JSC::B3::Value::invertedCompare): 165 * b3/B3Value.h: 166 * b3/air/AirArg.cpp: 167 (JSC::B3::Air::Arg::isRepresentableAs): 168 (JSC::B3::Air::Arg::dump): 169 (WTF::printInternal): 170 * b3/air/AirArg.h: 171 (JSC::B3::Air::Arg::isUse): 172 (JSC::B3::Air::Arg::typeForB3Type): 173 (JSC::B3::Air::Arg::widthForB3Type): 174 (JSC::B3::Air::Arg::Arg): 175 (JSC::B3::Air::Arg::value): 176 (JSC::B3::Air::Arg::isRepresentableAs): 177 (JSC::B3::Air::Arg::asNumber): 178 (JSC::B3::Air::Arg::pointerValue): 179 (JSC::B3::Air::Arg::asDoubleCondition): 180 (JSC::B3::Air::Arg::inverted): 181 (JSC::B3::Air::Arg::flipped): 182 (JSC::B3::Air::Arg::isSignedCond): 183 (JSC::B3::Air::Arg::isUnsignedCond): 184 * b3/air/AirInst.h: 185 (JSC::B3::Air::Inst::Inst): 186 (JSC::B3::Air::Inst::operator bool): 187 * b3/air/AirOpcode.opcodes: 188 * b3/air/opcode_generator.rb: 189 * b3/testb3.cpp: 190 (hiddenTruthBecauseNoReturnIsStupid): 191 (JSC::B3::testStoreLoadStackSlot): 192 (JSC::B3::modelLoad): 193 (JSC::B3::testLoad): 194 (JSC::B3::testBranch): 195 (JSC::B3::testComplex): 196 (JSC::B3::testSimplePatchpoint): 197 (JSC::B3::testSimpleCheck): 198 (JSC::B3::genericTestCompare): 199 (JSC::B3::modelCompare): 200 (JSC::B3::testCompareLoad): 201 (JSC::B3::testCompareImpl): 202 (JSC::B3::testCompare): 203 (JSC::B3::run): 204 (main): 205 * dfg/DFGSpeculativeJIT.cpp: 206 (JSC::DFG::SpeculativeJIT::compileArithMod): 207 * jit/JITPropertyAccess.cpp: 208 (JSC::JIT::emitIntTypedArrayGetByVal): 209 (JSC::JIT::emitIntTypedArrayPutByVal): 210 1 211 2015-11-05 Joseph Pecoraro <pecoraro@apple.com> 2 212 -
trunk/Source/JavaScriptCore/assembler/MacroAssembler.h
r191816 r192072 168 168 case DoubleLessThanOrEqualOrUnordered: 169 169 return DoubleGreaterThan; 170 default: 171 RELEASE_ASSERT_NOT_REACHED(); 172 return DoubleEqual; // make compiler happy 173 } 170 } 171 RELEASE_ASSERT_NOT_REACHED(); 172 return DoubleEqual; // make compiler happy 174 173 } 175 174 … … 195 194 RELEASE_ASSERT_NOT_REACHED(); 196 195 return Zero; // Make compiler happy for release builds. 196 } 197 } 198 199 static RelationalCondition flip(RelationalCondition cond) 200 { 201 switch (cond) { 202 case Equal: 203 case NotEqual: 204 return cond; 205 case Above: 206 return Below; 207 case AboveOrEqual: 208 return BelowOrEqual; 209 case Below: 210 return Above; 211 case BelowOrEqual: 212 return AboveOrEqual; 213 case GreaterThan: 214 return LessThan; 215 case GreaterThanOrEqual: 216 return LessThanOrEqual; 217 case LessThan: 218 return GreaterThan; 219 case LessThanOrEqual: 220 return GreaterThanOrEqual; 221 } 222 223 RELEASE_ASSERT_NOT_REACHED(); 224 return Equal; 225 } 226 227 // True if this: 228 // branch8(cond, value, value) 229 // Is the same as this: 230 // branch32(cond, signExt8(value), signExt8(value)) 231 static bool isSigned(RelationalCondition cond) 232 { 233 switch (cond) { 234 case Equal: 235 case NotEqual: 236 case GreaterThan: 237 case GreaterThanOrEqual: 238 case LessThan: 239 case LessThanOrEqual: 240 return true; 241 default: 242 return false; 243 } 244 } 245 246 // True if this: 247 // branch8(cond, value, value) 248 // Is the same as this: 249 // branch32(cond, zeroExt8(value), zeroExt8(value)) 250 static bool isUnsigned(RelationalCondition cond) 251 { 252 switch (cond) { 253 case Equal: 254 case NotEqual: 255 case Above: 256 case AboveOrEqual: 257 case Below: 258 case BelowOrEqual: 259 return true; 260 default: 261 return false; 197 262 } 198 263 } -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
r192008 r192072 1472 1472 { 1473 1473 generateTest32(address, mask); 1474 set32(x86Condition(cond), dest); 1475 } 1476 1477 void test32(ResultCondition cond, RegisterID reg, RegisterID mask, RegisterID dest) 1478 { 1479 m_assembler.testl_rr(reg, mask); 1474 1480 set32(x86Condition(cond), dest); 1475 1481 } -
trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp
r191993 r192072 58 58 } // anonymous namespace 59 59 60 CheckSpecial::Key::Key(const Inst& inst) 61 { 62 m_opcode = inst.opcode; 63 m_numArgs = inst.args.size(); 64 } 65 66 void CheckSpecial::Key::dump(PrintStream& out) const 67 { 68 out.print(m_opcode, "(", m_numArgs, ")"); 69 } 70 60 71 CheckSpecial::CheckSpecial(Air::Opcode opcode, unsigned numArgs) 61 72 : m_checkOpcode(opcode) … … 63 74 { 64 75 ASSERT(isTerminal(opcode)); 76 } 77 78 CheckSpecial::CheckSpecial(const CheckSpecial::Key& key) 79 : CheckSpecial(key.opcode(), key.numArgs()) 80 { 65 81 } 66 82 -
trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h
r191705 r192072 31 31 #include "AirOpcode.h" 32 32 #include "B3StackmapSpecial.h" 33 #include <wtf/HashMap.h> 33 34 34 35 namespace JSC { namespace B3 { 36 37 namespace Air { 38 struct Inst; 39 } 35 40 36 41 // We want to lower Check instructions to a branch, but then we want to route that branch to our … … 47 52 class CheckSpecial : public StackmapSpecial { 48 53 public: 54 // Support for hash consing these things. 55 class Key { 56 public: 57 Key() 58 : m_opcode(Air::Nop) 59 , m_numArgs(0) 60 { 61 } 62 63 Key(Air::Opcode opcode, unsigned numArgs) 64 : m_opcode(opcode) 65 , m_numArgs(numArgs) 66 { 67 } 68 69 explicit Key(const Air::Inst&); 70 71 bool operator==(const Key& other) const 72 { 73 return m_opcode == other.m_opcode 74 && m_numArgs == other.m_numArgs; 75 } 76 77 bool operator!=(const Key& other) const 78 { 79 return !(*this == other); 80 } 81 82 explicit operator bool() const { return *this != Key(); } 83 84 Air::Opcode opcode() const { return m_opcode; } 85 unsigned numArgs() const { return m_numArgs; } 86 87 void dump(PrintStream& out) const; 88 89 Key(WTF::HashTableDeletedValueType) 90 : m_opcode(Air::Nop) 91 , m_numArgs(1) 92 { 93 } 94 95 bool isHashTableDeletedValue() const 96 { 97 return *this == Key(WTF::HashTableDeletedValue); 98 } 99 100 unsigned hash() const 101 { 102 // Seriously, we don't need to be smart here. It just doesn't matter. 103 return m_opcode + m_numArgs; 104 } 105 106 private: 107 Air::Opcode m_opcode; 108 unsigned m_numArgs; 109 }; 110 49 111 CheckSpecial(Air::Opcode, unsigned numArgs); 112 CheckSpecial(const Key&); 50 113 ~CheckSpecial(); 51 114 … … 71 134 }; 72 135 136 struct CheckSpecialKeyHash { 137 static unsigned hash(const CheckSpecial::Key& key) { return key.hash(); } 138 static bool equal(const CheckSpecial::Key& a, const CheckSpecial::Key& b) { return a == b; } 139 static const bool safeToCompareToEmptyOrDeleted = true; 140 }; 141 73 142 } } // namespace JSC::B3 143 144 namespace WTF { 145 146 template<typename T> struct DefaultHash; 147 template<> struct DefaultHash<JSC::B3::CheckSpecial::Key> { 148 typedef JSC::B3::CheckSpecialKeyHash Hash; 149 }; 150 151 template<typename T> struct HashTraits; 152 template<> struct HashTraits<JSC::B3::CheckSpecial::Key> : SimpleClassHashTraits<JSC::B3::CheckSpecial::Key> { 153 // I don't want to think about this very hard, it's not worth it. I'm a be conservative. 154 static const bool emptyValueIsZero = false; 155 }; 156 157 } // namespace WTF 74 158 75 159 #endif // ENABLE(B3_JIT) -
trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp
r192051 r192072 104 104 } 105 105 106 Value* Const32Value::equalConstant(Procedure& proc,Value* other) const106 TriState Const32Value::equalConstant(Value* other) const 107 107 { 108 108 if (!other->hasInt32()) 109 return nullptr;110 return proc.add<Const32Value>(origin(),m_value == other->asInt32());109 return MixedTriState; 110 return triState(m_value == other->asInt32()); 111 111 } 112 112 113 Value* Const32Value::notEqualConstant(Procedure& proc,Value* other) const113 TriState Const32Value::notEqualConstant(Value* other) const 114 114 { 115 115 if (!other->hasInt32()) 116 return nullptr; 117 return proc.add<Const32Value>(origin(), m_value != other->asInt32()); 116 return MixedTriState; 117 return triState(m_value != other->asInt32()); 118 } 119 120 TriState Const32Value::lessThanConstant(Value* other) const 121 { 122 if (!other->hasInt32()) 123 return MixedTriState; 124 return triState(m_value < other->asInt32()); 125 } 126 127 TriState Const32Value::greaterThanConstant(Value* other) const 128 { 129 if (!other->hasInt32()) 130 return MixedTriState; 131 return triState(m_value > other->asInt32()); 132 } 133 134 TriState Const32Value::lessEqualConstant(Value* other) const 135 { 136 if (!other->hasInt32()) 137 return MixedTriState; 138 return triState(m_value <= other->asInt32()); 139 } 140 141 TriState Const32Value::greaterEqualConstant(Value* other) const 142 { 143 if (!other->hasInt32()) 144 return MixedTriState; 145 return triState(m_value >= other->asInt32()); 146 } 147 148 TriState Const32Value::aboveConstant(Value* other) const 149 { 150 if (!other->hasInt32()) 151 return MixedTriState; 152 return triState(static_cast<uint32_t>(m_value) > static_cast<uint32_t>(other->asInt32())); 153 } 154 155 TriState Const32Value::belowConstant(Value* other) const 156 { 157 if (!other->hasInt32()) 158 return MixedTriState; 159 return triState(static_cast<uint32_t>(m_value) < static_cast<uint32_t>(other->asInt32())); 160 } 161 162 TriState Const32Value::aboveEqualConstant(Value* other) const 163 { 164 if (!other->hasInt32()) 165 return MixedTriState; 166 return triState(static_cast<uint32_t>(m_value) >= static_cast<uint32_t>(other->asInt32())); 167 } 168 169 TriState Const32Value::belowEqualConstant(Value* other) const 170 { 171 if (!other->hasInt32()) 172 return MixedTriState; 173 return triState(static_cast<uint32_t>(m_value) <= static_cast<uint32_t>(other->asInt32())); 118 174 } 119 175 -
trunk/Source/JavaScriptCore/b3/B3Const32Value.h
r192051 r192072 51 51 Value* sShrConstant(Procedure&, Value* other) const override; 52 52 Value* zShrConstant(Procedure&, Value* other) const override; 53 Value* equalConstant(Procedure&, Value* other) const override; 54 Value* notEqualConstant(Procedure&, Value* other) const override; 53 54 TriState equalConstant(Value* other) const override; 55 TriState notEqualConstant(Value* other) const override; 56 TriState lessThanConstant(Value* other) const override; 57 TriState greaterThanConstant(Value* other) const override; 58 TriState lessEqualConstant(Value* other) const override; 59 TriState greaterEqualConstant(Value* other) const override; 60 TriState aboveConstant(Value* other) const override; 61 TriState belowConstant(Value* other) const override; 62 TriState aboveEqualConstant(Value* other) const override; 63 TriState belowEqualConstant(Value* other) const override; 55 64 56 65 protected: -
trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp
r192051 r192072 104 104 } 105 105 106 Value* Const64Value::equalConstant(Procedure& proc,Value* other) const106 TriState Const64Value::equalConstant(Value* other) const 107 107 { 108 108 if (!other->hasInt64()) 109 return nullptr;110 return proc.add<Const32Value>(origin(),m_value == other->asInt64());109 return MixedTriState; 110 return triState(m_value == other->asInt64()); 111 111 } 112 112 113 Value* Const64Value::notEqualConstant(Procedure& proc,Value* other) const113 TriState Const64Value::notEqualConstant(Value* other) const 114 114 { 115 115 if (!other->hasInt64()) 116 return nullptr; 117 return proc.add<Const32Value>(origin(), m_value != other->asInt64()); 116 return MixedTriState; 117 return triState(m_value != other->asInt64()); 118 } 119 120 TriState Const64Value::lessThanConstant(Value* other) const 121 { 122 if (!other->hasInt64()) 123 return MixedTriState; 124 return triState(m_value < other->asInt64()); 125 } 126 127 TriState Const64Value::greaterThanConstant(Value* other) const 128 { 129 if (!other->hasInt64()) 130 return MixedTriState; 131 return triState(m_value > other->asInt64()); 132 } 133 134 TriState Const64Value::lessEqualConstant(Value* other) const 135 { 136 if (!other->hasInt64()) 137 return MixedTriState; 138 return triState(m_value <= other->asInt64()); 139 } 140 141 TriState Const64Value::greaterEqualConstant(Value* other) const 142 { 143 if (!other->hasInt64()) 144 return MixedTriState; 145 return triState(m_value >= other->asInt64()); 146 } 147 148 TriState Const64Value::aboveConstant(Value* other) const 149 { 150 if (!other->hasInt64()) 151 return MixedTriState; 152 return triState(static_cast<uint64_t>(m_value) > static_cast<uint64_t>(other->asInt64())); 153 } 154 155 TriState Const64Value::belowConstant(Value* other) const 156 { 157 if (!other->hasInt64()) 158 return MixedTriState; 159 return triState(static_cast<uint64_t>(m_value) < static_cast<uint64_t>(other->asInt64())); 160 } 161 162 TriState Const64Value::aboveEqualConstant(Value* other) const 163 { 164 if (!other->hasInt64()) 165 return MixedTriState; 166 return triState(static_cast<uint64_t>(m_value) >= static_cast<uint64_t>(other->asInt64())); 167 } 168 169 TriState Const64Value::belowEqualConstant(Value* other) const 170 { 171 if (!other->hasInt64()) 172 return MixedTriState; 173 return triState(static_cast<uint64_t>(m_value) <= static_cast<uint64_t>(other->asInt64())); 118 174 } 119 175 -
trunk/Source/JavaScriptCore/b3/B3Const64Value.h
r192051 r192072 51 51 Value* sShrConstant(Procedure&, Value* other) const override; 52 52 Value* zShrConstant(Procedure&, Value* other) const override; 53 Value* equalConstant(Procedure&, Value* other) const override; 54 Value* notEqualConstant(Procedure&, Value* other) const override; 53 54 TriState equalConstant(Value* other) const override; 55 TriState notEqualConstant(Value* other) const override; 56 TriState lessThanConstant(Value* other) const override; 57 TriState greaterThanConstant(Value* other) const override; 58 TriState lessEqualConstant(Value* other) const override; 59 TriState greaterEqualConstant(Value* other) const override; 60 TriState aboveConstant(Value* other) const override; 61 TriState belowConstant(Value* other) const override; 62 TriState aboveEqualConstant(Value* other) const override; 63 TriState belowEqualConstant(Value* other) const override; 55 64 56 65 protected: -
trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp
r191993 r192072 62 62 } 63 63 64 Value* ConstDoubleValue::equalConstant(Procedure& proc,Value* other) const64 TriState ConstDoubleValue::equalConstant(Value* other) const 65 65 { 66 66 if (!other->hasDouble()) 67 return nullptr;68 return proc.add<Const32Value>(origin(),m_value == other->asDouble());67 return MixedTriState; 68 return triState(m_value == other->asDouble()); 69 69 } 70 70 71 Value* ConstDoubleValue::notEqualConstant(Procedure& proc,Value* other) const71 TriState ConstDoubleValue::notEqualConstant(Value* other) const 72 72 { 73 73 if (!other->hasDouble()) 74 return nullptr; 75 return proc.add<Const32Value>(origin(), m_value != other->asDouble()); 74 return MixedTriState; 75 return triState(m_value != other->asDouble()); 76 } 77 78 TriState ConstDoubleValue::lessThanConstant(Value* other) const 79 { 80 if (!other->hasDouble()) 81 return MixedTriState; 82 return triState(m_value < other->asDouble()); 83 } 84 85 TriState ConstDoubleValue::greaterThanConstant(Value* other) const 86 { 87 if (!other->hasDouble()) 88 return MixedTriState; 89 return triState(m_value > other->asDouble()); 90 } 91 92 TriState ConstDoubleValue::lessEqualConstant(Value* other) const 93 { 94 if (!other->hasDouble()) 95 return MixedTriState; 96 return triState(m_value <= other->asDouble()); 97 } 98 99 TriState ConstDoubleValue::greaterEqualConstant(Value* other) const 100 { 101 if (!other->hasDouble()) 102 return MixedTriState; 103 return triState(m_value >= other->asDouble()); 76 104 } 77 105 -
trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h
r191994 r192072 45 45 Value* addConstant(Procedure& proc, Value* other) const override; 46 46 Value* subConstant(Procedure& proc, Value* other) const override; 47 Value* equalConstant(Procedure& proc, Value* other) const override; 48 Value* notEqualConstant(Procedure& proc, Value* other) const override; 47 48 TriState equalConstant(Value* other) const override; 49 TriState notEqualConstant(Value* other) const override; 50 TriState lessThanConstant(Value* other) const override; 51 TriState greaterThanConstant(Value* other) const override; 52 TriState lessEqualConstant(Value* other) const override; 53 TriState greaterEqualConstant(Value* other) const override; 49 54 50 55 protected: -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r192051 r192072 58 58 namespace { 59 59 60 const bool verbose = false; 61 60 62 class LowerToAir { 61 63 public: … … 87 89 // Reset some state. 88 90 insts.resize(0); 91 92 if (verbose) 93 dataLog("Lowering Block ", *block, ":\n"); 89 94 90 95 // Process blocks in reverse order so we see uses before defs. That's what allows us … … 96 101 continue; 97 102 insts.append(Vector<Inst>()); 103 if (verbose) 104 dataLog("Lowering ", deepDump(currentValue), ":\n"); 98 105 bool result = runLoweringMatcher(currentValue, *this); 99 106 if (!result) { 100 107 dataLog("FATAL: could not lower ", deepDump(currentValue), "\n"); 101 108 RELEASE_ASSERT_NOT_REACHED(); 109 } 110 if (verbose) { 111 for (Inst& inst : insts.last()) 112 dataLog(" ", inst, "\n"); 102 113 } 103 114 } … … 163 174 } 164 175 176 class ArgPromise { 177 public: 178 ArgPromise() { } 179 180 ArgPromise(const Arg& arg, Value* valueToLock = nullptr) 181 : m_arg(arg) 182 , m_value(valueToLock) 183 { 184 } 185 186 static ArgPromise tmp(Value* value) 187 { 188 ArgPromise result; 189 result.m_value = value; 190 return result; 191 } 192 193 explicit operator bool() const { return m_arg || m_value; } 194 195 Arg::Kind kind() const 196 { 197 if (!m_arg && m_value) 198 return Arg::Tmp; 199 return m_arg.kind(); 200 } 201 202 const Arg& peek() const 203 { 204 return m_arg; 205 } 206 207 Arg consume(LowerToAir& lower) const 208 { 209 if (!m_arg && m_value) 210 return lower.tmp(m_value); 211 if (m_value) 212 lower.commitInternal(m_value); 213 return m_arg; 214 } 215 216 private: 217 // Three forms: 218 // Everything null: invalid. 219 // Arg non-null, value null: just use the arg, nothing special. 220 // Arg null, value non-null: it's a tmp, pin it when necessary. 221 // Arg non-null, value non-null: use the arg, lock the value. 222 Arg m_arg; 223 Value* m_value; 224 }; 225 226 // Consider using tmpPromise() in cases where you aren't sure that you want to pin the value yet. 227 // Here are three canonical ways of using tmp() and tmpPromise(): 228 // 229 // Idiom #1: You know that you want a tmp() and you know that it will be valid for the 230 // instruction you're emitting. 231 // 232 // append(Foo, tmp(bar)); 233 // 234 // Idiom #2: You don't know if you want to use a tmp() because you haven't determined if the 235 // instruction will accept it, so you query first. Note that the call to tmp() happens only after 236 // you are sure that you will use it. 237 // 238 // if (isValidForm(Foo, Arg::Tmp)) 239 // append(Foo, tmp(bar)) 240 // 241 // Idiom #3: Same as Idiom #2, but using tmpPromise. Notice that this calls consume() only after 242 // it's sure it will use the tmp. That's deliberate. 243 // 244 // ArgPromise promise = tmpPromise(bar); 245 // if (isValidForm(Foo, promise.kind())) 246 // append(Foo, promise.consume(*this)) 247 // 248 // In both idiom #2 and idiom #3, we don't pin the value to a temporary except when we actually 249 // emit the instruction. Both tmp() and tmpPromise().consume(*this) will pin it. Pinning means 250 // that we will henceforth require that the value of 'bar' is generated as a separate 251 // instruction. We don't want to pin the value to a temporary if we might change our minds, and 252 // pass an address operand representing 'bar' to Foo instead. 253 // 254 // Because tmp() pins, the following is not an idiom you should use: 255 // 256 // Tmp tmp = this->tmp(bar); 257 // if (isValidForm(Foo, tmp.kind())) 258 // append(Foo, tmp); 259 // 260 // That's because if isValidForm() returns false, you will have already pinned the 'bar' to a 261 // temporary. You might later want to try to do something like loadPromise(), and that will fail. 262 // This arises in operations that have both a Addr,Tmp and Tmp,Addr forms. The following code 263 // seems right, but will actually fail to ever match the Tmp,Addr form because by then, the right 264 // value is already pinned. 265 // 266 // auto tryThings = [this] (const Arg& left, const Arg& right) { 267 // if (isValidForm(Foo, left.kind(), right.kind())) 268 // return Inst(Foo, currentValue, left, right); 269 // return Inst(); 270 // }; 271 // if (Inst result = tryThings(loadAddr(left), tmp(right))) 272 // return result; 273 // if (Inst result = tryThings(tmp(left), loadAddr(right))) // this never succeeds. 274 // return result; 275 // return Inst(Foo, currentValue, tmp(left), tmp(right)); 276 // 277 // If you imagine that loadAddr(value) is just loadPromise(value).consume(*this), then this code 278 // will run correctly - it will generate OK code - but the second form is never matched. 279 // loadAddr(right) will never succeed because it will observe that 'right' is already pinned. 280 // Of course, it's exactly because of the risky nature of such code that we don't have a 281 // loadAddr() helper and require you to balance ArgPromise's in code like this. Such code will 282 // work fine if written as: 283 // 284 // auto tryThings = [this] (const ArgPromise& left, const ArgPromise& right) { 285 // if (isValidForm(Foo, left.kind(), right.kind())) 286 // return Inst(Foo, currentValue, left.consume(*this), right.consume(*this)); 287 // return Inst(); 288 // }; 289 // if (Inst result = tryThings(loadPromise(left), tmpPromise(right))) 290 // return result; 291 // if (Inst result = tryThings(tmpPromise(left), loadPromise(right))) 292 // return result; 293 // return Inst(Foo, currentValue, tmp(left), tmp(right)); 294 // 295 // Notice that we did use tmp in the fall-back case at the end, because by then, we know for sure 296 // that we want a tmp. But using tmpPromise in the tryThings() calls ensures that doing so 297 // doesn't prevent us from trying loadPromise on the same value. 165 298 Tmp tmp(Value* value) 166 299 { … … 169 302 while (shouldCopyPropagate(value)) 170 303 value = value->child(0); 171 tmp = code.newTmp(isInt(value->type()) ? Arg::GP : Arg::FP); 172 valueToTmp[value] = tmp; 304 Tmp& realTmp = valueToTmp[value]; 305 if (!realTmp) 306 realTmp = code.newTmp(Arg::typeForB3Type(value->type())); 307 tmp = realTmp; 173 308 } 174 309 return tmp; 310 } 311 312 ArgPromise tmpPromise(Value* value) 313 { 314 return ArgPromise::tmp(value); 175 315 } 176 316 … … 254 394 } 255 395 256 Arg loadAddr(Value* loadValue)257 { 258 if (loadValue->opcode() != Load)396 ArgPromise loadPromise(Value* loadValue, B3::Opcode loadOpcode) 397 { 398 if (loadValue->opcode() != loadOpcode) 259 399 return Arg(); 260 400 if (!canBeInternal(loadValue)) … … 262 402 if (crossesInterference(loadValue)) 263 403 return Arg(); 264 return addr(loadValue); 404 return ArgPromise(addr(loadValue), loadValue); 405 } 406 407 ArgPromise loadPromise(Value* loadValue) 408 { 409 return loadPromise(loadValue, Load); 265 410 } 266 411 … … 341 486 342 487 if (commutativity == Commutative) { 343 Arg leftAddr = loadAddr(left);488 ArgPromise leftAddr = loadPromise(left); 344 489 if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) { 345 commitInternal(left);346 490 append(relaxedMoveForType(currentValue->type()), tmp(right), result); 347 append(opcode, leftAddr , result);491 append(opcode, leftAddr.consume(*this), result); 348 492 return; 349 493 } 350 494 } 351 495 352 Arg rightAddr = loadAddr(right);496 ArgPromise rightAddr = loadPromise(right); 353 497 if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) { 354 commitInternal(right);355 498 append(relaxedMoveForType(currentValue->type()), tmp(left), result); 356 append(opcode, rightAddr , result);499 append(opcode, rightAddr.consume(*this), result); 357 500 return; 358 501 } … … 379 522 ASSERT(storeAddr); 380 523 381 if (loadAddr(value) != storeAddr) 382 return false; 383 384 commitInternal(value); 524 ArgPromise loadPromise = this->loadPromise(value); 525 if (loadPromise.peek() != storeAddr) 526 return false; 527 528 loadPromise.consume(*this); 385 529 append(opcode, storeAddr); 386 530 return true; … … 393 537 ASSERT(storeAddr); 394 538 395 Value* loadValue; 396 Value* otherValue; 397 if (loadAddr(left) == storeAddr) { 398 loadValue = left; 539 ArgPromise loadPromise; 540 Value* otherValue = nullptr; 541 542 loadPromise = this->loadPromise(left); 543 if (loadPromise.peek() == storeAddr) 399 544 otherValue = right; 400 } else if (commutativity == Commutative && loadAddr(right) == storeAddr) { 401 loadValue = right; 402 otherValue = left; 403 } else 545 else if (commutativity == Commutative) { 546 loadPromise = this->loadPromise(right); 547 if (loadPromise.peek() == storeAddr) 548 otherValue = left; 549 } 550 551 if (!otherValue) 404 552 return false; 405 553 406 554 if (isValidForm(opcode, Arg::Imm, storeAddr.kind()) && imm(otherValue)) { 407 commitInternal(loadValue);555 loadPromise.consume(*this); 408 556 append(opcode, imm(otherValue), storeAddr); 409 557 return true; … … 413 561 return false; 414 562 415 commitInternal(loadValue);563 loadPromise.consume(*this); 416 564 append(opcode, tmp(otherValue), storeAddr); 417 565 return true; … … 623 771 AddressSelector addressSelector; 624 772 773 // Create an Inst to do the comparison specified by the given value. 774 template<typename CompareFunctor, typename TestFunctor, typename CompareDoubleFunctor> 775 Inst createGenericCompare( 776 Value* value, 777 const CompareFunctor& compare, // Signature: (Arg::Width, Arg relCond, Arg, Arg) -> Inst 778 const TestFunctor& test, // Signature: (Arg::Width, Arg resCond, Arg, Arg) -> Inst 779 const CompareDoubleFunctor& compareDouble, // Signature: (Arg doubleCond, Arg, Arg) -> Inst 780 bool inverted = false) 781 { 782 // Chew through any negations. It's not strictly necessary for this to be a loop, but we like 783 // to follow the rule that the instruction selector reduces strength whenever it doesn't 784 // require making things more complicated. 785 for (;;) { 786 if (!canBeInternal(value) && value != currentValue) 787 break; 788 bool shouldInvert = 789 (value->opcode() == BitXor && value->child(1)->isInt(1) && value->child(0)->returnsBool()) 790 || (value->opcode() == Equal && value->child(1)->isInt(0)); 791 if (!shouldInvert) 792 break; 793 value = value->child(0); 794 inverted = !inverted; 795 commitInternal(value); 796 } 797 798 auto createRelCond = [&] ( 799 MacroAssembler::RelationalCondition relationalCondition, 800 MacroAssembler::DoubleCondition doubleCondition) { 801 Arg relCond = Arg::relCond(relationalCondition).inverted(inverted); 802 Arg doubleCond = Arg::doubleCond(doubleCondition).inverted(inverted); 803 Value* left = value->child(0); 804 Value* right = value->child(1); 805 806 if (isInt(value->child(0)->type())) { 807 Arg leftImm = imm(left); 808 Arg rightImm = imm(right); 809 810 auto tryCompare = [&] ( 811 Arg::Width width, const ArgPromise& left, const ArgPromise& right) -> Inst { 812 if (Inst result = compare(width, relCond, left, right)) 813 return result; 814 if (Inst result = compare(width, relCond.flipped(), right, left)) 815 return result; 816 return Inst(); 817 }; 818 819 auto tryCompareLoadImm = [&] ( 820 Arg::Width width, B3::Opcode loadOpcode, Arg::Signedness signedness) -> Inst { 821 if (rightImm && rightImm.isRepresentableAs(width, signedness)) { 822 if (Inst result = tryCompare(width, loadPromise(left, loadOpcode), rightImm)) { 823 commitInternal(left); 824 return result; 825 } 826 } 827 if (leftImm && leftImm.isRepresentableAs(width, signedness)) { 828 if (Inst result = tryCompare(width, leftImm, loadPromise(right, loadOpcode))) { 829 commitInternal(right); 830 return result; 831 } 832 } 833 return Inst(); 834 }; 835 836 // First handle compares that involve fewer bits than B3's type system supports. 837 // This is pretty important. For example, we want this to be a single instruction: 838 // 839 // @1 = Load8S(...) 840 // @2 = Const32(...) 841 // @3 = LessThan(@1, @2) 842 // Branch(@3) 843 844 if (relCond.isSignedCond()) { 845 if (Inst result = tryCompareLoadImm(Arg::Width8, Load8S, Arg::Signed)) 846 return result; 847 } 848 849 if (relCond.isUnsignedCond()) { 850 if (Inst result = tryCompareLoadImm(Arg::Width8, Load8Z, Arg::Unsigned)) 851 return result; 852 } 853 854 if (relCond.isSignedCond()) { 855 if (Inst result = tryCompareLoadImm(Arg::Width16, Load16S, Arg::Signed)) 856 return result; 857 } 858 859 if (relCond.isUnsignedCond()) { 860 if (Inst result = tryCompareLoadImm(Arg::Width16, Load16Z, Arg::Unsigned)) 861 return result; 862 } 863 864 // Now handle compares that involve a load and an immediate. 865 866 Arg::Width width = Arg::widthForB3Type(value->child(0)->type()); 867 if (Inst result = tryCompareLoadImm(width, Load, Arg::Signed)) 868 return result; 869 870 // Now handle compares that involve a load. It's not obvious that it's better to 871 // handle this before the immediate cases or not. Probably doesn't matter. 872 873 if (Inst result = tryCompare(width, loadPromise(left), tmpPromise(right))) { 874 commitInternal(left); 875 return result; 876 } 877 878 if (Inst result = tryCompare(width, tmpPromise(left), loadPromise(right))) { 879 commitInternal(right); 880 return result; 881 } 882 883 // Now handle compares that involve an immediate and a tmp. 884 885 if (leftImm && leftImm.isRepresentableAs<int32_t>()) { 886 if (Inst result = tryCompare(width, leftImm, tmpPromise(right))) 887 return result; 888 } 889 890 if (rightImm && rightImm.isRepresentableAs<int32_t>()) { 891 if (Inst result = tryCompare(width, tmpPromise(left), rightImm)) 892 return result; 893 } 894 895 // Finally, handle comparison between tmps. 896 return tryCompare(width, tmpPromise(left), tmpPromise(right)); 897 } 898 899 // Double comparisons can't really do anything smart. 900 return compareDouble(doubleCond, tmpPromise(left), tmpPromise(right)); 901 }; 902 903 Arg::Width width = Arg::widthForB3Type(value->type()); 904 Arg resCond = Arg::resCond(MacroAssembler::NonZero).inverted(inverted); 905 906 auto attemptFused = [&] () -> Inst { 907 switch (value->opcode()) { 908 case NotEqual: 909 return createRelCond(MacroAssembler::NotEqual, MacroAssembler::DoubleNotEqualOrUnordered); 910 case Equal: 911 return createRelCond(MacroAssembler::Equal, MacroAssembler::DoubleEqual); 912 case LessThan: 913 return createRelCond(MacroAssembler::LessThan, MacroAssembler::DoubleLessThan); 914 case GreaterThan: 915 return createRelCond(MacroAssembler::GreaterThan, MacroAssembler::DoubleGreaterThan); 916 case LessEqual: 917 return createRelCond(MacroAssembler::LessThanOrEqual, MacroAssembler::DoubleLessThanOrEqual); 918 case GreaterEqual: 919 return createRelCond(MacroAssembler::GreaterThanOrEqual, MacroAssembler::DoubleGreaterThanOrEqual); 920 case Above: 921 // We use a bogus double condition because these integer comparisons won't got down that 922 // path anyway. 923 return createRelCond(MacroAssembler::Above, MacroAssembler::DoubleEqual); 924 case Below: 925 return createRelCond(MacroAssembler::Below, MacroAssembler::DoubleEqual); 926 case AboveEqual: 927 return createRelCond(MacroAssembler::AboveOrEqual, MacroAssembler::DoubleEqual); 928 case BelowEqual: 929 return createRelCond(MacroAssembler::BelowOrEqual, MacroAssembler::DoubleEqual); 930 case BitAnd: { 931 Value* left = value->child(0); 932 Value* right = value->child(1); 933 934 Arg leftImm = imm(left); 935 Arg rightImm = imm(right); 936 937 auto tryTest = [&] ( 938 Arg::Width width, const ArgPromise& left, const ArgPromise& right) -> Inst { 939 if (Inst result = test(width, resCond, left, right)) 940 return result; 941 if (Inst result = test(width, resCond, right, left)) 942 return result; 943 return Inst(); 944 }; 945 946 auto tryTestLoadImm = [&] (Arg::Width width, B3::Opcode loadOpcode) -> Inst { 947 if (rightImm && rightImm.isRepresentableAs(width, Arg::Unsigned)) { 948 if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm)) { 949 commitInternal(left); 950 return result; 951 } 952 } 953 if (leftImm && leftImm.isRepresentableAs(width, Arg::Unsigned)) { 954 if (Inst result = tryTest(width, leftImm, loadPromise(right, loadOpcode))) { 955 commitInternal(right); 956 return result; 957 } 958 } 959 return Inst(); 960 }; 961 962 // First handle test's that involve fewer bits than B3's type system supports. 963 964 if (Inst result = tryTestLoadImm(Arg::Width8, Load8Z)) 965 return result; 966 967 if (Inst result = tryTestLoadImm(Arg::Width8, Load8S)) 968 return result; 969 970 if (Inst result = tryTestLoadImm(Arg::Width16, Load16Z)) 971 return result; 972 973 if (Inst result = tryTestLoadImm(Arg::Width16, Load16S)) 974 return result; 975 976 // Now handle test's that involve a load and an immediate. Note that immediates are 977 // 32-bit, and we want zero-extension. Hence, the immediate form is compiled as a 978 // 32-bit test. Note that this spits on the grave of inferior endians, such as the 979 // big one. 980 981 if (Inst result = tryTestLoadImm(Arg::Width32, Load)) 982 return result; 983 984 // Now handle test's that involve a load. 985 986 Arg::Width width = Arg::widthForB3Type(value->child(0)->type()); 987 if (Inst result = tryTest(width, loadPromise(left), tmpPromise(right))) { 988 commitInternal(left); 989 return result; 990 } 991 992 if (Inst result = tryTest(width, tmpPromise(left), loadPromise(right))) { 993 commitInternal(right); 994 return result; 995 } 996 997 // Now handle test's that involve an immediate and a tmp. 998 999 if (leftImm && leftImm.isRepresentableAs<uint32_t>()) { 1000 if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right))) 1001 return result; 1002 } 1003 1004 if (rightImm && rightImm.isRepresentableAs<uint32_t>()) { 1005 if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm)) 1006 return result; 1007 } 1008 1009 // Finally, just do tmp's. 1010 return tryTest(width, tmpPromise(left), tmpPromise(right)); 1011 } 1012 default: 1013 return Inst(); 1014 } 1015 }; 1016 1017 if (canBeInternal(value) || value == currentValue) { 1018 if (Inst result = attemptFused()) { 1019 commitInternal(value); 1020 return result; 1021 } 1022 } 1023 1024 if (Inst result = test(width, resCond, tmpPromise(value), Arg::imm(-1))) 1025 return result; 1026 1027 // Sometimes this is the only form of test available. We prefer not to use this because 1028 // it's less canonical. 1029 return test(width, resCond, tmpPromise(value), tmpPromise(value)); 1030 } 1031 1032 Inst createBranch(Value* value, bool inverted = false) 1033 { 1034 return createGenericCompare( 1035 value, 1036 [this] ( 1037 Arg::Width width, const Arg& relCond, 1038 const ArgPromise& left, const ArgPromise& right) -> Inst { 1039 switch (width) { 1040 case Arg::Width8: 1041 if (isValidForm(Branch8, Arg::RelCond, left.kind(), right.kind())) { 1042 return Inst( 1043 Branch8, currentValue, relCond, 1044 left.consume(*this), right.consume(*this)); 1045 } 1046 return Inst(); 1047 case Arg::Width16: 1048 return Inst(); 1049 case Arg::Width32: 1050 if (isValidForm(Branch32, Arg::RelCond, left.kind(), right.kind())) { 1051 return Inst( 1052 Branch32, currentValue, relCond, 1053 left.consume(*this), right.consume(*this)); 1054 } 1055 return Inst(); 1056 case Arg::Width64: 1057 if (isValidForm(Branch64, Arg::RelCond, left.kind(), right.kind())) { 1058 return Inst( 1059 Branch64, currentValue, relCond, 1060 left.consume(*this), right.consume(*this)); 1061 } 1062 return Inst(); 1063 } 1064 }, 1065 [this] ( 1066 Arg::Width width, const Arg& resCond, 1067 const ArgPromise& left, const ArgPromise& right) -> Inst { 1068 switch (width) { 1069 case Arg::Width8: 1070 if (isValidForm(BranchTest8, Arg::ResCond, left.kind(), right.kind())) { 1071 return Inst( 1072 BranchTest8, currentValue, resCond, 1073 left.consume(*this), right.consume(*this)); 1074 } 1075 return Inst(); 1076 case Arg::Width16: 1077 return Inst(); 1078 case Arg::Width32: 1079 if (isValidForm(BranchTest32, Arg::ResCond, left.kind(), right.kind())) { 1080 return Inst( 1081 BranchTest32, currentValue, resCond, 1082 left.consume(*this), right.consume(*this)); 1083 } 1084 return Inst(); 1085 case Arg::Width64: 1086 if (isValidForm(BranchTest64, Arg::ResCond, left.kind(), right.kind())) { 1087 return Inst( 1088 BranchTest64, currentValue, resCond, 1089 left.consume(*this), right.consume(*this)); 1090 } 1091 return Inst(); 1092 } 1093 }, 1094 [this] (Arg doubleCond, const ArgPromise& left, const ArgPromise& right) -> Inst { 1095 if (isValidForm(BranchDouble, Arg::DoubleCond, left.kind(), right.kind())) { 1096 return Inst( 1097 BranchDouble, currentValue, doubleCond, 1098 left.consume(*this), right.consume(*this)); 1099 } 1100 return Inst(); 1101 }, 1102 inverted); 1103 } 1104 1105 Inst createCompare(Value* value, bool inverted = false) 1106 { 1107 return createGenericCompare( 1108 value, 1109 [this] ( 1110 Arg::Width width, const Arg& relCond, 1111 const ArgPromise& left, const ArgPromise& right) -> Inst { 1112 switch (width) { 1113 case Arg::Width8: 1114 case Arg::Width16: 1115 return Inst(); 1116 case Arg::Width32: 1117 if (isValidForm(Compare32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) { 1118 return Inst( 1119 Compare32, currentValue, relCond, 1120 left.consume(*this), right.consume(*this), tmp(currentValue)); 1121 } 1122 return Inst(); 1123 case Arg::Width64: 1124 if (isValidForm(Compare64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) { 1125 return Inst( 1126 Compare64, currentValue, relCond, 1127 left.consume(*this), right.consume(*this), tmp(currentValue)); 1128 } 1129 return Inst(); 1130 } 1131 }, 1132 [this] ( 1133 Arg::Width width, const Arg& resCond, 1134 const ArgPromise& left, const ArgPromise& right) -> Inst { 1135 switch (width) { 1136 case Arg::Width8: 1137 case Arg::Width16: 1138 return Inst(); 1139 case Arg::Width32: 1140 if (isValidForm(Test32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) { 1141 return Inst( 1142 Test32, currentValue, resCond, 1143 left.consume(*this), right.consume(*this), tmp(currentValue)); 1144 } 1145 return Inst(); 1146 case Arg::Width64: 1147 if (isValidForm(Test64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) { 1148 return Inst( 1149 Test64, currentValue, resCond, 1150 left.consume(*this), right.consume(*this), tmp(currentValue)); 1151 } 1152 return Inst(); 1153 } 1154 }, 1155 [this] (const Arg&, const ArgPromise&, const ArgPromise&) -> Inst { 1156 // FIXME: Implement this. 1157 // https://bugs.webkit.org/show_bug.cgi?id=150903 1158 return Inst(); 1159 }, 1160 inverted); 1161 } 1162 625 1163 // Below is the code for a lowering selector, so that we can pass *this to runLoweringMatcher. 626 1164 // This will match complex multi-value expressions, but only if there is no sharing. For example, … … 671 1209 moveForType(currentValue->type()), 672 1210 effectiveAddr(address, currentValue), tmp(currentValue)); 1211 return true; 1212 } 1213 1214 bool tryLoad8S(Value* address) 1215 { 1216 append(Load8SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue)); 1217 return true; 1218 } 1219 1220 bool tryLoad8Z(Value* address) 1221 { 1222 append(Load8, effectiveAddr(address, currentValue), tmp(currentValue)); 1223 return true; 1224 } 1225 1226 bool tryLoad16S(Value* address) 1227 { 1228 append(Load16SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue)); 1229 return true; 1230 } 1231 1232 bool tryLoad16Z(Value* address) 1233 { 1234 append(Load16, effectiveAddr(address, currentValue), tmp(currentValue)); 673 1235 return true; 674 1236 } … … 887 1449 } 888 1450 1451 bool tryEqual() 1452 { 1453 insts.last().append(createCompare(currentValue)); 1454 return true; 1455 } 1456 1457 bool tryNotEqual() 1458 { 1459 insts.last().append(createCompare(currentValue)); 1460 return true; 1461 } 1462 1463 bool tryLessThan() 1464 { 1465 insts.last().append(createCompare(currentValue)); 1466 return true; 1467 } 1468 1469 bool tryGreaterThan() 1470 { 1471 insts.last().append(createCompare(currentValue)); 1472 return true; 1473 } 1474 1475 bool tryLessEqual() 1476 { 1477 insts.last().append(createCompare(currentValue)); 1478 return true; 1479 } 1480 1481 bool tryGreaterEqual() 1482 { 1483 insts.last().append(createCompare(currentValue)); 1484 return true; 1485 } 1486 1487 bool tryAbove() 1488 { 1489 insts.last().append(createCompare(currentValue)); 1490 return true; 1491 } 1492 1493 bool tryBelow() 1494 { 1495 insts.last().append(createCompare(currentValue)); 1496 return true; 1497 } 1498 1499 bool tryAboveEqual() 1500 { 1501 insts.last().append(createCompare(currentValue)); 1502 return true; 1503 } 1504 1505 bool tryBelowEqual() 1506 { 1507 insts.last().append(createCompare(currentValue)); 1508 return true; 1509 } 1510 889 1511 PatchpointSpecial* patchpointSpecial { nullptr }; 890 1512 bool tryPatchpoint() … … 904 1526 } 905 1527 906 CheckSpecial* checkBranchTest32Special { nullptr }; 907 CheckSpecial* checkBranchTest64Special { nullptr }; 1528 HashMap<CheckSpecial::Key, CheckSpecial*> checkSpecials; 908 1529 bool tryCheck(Value* value) 909 1530 { 910 if (!isInt(value->type())) { 911 // FIXME: Implement double branches. 912 // https://bugs.webkit.org/show_bug.cgi?id=150727 913 return false; 914 } 915 916 CheckSpecial* special; 917 switch (value->type()) { 918 case Int32: 919 special = ensureSpecial(checkBranchTest32Special, BranchTest32, 3); 920 break; 921 case Int64: 922 special = ensureSpecial(checkBranchTest64Special, BranchTest64, 3); 923 break; 924 default: 925 RELEASE_ASSERT_NOT_REACHED(); 926 break; 927 } 1531 Inst branch = createBranch(value); 1532 1533 CheckSpecial::Key key(branch); 1534 auto result = checkSpecials.add(key, nullptr); 1535 Special* special = ensureSpecial(result.iterator->value, key); 928 1536 929 1537 CheckValue* checkValue = currentValue->as<CheckValue>(); 930 1538 931 Inst inst( 932 Patch, checkValue, Arg::special(special), 933 Arg::resCond(MacroAssembler::NonZero), tmp(value), Arg::imm(-1)); 1539 Inst inst(Patch, checkValue, Arg::special(special)); 1540 inst.args.appendVector(branch.args); 934 1541 935 1542 fillStackmap(inst, checkValue, 1); … … 956 1563 bool tryBranch(Value* value) 957 1564 { 958 // FIXME: Implement branch fusion by delegating to a pattern matcher for comparisons. 959 // https://bugs.webkit.org/show_bug.cgi?id=150721 960 961 // In B3 it's possible to branch on any value. The semantics of: 962 // 963 // Branch(value) 964 // 965 // Are guaranteed to be identical to: 966 // 967 // Branch(NotEqual(value, 0)) 968 969 if (!isInt(value->type())) { 970 // FIXME: Implement double branches. 971 // https://bugs.webkit.org/show_bug.cgi?id=150727 972 return false; 973 } 974 975 Air::Opcode opcode; 976 switch (value->type()) { 977 case Int32: 978 opcode = BranchTest32; 979 break; 980 case Int64: 981 opcode = BranchTest64; 982 break; 983 default: 984 RELEASE_ASSERT_NOT_REACHED(); 985 break; 986 } 987 988 Arg resCond = Arg::resCond(MacroAssembler::NonZero); 989 990 Arg addr = loadAddr(value); 991 if (isValidForm(opcode, resCond.kind(), addr.kind(), Arg::Imm)) { 992 commitInternal(value); 993 append(opcode, resCond, addr, Arg::imm(-1)); 994 return true; 995 } 996 997 append(opcode, resCond, tmp(value), Arg::imm(-1)); 1565 insts.last().append(createBranch(value)); 998 1566 return true; 999 1567 } -
trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns
r192051 r192072 31 31 Load = Load(address) 32 32 33 Load8S = Load8S(address) 34 Load8Z = Load8Z(address) 35 Load16S = Load16S(address) 36 Load16Z = Load16Z(address) 37 33 38 Add = Add(left, right) 34 39 Sub = Sub(left, right) … … 58 63 FramePointer = FramePointer() 59 64 65 # These patterns delegate to the comparison matcher. 66 Equal = Equal() 67 NotEqual = NotEqual() 68 LessThan = LessThan() 69 GreaterThan = GreaterThan() 70 LessEqual = LessEqual() 71 GreaterEqual = GreaterEqual() 72 Above = Above() 73 Below = Below() 74 AboveEqual = AboveEqual() 75 BelowEqual = BelowEqual() 76 60 77 Patchpoint = Patchpoint() 61 78 Check = Check(value) -
trunk/Source/JavaScriptCore/b3/B3Opcode.cpp
r191705 r192072 31 31 #include <wtf/PrintStream.h> 32 32 33 namespace JSC { namespace B3 { 34 35 Optional<Opcode> invertedCompare(Opcode opcode, Type type) 36 { 37 switch (opcode) { 38 case Equal: 39 return NotEqual; 40 case NotEqual: 41 return Equal; 42 case LessThan: 43 if (isInt(type)) 44 return GreaterEqual; 45 return Nullopt; 46 case GreaterThan: 47 if (isInt(type)) 48 return LessEqual; 49 return Nullopt; 50 case LessEqual: 51 if (isInt(type)) 52 return GreaterThan; 53 return Nullopt; 54 case GreaterEqual: 55 if (isInt(type)) 56 return LessThan; 57 return Nullopt; 58 case Above: 59 return BelowEqual; 60 case Below: 61 return AboveEqual; 62 case AboveEqual: 63 return Below; 64 case BelowEqual: 65 return Above; 66 default: 67 return Nullopt; 68 } 69 } 70 71 } } // namespace JSC::B3 72 33 73 namespace WTF { 34 74 -
trunk/Source/JavaScriptCore/b3/B3Opcode.h
r192051 r192072 29 29 #if ENABLE(B3_JIT) 30 30 31 #include "B3Type.h" 32 #include <wtf/Optional.h> 31 33 #include <wtf/StdLibExtras.h> 32 34 … … 167 169 168 170 // Check that side-exits. Use the CheckValue class. Like CheckAdd and friends, this has a 169 // stackmap with a generation callback. This takes an Int32argument that this branches on, with171 // stackmap with a generation callback. This takes an int argument that this branches on, with 170 172 // full branch fusion in the instruction selector. A true value jumps to the generator's slow 171 173 // path. … … 179 181 Jump, 180 182 181 // Polymorphic branch, usable with any valuetype. Branches if not equal to zero. Uses the183 // Polymorphic branch, usable with any integer type. Branches if not equal to zero. Uses the 182 184 // ControlValue class, with the 0-index successor being the true successor. 183 185 Branch, … … 206 208 } 207 209 210 Optional<Opcode> invertedCompare(Opcode, Type); 211 208 212 } } // namespace JSC::B3 209 213 -
trunk/Source/JavaScriptCore/b3/B3Procedure.cpp
r191816 r192072 51 51 m_blocks.append(WTF::move(block)); 52 52 return result; 53 } 54 55 Value* Procedure::addIntConstant(Type type, int64_t value) 56 { 57 switch (type) { 58 case Int32: 59 return add<Const32Value>(Origin(), static_cast<int32_t>(value)); 60 case Int64: 61 return add<Const64Value>(Origin(), value); 62 case Double: 63 return add<ConstDoubleValue>(Origin(), static_cast<double>(value)); 64 default: 65 RELEASE_ASSERT_NOT_REACHED(); 66 return nullptr; 67 } 68 } 69 70 Value* Procedure::addBoolConstant(TriState triState) 71 { 72 int32_t value = 0; 73 switch (triState) { 74 case FalseTriState: 75 value = 0; 76 break; 77 case TrueTriState: 78 value = 1; 79 break; 80 case MixedTriState: 81 return nullptr; 82 } 83 84 return addIntConstant(Int32, value); 53 85 } 54 86 -
trunk/Source/JavaScriptCore/b3/B3Procedure.h
r191762 r192072 29 29 #if ENABLE(B3_JIT) 30 30 31 #include "B3Type.h" 31 32 #include "PureNaN.h" 32 33 #include <wtf/Bag.h> … … 34 35 #include <wtf/Noncopyable.h> 35 36 #include <wtf/PrintStream.h> 37 #include <wtf/TriState.h> 36 38 #include <wtf/Vector.h> 37 39 … … 53 55 template<typename ValueType, typename... Arguments> 54 56 ValueType* add(Arguments...); 57 58 Value* addIntConstant(Type, int64_t value); 59 60 // Returns null for MixedTriState. 61 Value* addBoolConstant(TriState); 55 62 56 63 void resetValueOwners(); -
trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp
r192051 r192072 44 44 namespace { 45 45 46 // The goal of this phase is to: 47 // 48 // - Replace operations with less expensive variants. This includes constant folding and classic 49 // strength reductions like turning Mul(x, 1 << k) into Shl(x, k). 50 // 51 // - Reassociate constant operations. For example, Load(Add(x, c)) is turned into Load(x, offset = c) 52 // and Add(Add(x, c), d) is turned into Add(x, c + d). 53 // 54 // - Canonicalize operations. There are some cases where it's not at all obvious which kind of 55 // operation is less expensive, but it's useful for subsequent phases - particularly LowerToAir - 56 // to have only one way of representing things. 57 // 58 // This phase runs to fixpoint. Therefore, the canonicalizations must be designed to be monotonic. 59 // For example, if we had a canonicalization that said that Add(x, -c) should be Sub(x, c) and 60 // another canonicalization that said that Sub(x, d) should be Add(x, -d), then this phase would end 61 // up running forever. We don't want that. 62 // 63 // Therefore, we need to prioritize certain canonical forms over others. Naively, we want strength 64 // reduction to reduce the number of values, and so a form involving fewer total values is more 65 // canonical. But we might break this, for example when reducing strength of Mul(x, 9). This could be 66 // better written as Add(Shl(x, 3), x), which also happens to be representable using a single 67 // instruction on x86. 68 // 69 // Here are some of the rules we have: 70 // 71 // Canonical form of logical not: BitXor(value, 1). We may have to avoid using this form if we don't 72 // know for sure that 'value' is 0-or-1 (i.e. returnsBool). In that case we fall back on 73 // Equal(value, 0). 74 // 75 // Canonical form of commutative operations: if the operation involves a constant, the constant must 76 // come second. Add(x, constant) is canonical, while Add(constant, x) is not. If there are no 77 // constants then the canonical form involves the lower-indexed value first. Given Add(x, y), it's 78 // canonical if x->index() <= y->index(). 79 80 bool verbose = false; 81 46 82 class ReduceStrength { 47 83 public: … … 55 91 { 56 92 bool result = false; 93 unsigned index = 0; 57 94 do { 58 95 m_changed = false; 59 96 m_changedCFG = false; 97 98 if (verbose) { 99 dataLog("Reduce strength IR before iteration #", ++index, "\n"); 100 dataLog(m_proc); 101 } 60 102 61 103 for (BasicBlock* block : m_proc.blocksInPreOrder()) { … … 258 300 } 259 301 302 // Turn this: BitXor(compare, 1) 303 // Into this: invertedCompare 304 if (m_value->child(1)->isInt32(1)) { 305 if (Value* invertedCompare = m_value->child(0)->invertedCompare(m_proc)) { 306 replaceWithNewValue(invertedCompare); 307 break; 308 } 309 } 310 260 311 // Turn this: BitXor(valueX, valueX) 261 312 // Into this: zero-constant. 262 313 if (m_value->child(0) == m_value->child(1)) { 263 Value* zeroConstant; 264 if (m_value->type() == Int32) 265 zeroConstant = m_proc.add<Const32Value>(m_value->origin(), 0); 266 else if (m_value->type() == Int64) 267 zeroConstant = m_proc.add<Const64Value>(m_value->origin(), 0); 268 else { 269 RELEASE_ASSERT(m_value->type() == Double); 270 zeroConstant = m_proc.add<ConstDoubleValue>(m_value->origin(), 0); 271 } 272 replaceWithNewValue(zeroConstant); 314 replaceWithNewValue(m_proc.addIntConstant(m_value->type(), 0)); 273 315 break; 274 316 } … … 378 420 handleCommutativity(); 379 421 380 // Turn this: Equal(Equal(x, 0), 0) 381 // Into this: NotEqual(x, 0) 382 if (m_value->child(0)->opcode() == Equal && m_value->child(1)->isInt32(0) 383 && m_value->child(0)->child(1)->isLikeZero()) { 422 // Turn this: Equal(bool, 0) 423 // Into this: BitXor(bool, 1) 424 if (m_value->child(0)->returnsBool() && m_value->child(1)->isInt32(0)) { 384 425 replaceWithNew<Value>( 385 NotEqual, m_value->origin(),386 m_ value->child(0)->child(0), m_value->child(0)->child(1));387 break; 388 } 389 426 BitXor, m_value->origin(), m_value->child(0), 427 m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), 1)); 428 break; 429 } 430 390 431 // Turn this Equal(bool, 1) 391 432 // Into this: bool … … 396 437 } 397 438 398 // FIXME: Have a compare-flipping optimization, like Equal(LessThan(a, b), 0) turns into399 // GreaterEqual(a, b).400 // https://bugs.webkit.org/show_bug.cgi?id=150726401 402 439 // Turn this: Equal(const1, const2) 403 440 // Into this: const1 == const2 404 replaceWithNewValue(m_value->child(0)->equalConstant(m_proc, m_value->child(1))); 441 replaceWithNewValue( 442 m_proc.addBoolConstant(m_value->child(0)->equalConstant(m_value->child(1)))); 405 443 break; 406 444 … … 428 466 // Turn this: NotEqual(const1, const2) 429 467 // Into this: const1 != const2 430 replaceWithNewValue(m_value->child(0)->notEqualConstant(m_proc, m_value->child(1))); 468 replaceWithNewValue( 469 m_proc.addBoolConstant(m_value->child(0)->notEqualConstant(m_value->child(1)))); 470 break; 471 472 case LessThan: 473 replaceWithNewValue( 474 m_proc.addBoolConstant(m_value->child(0)->lessThanConstant(m_value->child(1)))); 475 break; 476 477 case GreaterThan: 478 replaceWithNewValue( 479 m_proc.addBoolConstant(m_value->child(0)->greaterThanConstant(m_value->child(1)))); 480 break; 481 482 case LessEqual: 483 replaceWithNewValue( 484 m_proc.addBoolConstant(m_value->child(0)->lessEqualConstant(m_value->child(1)))); 485 break; 486 487 case GreaterEqual: 488 replaceWithNewValue( 489 m_proc.addBoolConstant(m_value->child(0)->greaterEqualConstant(m_value->child(1)))); 490 break; 491 492 case Above: 493 replaceWithNewValue( 494 m_proc.addBoolConstant(m_value->child(0)->aboveConstant(m_value->child(1)))); 495 break; 496 497 case Below: 498 replaceWithNewValue( 499 m_proc.addBoolConstant(m_value->child(0)->belowConstant(m_value->child(1)))); 500 break; 501 502 case AboveEqual: 503 replaceWithNewValue( 504 m_proc.addBoolConstant(m_value->child(0)->aboveEqualConstant(m_value->child(1)))); 505 break; 506 507 case BelowEqual: 508 replaceWithNewValue( 509 m_proc.addBoolConstant(m_value->child(0)->belowEqualConstant(m_value->child(1)))); 431 510 break; 432 511 … … 436 515 // Turn this: Branch(NotEqual(x, 0)) 437 516 // Into this: Branch(x) 438 if (branch->child(0)->opcode() == NotEqual && branch->child(0)->child(1)->is LikeZero()) {517 if (branch->child(0)->opcode() == NotEqual && branch->child(0)->child(1)->isInt(0)) { 439 518 branch->child(0) = branch->child(0)->child(0); 440 519 m_changed = true; … … 443 522 // Turn this: Branch(Equal(x, 0), then, else) 444 523 // Into this: Branch(x, else, then) 445 if (branch->child(0)->opcode() == Equal && branch->child(0)->child(1)->isLikeZero()) { 524 if (branch->child(0)->opcode() == Equal && branch->child(0)->child(1)->isInt(0)) { 525 branch->child(0) = branch->child(0)->child(0); 526 std::swap(branch->taken(), branch->notTaken()); 527 m_changed = true; 528 } 529 530 // Turn this: Branch(BitXor(bool, 1), then, else) 531 // Into this: Branch(bool, else, then) 532 if (branch->child(0)->opcode() == BitXor 533 && branch->child(0)->child(1)->isInt32(1) 534 && branch->child(0)->child(0)->returnsBool()) { 446 535 branch->child(0) = branch->child(0)->child(0); 447 536 std::swap(branch->taken(), branch->notTaken()); -
trunk/Source/JavaScriptCore/b3/B3Validate.cpp
r191993 r192072 280 280 break; 281 281 case Check: 282 VALIDATE(value->numChildren() >= 1, ("At ", *value)); 283 VALIDATE(isInt(value->child(0)->type()), ("At ", *value)); 284 VALIDATE(value->as<StackmapValue>()->constrainedChild(0).rep() == ValueRep::Any, ("At ", *value)); 282 285 validateStackmap(value); 283 286 break; … … 292 295 VALIDATE(value->type() != Void, ("At ", *value)); 293 296 break; 297 case Return: 298 VALIDATE(value->numChildren() == 1, ("At ", *value)); 299 VALIDATE(value->type() == Void, ("At ", *value)); 300 break; 294 301 case Branch: 295 case Return:296 VALIDATE(value->numChildren() == 1, ("At ", *value));297 VALIDATE(value->type() == Void, ("At ", *value));298 break;299 302 case Switch: 300 303 VALIDATE(value->numChildren() == 1, ("At ", *value)); -
trunk/Source/JavaScriptCore/b3/B3Value.cpp
r192051 r192072 33 33 #include "B3ControlValue.h" 34 34 #include "B3MemoryValue.h" 35 #include "B3ProcedureInlines.h" 35 36 #include "B3StackSlotValue.h" 36 37 #include "B3UpsilonValue.h" … … 163 164 } 164 165 165 Value* Value::equalConstant(Procedure&, Value*) const 166 { 167 return nullptr; 168 } 169 170 Value* Value::notEqualConstant(Procedure&, Value*) const 171 { 166 TriState Value::equalConstant(Value*) const 167 { 168 return MixedTriState; 169 } 170 171 TriState Value::notEqualConstant(Value*) const 172 { 173 return MixedTriState; 174 } 175 176 TriState Value::lessThanConstant(Value*) const 177 { 178 return MixedTriState; 179 } 180 181 TriState Value::greaterThanConstant(Value*) const 182 { 183 return MixedTriState; 184 } 185 186 TriState Value::lessEqualConstant(Value*) const 187 { 188 return MixedTriState; 189 } 190 191 TriState Value::greaterEqualConstant(Value*) const 192 { 193 return MixedTriState; 194 } 195 196 TriState Value::aboveConstant(Value*) const 197 { 198 return MixedTriState; 199 } 200 201 TriState Value::belowConstant(Value*) const 202 { 203 return MixedTriState; 204 } 205 206 TriState Value::aboveEqualConstant(Value*) const 207 { 208 return MixedTriState; 209 } 210 211 TriState Value::belowEqualConstant(Value*) const 212 { 213 return MixedTriState; 214 } 215 216 Value* Value::invertedCompare(Procedure& proc) const 217 { 218 if (!numChildren()) 219 return nullptr; 220 if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) 221 return proc.add<Value>(*invertedOpcode, type(), origin(), children()); 172 222 return nullptr; 173 223 } -
trunk/Source/JavaScriptCore/b3/B3Value.h
r192051 r192072 119 119 virtual Value* sShrConstant(Procedure&, Value* other) const; 120 120 virtual Value* zShrConstant(Procedure&, Value* other) const; 121 virtual Value* equalConstant(Procedure&, Value* other) const; 122 virtual Value* notEqualConstant(Procedure&, Value* other) const; 121 122 virtual TriState equalConstant(Value* other) const; 123 virtual TriState notEqualConstant(Value* other) const; 124 virtual TriState lessThanConstant(Value* other) const; 125 virtual TriState greaterThanConstant(Value* other) const; 126 virtual TriState lessEqualConstant(Value* other) const; 127 virtual TriState greaterEqualConstant(Value* other) const; 128 virtual TriState aboveConstant(Value* other) const; 129 virtual TriState belowConstant(Value* other) const; 130 virtual TriState aboveEqualConstant(Value* other) const; 131 virtual TriState belowEqualConstant(Value* other) const; 132 133 // If the value is a comparison then this returns the inverted form of that comparison, if 134 // possible. It can be impossible for double comparisons, where for example LessThan and 135 // GreaterEqual behave differently. If this returns a value, it is a new value, which must be 136 // either inserted into some block or deleted. 137 Value* invertedCompare(Procedure&) const; 123 138 124 139 bool hasInt32() const; -
trunk/Source/JavaScriptCore/b3/air/AirArg.cpp
r191952 r192072 34 34 namespace JSC { namespace B3 { namespace Air { 35 35 36 bool Arg::isRepresentableAs(Width width, Signedness signedness) const 37 { 38 switch (signedness) { 39 case Signed: 40 switch (width) { 41 case Width8: 42 return isRepresentableAs<int8_t>(); 43 case Width16: 44 return isRepresentableAs<int16_t>(); 45 case Width32: 46 return isRepresentableAs<int32_t>(); 47 case Width64: 48 return isRepresentableAs<int64_t>(); 49 } 50 case Unsigned: 51 switch (width) { 52 case Width8: 53 return isRepresentableAs<uint8_t>(); 54 case Width16: 55 return isRepresentableAs<uint16_t>(); 56 case Width32: 57 return isRepresentableAs<uint32_t>(); 58 case Width64: 59 return isRepresentableAs<uint64_t>(); 60 } 61 } 62 } 63 36 64 void Arg::dump(PrintStream& out) const 37 65 { … … 91 119 } } } // namespace JSC::B3::Air 92 120 121 namespace WTF { 122 123 using namespace JSC::B3::Air; 124 125 void printInternal(PrintStream& out, Arg::Kind kind) 126 { 127 switch (kind) { 128 case Arg::Invalid: 129 out.print("Invalid"); 130 return; 131 case Arg::Tmp: 132 out.print("Tmp"); 133 return; 134 case Arg::Imm: 135 out.print("Imm"); 136 return; 137 case Arg::Imm64: 138 out.print("Imm64"); 139 return; 140 case Arg::Addr: 141 out.print("Addr"); 142 return; 143 case Arg::Stack: 144 out.print("Stack"); 145 return; 146 case Arg::CallArg: 147 out.print("CallArg"); 148 return; 149 case Arg::Index: 150 out.print("Index"); 151 return; 152 case Arg::RelCond: 153 out.print("RelCond"); 154 return; 155 case Arg::ResCond: 156 out.print("ResCond"); 157 return; 158 case Arg::DoubleCond: 159 out.print("DoubleCond"); 160 return; 161 case Arg::Special: 162 out.print("Special"); 163 return; 164 } 165 166 RELEASE_ASSERT_NOT_REACHED(); 167 } 168 169 void printInternal(PrintStream& out, Arg::Role role) 170 { 171 switch (role) { 172 case Arg::Use: 173 out.print("Use"); 174 return; 175 case Arg::Def: 176 out.print("Def"); 177 return; 178 case Arg::UseDef: 179 out.print("UseDef"); 180 return; 181 case Arg::UseAddr: 182 out.print("UseAddr"); 183 return; 184 } 185 186 RELEASE_ASSERT_NOT_REACHED(); 187 } 188 189 void printInternal(PrintStream& out, Arg::Type type) 190 { 191 switch (type) { 192 case Arg::GP: 193 out.print("GP"); 194 return; 195 case Arg::FP: 196 out.print("FP"); 197 return; 198 } 199 200 RELEASE_ASSERT_NOT_REACHED(); 201 } 202 203 void printInternal(PrintStream& out, Arg::Width width) 204 { 205 switch (width) { 206 case Arg::Width8: 207 out.print("Width8"); 208 return; 209 case Arg::Width16: 210 out.print("Width16"); 211 return; 212 case Arg::Width32: 213 out.print("Width32"); 214 return; 215 case Arg::Width64: 216 out.print("Width64"); 217 return; 218 } 219 220 RELEASE_ASSERT_NOT_REACHED(); 221 } 222 223 void printInternal(PrintStream& out, Arg::Signedness signedness) 224 { 225 switch (signedness) { 226 case Arg::Signed: 227 out.print("Signed"); 228 return; 229 case Arg::Unsigned: 230 out.print("Unsigned"); 231 return; 232 } 233 234 RELEASE_ASSERT_NOT_REACHED(); 235 } 236 237 } // namespace WTF 238 93 239 #endif // ENABLE(B3_JIT) -
trunk/Source/JavaScriptCore/b3/air/AirArg.h
r191957 r192072 111 111 static const unsigned numTypes = 2; 112 112 113 enum Width : int8_t { 114 Width8, 115 Width16, 116 Width32, 117 Width64 118 }; 119 120 enum Signedness : int8_t { 121 Signed, 122 Unsigned 123 }; 124 113 125 // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for 114 126 // UseAddr, since isUse() for an Arg::addr means that we are loading from the address. … … 152 164 ASSERT_NOT_REACHED(); 153 165 return GP; 166 } 167 168 static Width widthForB3Type(B3::Type type) 169 { 170 switch (type) { 171 case Void: 172 ASSERT_NOT_REACHED(); 173 return Width8; 174 case Int32: 175 return Width32; 176 case Int64: 177 case Double: 178 return Width64; 179 } 154 180 } 155 181 … … 375 401 ASSERT(kind() == Imm || kind() == Imm64); 376 402 return m_offset; 403 } 404 405 template<typename T> 406 bool isRepresentableAs() const 407 { 408 return B3::isRepresentableAs<T>(value()); 409 } 410 411 bool isRepresentableAs(Width, Signedness) const; 412 413 template<typename T> 414 T asNumber() const 415 { 416 return static_cast<T>(value()); 377 417 } 378 418 … … 685 725 } 686 726 727 // This is valid for condition arguments. It will invert them. 728 Arg inverted(bool inverted = true) const 729 { 730 if (!inverted) 731 return *this; 732 switch (kind()) { 733 case RelCond: 734 return relCond(MacroAssembler::invert(asRelationalCondition())); 735 case ResCond: 736 return resCond(MacroAssembler::invert(asResultCondition())); 737 case DoubleCond: 738 return doubleCond(MacroAssembler::invert(asDoubleCondition())); 739 default: 740 RELEASE_ASSERT_NOT_REACHED(); 741 return Arg(); 742 } 743 } 744 745 Arg flipped(bool flipped = true) const 746 { 747 if (!flipped) 748 return Arg(); 749 return relCond(MacroAssembler::flip(asRelationalCondition())); 750 } 751 752 bool isSignedCond() const 753 { 754 return isRelCond() && MacroAssembler::isSigned(asRelationalCondition()); 755 } 756 757 bool isUnsignedCond() const 758 { 759 return isRelCond() && MacroAssembler::isUnsigned(asRelationalCondition()); 760 } 761 687 762 void dump(PrintStream&) const; 688 763 … … 722 797 namespace WTF { 723 798 799 void printInternal(PrintStream&, JSC::B3::Air::Arg::Kind); 800 void printInternal(PrintStream&, JSC::B3::Air::Arg::Role); 801 void printInternal(PrintStream&, JSC::B3::Air::Arg::Type); 802 void printInternal(PrintStream&, JSC::B3::Air::Arg::Width); 803 void printInternal(PrintStream&, JSC::B3::Air::Arg::Signedness); 804 724 805 template<typename T> struct DefaultHash; 725 806 template<> struct DefaultHash<JSC::B3::Air::Arg> { -
trunk/Source/JavaScriptCore/b3/air/AirInst.h
r191846 r192072 84 84 } 85 85 86 explicit operator bool() const { return origin || opcode != Nop || args.size(); } 87 86 88 // Note that these functors all avoid using "const" because we want to use them for things that 87 89 // edit IR. IR is meant to be edited; if you're carrying around a "const Inst&" then you're -
trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
r192051 r192072 198 198 Tmp, Tmp 199 199 200 Load8 U:G, D:G 201 Addr, Tmp 202 Index, Tmp 203 204 Load8SignedExtendTo32 U:G, D:G 205 Addr, Tmp 206 Index, Tmp 207 208 Load16 U:G, D:G 209 Addr, Tmp 210 Index, Tmp 211 212 Load16SignedExtendTo32 U:G, D:G 213 Addr, Tmp 214 Index, Tmp 215 216 Compare32 U:G, U:G, U:G, D:G 217 RelCond, Tmp, Tmp, Tmp 218 RelCond, Tmp, Imm, Tmp 219 220 Compare64 U:G, U:G, U:G, D:G 221 RelCond, Tmp, Imm, Tmp 222 RelCond, Tmp, Tmp, Tmp 223 224 Test32 U:G, U:G, U:G, D:G 225 ResCond, Addr, Imm, Tmp 226 ResCond, Tmp, Tmp, Tmp 227 228 Test64 U:G, U:G, U:G, D:G 229 ResCond, Tmp, Imm, Tmp 230 ResCond, Tmp, Tmp, Tmp 231 232 Branch8 U:G, U:G, U:G /branch 233 RelCond, Addr, Imm 234 RelCond, Index, Imm 235 236 Branch32 U:G, U:G, U:G /branch 237 RelCond, Addr, Imm 238 RelCond, Tmp, Tmp 239 RelCond, Tmp, Imm 240 RelCond, Tmp, Addr 241 RelCond, Addr, Tmp 242 RelCond, Index, Imm 243 244 Branch64 U:G, U:G, U:G /branch 245 RelCond, Tmp, Tmp 246 RelCond, Tmp, Addr 247 RelCond, Addr, Tmp 248 RelCond, Index, Tmp 249 250 BranchTest8 U:G, U:G, U:G /branch 251 ResCond, Addr, Imm 252 ResCond, Index, Imm 253 200 254 BranchTest32 U:G, U:G, U:G /branch 201 255 ResCond, Tmp, Tmp … … 204 258 ResCond, Index, Imm 205 259 260 # Warning: forms that take an immediate will sign-extend their immediate. You probably want 261 # BranchTest32 in most cases where you use an immediate. 206 262 BranchTest64 U:G, U:G, U:G /branch 207 263 ResCond, Tmp, Tmp -
trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb
r191846 r192072 411 411 412 412 if columnIndex >= forms[0].kinds.length 413 raise unless forms.length == 1413 raise "Did not reduce to one form: #{forms.inspect}" unless forms.length == 1 414 414 callback[forms[0]] 415 415 return -
trunk/Source/JavaScriptCore/b3/testb3.cpp
r192051 r192072 42 42 #include "LinkBuffer.h" 43 43 #include "VM.h" 44 #include <wtf/Lock.h> 45 #include <wtf/NumberOfCores.h> 46 #include <wtf/Threading.h> 44 47 45 48 // We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous. … … 1705 1708 1706 1709 CHECK(compileAndRun<int>(proc, value) == value); 1710 } 1711 1712 template<typename T> 1713 int32_t modelLoad(int32_t value) 1714 { 1715 union { 1716 int32_t original; 1717 T loaded; 1718 } u; 1719 1720 u.original = value; 1721 if (std::is_signed<T>::value) 1722 return static_cast<int32_t>(u.loaded); 1723 return static_cast<int32_t>(static_cast<uint32_t>(u.loaded)); 1724 } 1725 1726 template<typename T> 1727 void testLoad(B3::Opcode opcode, int32_t value) 1728 { 1729 // Simple load from an absolute address. 1730 { 1731 Procedure proc; 1732 BasicBlock* root = proc.addBlock(); 1733 1734 root->appendNew<ControlValue>( 1735 proc, Return, Origin(), 1736 root->appendNew<MemoryValue>( 1737 proc, opcode, Int32, Origin(), 1738 root->appendNew<ConstPtrValue>(proc, Origin(), &value))); 1739 1740 CHECK(compileAndRun<int32_t>(proc) == modelLoad<T>(value)); 1741 } 1742 1743 // Simple load from an address in a register. 1744 { 1745 Procedure proc; 1746 BasicBlock* root = proc.addBlock(); 1747 1748 root->appendNew<ControlValue>( 1749 proc, Return, Origin(), 1750 root->appendNew<MemoryValue>( 1751 proc, opcode, Int32, Origin(), 1752 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); 1753 1754 CHECK(compileAndRun<int32_t>(proc, &value) == modelLoad<T>(value)); 1755 } 1756 1757 // Simple load from an address in a register, at an offset. 1758 { 1759 Procedure proc; 1760 BasicBlock* root = proc.addBlock(); 1761 1762 root->appendNew<ControlValue>( 1763 proc, Return, Origin(), 1764 root->appendNew<MemoryValue>( 1765 proc, opcode, Int32, Origin(), 1766 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), 1767 sizeof(int32_t))); 1768 1769 CHECK(compileAndRun<int32_t>(proc, &value - 1) == modelLoad<T>(value)); 1770 } 1771 1772 // Load from a simple base-index with various scales. 1773 for (unsigned logScale = 0; logScale <= 3; ++logScale) { 1774 Procedure proc; 1775 BasicBlock* root = proc.addBlock(); 1776 1777 root->appendNew<ControlValue>( 1778 proc, Return, Origin(), 1779 root->appendNew<MemoryValue>( 1780 proc, opcode, Int32, Origin(), 1781 root->appendNew<Value>( 1782 proc, Add, Origin(), 1783 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), 1784 root->appendNew<Value>( 1785 proc, Shl, Origin(), 1786 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), 1787 root->appendNew<Const32Value>(proc, Origin(), logScale))))); 1788 1789 CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value)); 1790 } 1791 1792 // Load from a simple base-index with various scales, but commuted. 1793 for (unsigned logScale = 0; logScale <= 3; ++logScale) { 1794 Procedure proc; 1795 BasicBlock* root = proc.addBlock(); 1796 1797 root->appendNew<ControlValue>( 1798 proc, Return, Origin(), 1799 root->appendNew<MemoryValue>( 1800 proc, opcode, Int32, Origin(), 1801 root->appendNew<Value>( 1802 proc, Add, Origin(), 1803 root->appendNew<Value>( 1804 proc, Shl, Origin(), 1805 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), 1806 root->appendNew<Const32Value>(proc, Origin(), logScale)), 1807 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); 1808 1809 CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value)); 1810 } 1707 1811 } 1708 1812 … … 2247 2351 2248 2352 double after = monotonicallyIncreasingTimeMS(); 2249 dataLog( " That took ", after - before, " ms.\n");2353 dataLog(toCString(" That took ", after - before, " ms.\n")); 2250 2354 } 2251 2355 … … 2300 2404 } 2301 2405 2406 template<typename LeftFunctor, typename RightFunctor> 2407 void genericTestCompare( 2408 B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor, 2409 int left, int right, int result) 2410 { 2411 // Using a compare. 2412 { 2413 Procedure proc; 2414 BasicBlock* root = proc.addBlock(); 2415 2416 root->appendNew<ControlValue>( 2417 proc, Return, Origin(), 2418 root->appendNew<Value>( 2419 proc, NotEqual, Origin(), 2420 root->appendNew<Value>( 2421 proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)), 2422 root->appendNew<Const32Value>(proc, Origin(), 0))); 2423 2424 CHECK(compileAndRun<int>(proc, left, right) == result); 2425 } 2426 2427 // Using a branch. 2428 { 2429 Procedure proc; 2430 BasicBlock* root = proc.addBlock(); 2431 BasicBlock* thenCase = proc.addBlock(); 2432 BasicBlock* elseCase = proc.addBlock(); 2433 2434 root->appendNew<ControlValue>( 2435 proc, Branch, Origin(), 2436 root->appendNew<Value>( 2437 proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)), 2438 FrequentedBlock(thenCase), FrequentedBlock(elseCase)); 2439 2440 // We use a patchpoint on the then case to ensure that this doesn't get if-converted. 2441 PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin()); 2442 patchpoint->setGenerator( 2443 [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { 2444 CHECK(params.reps.size() == 1); 2445 CHECK(params.reps[0].isGPR()); 2446 jit.move(CCallHelpers::TrustedImm32(1), params.reps[0].gpr()); 2447 }); 2448 thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); 2449 2450 elseCase->appendNew<ControlValue>( 2451 proc, Return, Origin(), 2452 elseCase->appendNew<Const32Value>(proc, Origin(), 0)); 2453 2454 CHECK(compileAndRun<int>(proc, left, right) == result); 2455 } 2456 } 2457 2458 int modelCompare(B3::Opcode opcode, int left, int right) 2459 { 2460 switch (opcode) { 2461 case Equal: 2462 return left == right; 2463 case NotEqual: 2464 return left != right; 2465 case LessThan: 2466 return left < right; 2467 case GreaterThan: 2468 return left > right; 2469 case LessEqual: 2470 return left <= right; 2471 case GreaterEqual: 2472 return left >= right; 2473 case Above: 2474 return static_cast<unsigned>(left) > static_cast<unsigned>(right); 2475 case Below: 2476 return static_cast<unsigned>(left) < static_cast<unsigned>(right); 2477 case AboveEqual: 2478 return static_cast<unsigned>(left) >= static_cast<unsigned>(right); 2479 case BelowEqual: 2480 return static_cast<unsigned>(left) <= static_cast<unsigned>(right); 2481 case BitAnd: 2482 return !!(left & right); 2483 default: 2484 RELEASE_ASSERT_NOT_REACHED(); 2485 return 0; 2486 } 2487 } 2488 2489 template<typename T> 2490 void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right) 2491 { 2492 int result = modelCompare(opcode, modelLoad<T>(left), right); 2493 2494 // Test addr-to-tmp 2495 int slot = left; 2496 genericTestCompare( 2497 opcode, 2498 [&] (BasicBlock* block, Procedure& proc) { 2499 return block->appendNew<MemoryValue>( 2500 proc, loadOpcode, Int32, Origin(), 2501 block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); 2502 }, 2503 [&] (BasicBlock* block, Procedure& proc) { 2504 return block->appendNew<Value>( 2505 proc, Trunc, Origin(), 2506 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 2507 }, 2508 left, right, result); 2509 2510 // Test addr-to-imm 2511 slot = left; 2512 genericTestCompare( 2513 opcode, 2514 [&] (BasicBlock* block, Procedure& proc) { 2515 return block->appendNew<MemoryValue>( 2516 proc, loadOpcode, Int32, Origin(), 2517 block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); 2518 }, 2519 [&] (BasicBlock* block, Procedure& proc) { 2520 return block->appendNew<Const32Value>(proc, Origin(), right); 2521 }, 2522 left, right, result); 2523 2524 result = modelCompare(opcode, left, modelLoad<T>(right)); 2525 2526 // Test tmp-to-addr 2527 slot = right; 2528 genericTestCompare( 2529 opcode, 2530 [&] (BasicBlock* block, Procedure& proc) { 2531 return block->appendNew<Value>( 2532 proc, Trunc, Origin(), 2533 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 2534 }, 2535 [&] (BasicBlock* block, Procedure& proc) { 2536 return block->appendNew<MemoryValue>( 2537 proc, loadOpcode, Int32, Origin(), 2538 block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); 2539 }, 2540 left, right, result); 2541 2542 // Test imm-to-addr 2543 slot = right; 2544 genericTestCompare( 2545 opcode, 2546 [&] (BasicBlock* block, Procedure& proc) { 2547 return block->appendNew<Const32Value>(proc, Origin(), left); 2548 }, 2549 [&] (BasicBlock* block, Procedure& proc) { 2550 return block->appendNew<MemoryValue>( 2551 proc, loadOpcode, Int32, Origin(), 2552 block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); 2553 }, 2554 left, right, result); 2555 } 2556 2557 void testCompareImpl(B3::Opcode opcode, int left, int right) 2558 { 2559 int result = modelCompare(opcode, left, right); 2560 2561 // Test tmp-to-tmp. 2562 genericTestCompare( 2563 opcode, 2564 [&] (BasicBlock* block, Procedure& proc) { 2565 return block->appendNew<Value>( 2566 proc, Trunc, Origin(), 2567 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 2568 }, 2569 [&] (BasicBlock* block, Procedure& proc) { 2570 return block->appendNew<Value>( 2571 proc, Trunc, Origin(), 2572 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 2573 }, 2574 left, right, result); 2575 2576 // Test imm-to-tmp. 2577 genericTestCompare( 2578 opcode, 2579 [&] (BasicBlock* block, Procedure& proc) { 2580 return block->appendNew<Const32Value>(proc, Origin(), left); 2581 }, 2582 [&] (BasicBlock* block, Procedure& proc) { 2583 return block->appendNew<Value>( 2584 proc, Trunc, Origin(), 2585 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 2586 }, 2587 left, right, result); 2588 2589 // Test tmp-to-imm. 2590 genericTestCompare( 2591 opcode, 2592 [&] (BasicBlock* block, Procedure& proc) { 2593 return block->appendNew<Value>( 2594 proc, Trunc, Origin(), 2595 block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 2596 }, 2597 [&] (BasicBlock* block, Procedure& proc) { 2598 return block->appendNew<Const32Value>(proc, Origin(), right); 2599 }, 2600 left, right, result); 2601 2602 // Test imm-to-imm. 2603 genericTestCompare( 2604 opcode, 2605 [&] (BasicBlock* block, Procedure& proc) { 2606 return block->appendNew<Const32Value>(proc, Origin(), left); 2607 }, 2608 [&] (BasicBlock* block, Procedure& proc) { 2609 return block->appendNew<Const32Value>(proc, Origin(), right); 2610 }, 2611 left, right, result); 2612 2613 testCompareLoad<int32_t>(opcode, Load, left, right); 2614 testCompareLoad<int8_t>(opcode, Load8S, left, right); 2615 testCompareLoad<uint8_t>(opcode, Load8Z, left, right); 2616 testCompareLoad<int16_t>(opcode, Load16S, left, right); 2617 testCompareLoad<uint16_t>(opcode, Load16Z, left, right); 2618 } 2619 2620 void testCompare(B3::Opcode opcode, int left, int right) 2621 { 2622 auto variants = [&] (int left, int right) { 2623 testCompareImpl(opcode, left, right); 2624 testCompareImpl(opcode, left, right + 1); 2625 testCompareImpl(opcode, left, right - 1); 2626 2627 auto multipliedTests = [&] (int factor) { 2628 testCompareImpl(opcode, left * factor, right); 2629 testCompareImpl(opcode, left * factor, right + 1); 2630 testCompareImpl(opcode, left * factor, right - 1); 2631 2632 testCompareImpl(opcode, left, right * factor); 2633 testCompareImpl(opcode, left, (right + 1) * factor); 2634 testCompareImpl(opcode, left, (right - 1) * factor); 2635 2636 testCompareImpl(opcode, left * factor, right * factor); 2637 testCompareImpl(opcode, left * factor, (right + 1) * factor); 2638 testCompareImpl(opcode, left * factor, (right - 1) * factor); 2639 }; 2640 2641 multipliedTests(10); 2642 multipliedTests(100); 2643 multipliedTests(1000); 2644 multipliedTests(100000); 2645 }; 2646 2647 variants(left, right); 2648 variants(-left, right); 2649 variants(left, -right); 2650 variants(-left, -right); 2651 } 2652 2302 2653 #define RUN(test) do { \ 2303 2654 if (!shouldRun(#test)) \ 2304 2655 break; \ 2305 dataLog(#test ":\n"); \ 2306 test; \ 2307 dataLog(" OK!\n"); \ 2308 didRun++; \ 2656 tasks.append( \ 2657 createSharedTask<void()>( \ 2658 [&] () { \ 2659 dataLog(#test "...\n"); \ 2660 test; \ 2661 dataLog(#test ": OK!\n"); \ 2662 })); \ 2309 2663 } while (false); 2310 2664 … … 2314 2668 vm = &VM::create(LargeHeap).leakRef(); 2315 2669 2670 Deque<RefPtr<SharedTask<void()>>> tasks; 2671 2316 2672 auto shouldRun = [&] (const char* testName) -> bool { 2317 return ! !strcasestr(testName, filter);2673 return !filter || !!strcasestr(testName, filter); 2318 2674 }; 2319 unsigned didRun = 0;2320 2675 2321 2676 RUN(test42()); … … 2671 3026 RUN(testLoadFromFramePointer()); 2672 3027 RUN(testStoreLoadStackSlot(50)); 3028 2673 3029 RUN(testBranch()); 2674 3030 RUN(testBranchPtr()); … … 2700 3056 RUN(testSimpleCheck()); 2701 3057 2702 if (!didRun) 3058 RUN(testCompare(Equal, 42, 42)); 3059 RUN(testCompare(NotEqual, 42, 42)); 3060 RUN(testCompare(LessThan, 42, 42)); 3061 RUN(testCompare(GreaterThan, 42, 42)); 3062 RUN(testCompare(LessEqual, 42, 42)); 3063 RUN(testCompare(GreaterEqual, 42, 42)); 3064 RUN(testCompare(Below, 42, 42)); 3065 RUN(testCompare(Above, 42, 42)); 3066 RUN(testCompare(BelowEqual, 42, 42)); 3067 RUN(testCompare(AboveEqual, 42, 42)); 3068 3069 RUN(testCompare(BitAnd, 42, 42)); 3070 RUN(testCompare(BitAnd, 42, 0)); 3071 3072 RUN(testLoad<int32_t>(Load, 60)); 3073 RUN(testLoad<int32_t>(Load, -60)); 3074 RUN(testLoad<int32_t>(Load, 1000)); 3075 RUN(testLoad<int32_t>(Load, -1000)); 3076 RUN(testLoad<int32_t>(Load, 1000000)); 3077 RUN(testLoad<int32_t>(Load, -1000000)); 3078 RUN(testLoad<int32_t>(Load, 1000000000)); 3079 RUN(testLoad<int32_t>(Load, -1000000000)); 3080 3081 RUN(testLoad<int8_t>(Load8S, 60)); 3082 RUN(testLoad<int8_t>(Load8S, -60)); 3083 RUN(testLoad<int8_t>(Load8S, 1000)); 3084 RUN(testLoad<int8_t>(Load8S, -1000)); 3085 RUN(testLoad<int8_t>(Load8S, 1000000)); 3086 RUN(testLoad<int8_t>(Load8S, -1000000)); 3087 RUN(testLoad<int8_t>(Load8S, 1000000000)); 3088 RUN(testLoad<int8_t>(Load8S, -1000000000)); 3089 3090 RUN(testLoad<uint8_t>(Load8Z, 60)); 3091 RUN(testLoad<uint8_t>(Load8Z, -60)); 3092 RUN(testLoad<uint8_t>(Load8Z, 1000)); 3093 RUN(testLoad<uint8_t>(Load8Z, -1000)); 3094 RUN(testLoad<uint8_t>(Load8Z, 1000000)); 3095 RUN(testLoad<uint8_t>(Load8Z, -1000000)); 3096 RUN(testLoad<uint8_t>(Load8Z, 1000000000)); 3097 RUN(testLoad<uint8_t>(Load8Z, -1000000000)); 3098 3099 RUN(testLoad<int16_t>(Load16S, 60)); 3100 RUN(testLoad<int16_t>(Load16S, -60)); 3101 RUN(testLoad<int16_t>(Load16S, 1000)); 3102 RUN(testLoad<int16_t>(Load16S, -1000)); 3103 RUN(testLoad<int16_t>(Load16S, 1000000)); 3104 RUN(testLoad<int16_t>(Load16S, -1000000)); 3105 RUN(testLoad<int16_t>(Load16S, 1000000000)); 3106 RUN(testLoad<int16_t>(Load16S, -1000000000)); 3107 3108 RUN(testLoad<uint16_t>(Load16Z, 60)); 3109 RUN(testLoad<uint16_t>(Load16Z, -60)); 3110 RUN(testLoad<uint16_t>(Load16Z, 1000)); 3111 RUN(testLoad<uint16_t>(Load16Z, -1000)); 3112 RUN(testLoad<uint16_t>(Load16Z, 1000000)); 3113 RUN(testLoad<uint16_t>(Load16Z, -1000000)); 3114 RUN(testLoad<uint16_t>(Load16Z, 1000000000)); 3115 RUN(testLoad<uint16_t>(Load16Z, -1000000000)); 3116 3117 if (tasks.isEmpty()) 2703 3118 usage(); 3119 3120 Lock lock; 3121 3122 Vector<ThreadIdentifier> threads; 3123 for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) { 3124 threads.append( 3125 createThread( 3126 "testb3 thread", 3127 [&] () { 3128 for (;;) { 3129 RefPtr<SharedTask<void()>> task; 3130 { 3131 LockHolder locker(lock); 3132 if (tasks.isEmpty()) 3133 return; 3134 task = tasks.takeFirst(); 3135 } 3136 3137 task->run(); 3138 } 3139 })); 3140 } 3141 3142 for (ThreadIdentifier thread : threads) 3143 waitForThreadCompletion(thread); 2704 3144 } 2705 3145 … … 2717 3157 int main(int argc, char** argv) 2718 3158 { 2719 const char* filter = "";3159 const char* filter = nullptr; 2720 3160 switch (argc) { 2721 3161 case 1: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r192000 r192072 3475 3475 int32_t divisor = node->child2()->asInt32(); 3476 3476 if (divisor > 1 && hasOneBitSet(divisor)) { 3477 unsigned logarithm = WTF::fastLog2( divisor);3477 unsigned logarithm = WTF::fastLog2(static_cast<uint32_t>(divisor)); 3478 3478 GPRReg dividendGPR = op1.gpr(); 3479 3479 GPRTemporary result(this); -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r191937 r192072 1459 1459 switch (elementSize(type)) { 1460 1460 case 1: 1461 if ( isSigned(type))1461 if (JSC::isSigned(type)) 1462 1462 load8SignedExtendTo32(BaseIndex(scratch, property, TimesOne), resultPayload); 1463 1463 else … … 1465 1465 break; 1466 1466 case 2: 1467 if ( isSigned(type))1467 if (JSC::isSigned(type)) 1468 1468 load16SignedExtendTo32(BaseIndex(scratch, property, TimesTwo), resultPayload); 1469 1469 else … … 1597 1597 if (isClamped(type)) { 1598 1598 ASSERT(elementSize(type) == 1); 1599 ASSERT(! isSigned(type));1599 ASSERT(!JSC::isSigned(type)); 1600 1600 Jump inBounds = branch32(BelowOrEqual, earlyScratch, TrustedImm32(0xff)); 1601 1601 Jump tooBig = branch32(GreaterThan, earlyScratch, TrustedImm32(0xff));
Note: See TracChangeset
for help on using the changeset viewer.