OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/constant_propagator.h" | 8 #include "vm/constant_propagator.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 1571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1582 | 1582 |
1583 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. | 1583 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. |
1584 default: | 1584 default: |
1585 UNREACHABLE(); | 1585 UNREACHABLE(); |
1586 } | 1586 } |
1587 | 1587 |
1588 return false; | 1588 return false; |
1589 } | 1589 } |
1590 | 1590 |
1591 | 1591 |
| 1592 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { |
| 1593 Integer& result = Integer::Handle(); |
| 1594 |
| 1595 switch (op_kind()) { |
| 1596 case Token::kNEGATE: |
| 1597 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(Smi::New(-1))); |
| 1598 break; |
| 1599 |
| 1600 case Token::kBIT_NOT: |
| 1601 if (value.IsSmi()) { |
| 1602 result = Integer::New(~Smi::Cast(value).Value()); |
| 1603 } else if (value.IsMint()) { |
| 1604 result = Integer::New(~Mint::Cast(value).value()); |
| 1605 } |
| 1606 break; |
| 1607 |
| 1608 default: |
| 1609 UNREACHABLE(); |
| 1610 } |
| 1611 |
| 1612 if (!result.IsNull()) { |
| 1613 if (!IsRepresentable(result, representation())) { |
| 1614 // If this operation is not truncating it would deoptimize on overflow. |
| 1615 // Check that we match this behavior and don't produce a value that is |
| 1616 // larger than something this operation can produce. We could have |
| 1617 // specialized instructions that use this value under this assumption. |
| 1618 return Integer::null(); |
| 1619 } |
| 1620 result ^= result.CheckAndCanonicalize(NULL); |
| 1621 } |
| 1622 |
| 1623 return result.raw(); |
| 1624 } |
| 1625 |
| 1626 |
1592 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, | 1627 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, |
1593 const Integer& right) const { | 1628 const Integer& right) const { |
1594 Integer& result = Integer::Handle(); | 1629 Integer& result = Integer::Handle(); |
1595 | 1630 |
1596 switch (op_kind()) { | 1631 switch (op_kind()) { |
1597 case Token::kTRUNCDIV: | 1632 case Token::kTRUNCDIV: |
1598 case Token::kMOD: | 1633 case Token::kMOD: |
1599 // Check right value for zero. | 1634 // Check right value for zero. |
1600 if (right.AsInt64Value() == 0) { | 1635 if (right.AsInt64Value() == 0) { |
1601 break; // Will throw. | 1636 break; // Will throw. |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2302 other_defn->IsComparison() && | 2337 other_defn->IsComparison() && |
2303 (other->Type()->ToCid() == kBoolCid) && | 2338 (other->Type()->ToCid() == kBoolCid) && |
2304 other_defn->HasOnlyUse(other)) { | 2339 other_defn->HasOnlyUse(other)) { |
2305 *negated = true; | 2340 *negated = true; |
2306 return other_defn; | 2341 return other_defn; |
2307 } | 2342 } |
2308 return compare; | 2343 return compare; |
2309 } | 2344 } |
2310 | 2345 |
2311 | 2346 |
2312 // Recognize the pattern (a & b) == 0 where left is a bitwise and operation | 2347 static bool BindsToGivenConstant(Value* v, intptr_t expected) { |
2313 // and right is a constant 0. | 2348 return v->BindsToConstant() && |
2314 static bool RecognizeTestPattern(Value* left, Value* right) { | 2349 v->BoundConstant().IsSmi() && |
2315 if (!right->BindsToConstant()) { | 2350 (Smi::Cast(v->BoundConstant()).Value() == expected); |
| 2351 } |
| 2352 |
| 2353 |
| 2354 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. |
| 2355 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { |
| 2356 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { |
2316 return false; | 2357 return false; |
2317 } | 2358 } |
2318 | 2359 |
2319 const Object& value = right->BoundConstant(); | 2360 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); |
2320 if (!value.IsSmi() || (Smi::Cast(value).Value() != 0)) { | 2361 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { |
2321 return false; | 2362 return false; |
2322 } | 2363 } |
2323 | 2364 |
2324 Definition* left_defn = left->definition(); | 2365 |
2325 return left_defn->IsBinarySmiOp() && | 2366 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); |
2326 (left_defn->AsBinarySmiOp()->op_kind() == Token::kBIT_AND) && | 2367 if ((mask_op == NULL) || |
2327 left_defn->HasOnlyUse(left); | 2368 (mask_op->op_kind() != Token::kBIT_AND) || |
| 2369 !mask_op->HasOnlyUse(left)) { |
| 2370 return false; |
| 2371 } |
| 2372 |
| 2373 if (value == 0) { |
| 2374 // Recognized (a & b) == 0 pattern. |
| 2375 *negate = false; |
| 2376 return true; |
| 2377 } |
| 2378 |
| 2379 // Recognize |
| 2380 if (BindsToGivenConstant(mask_op->left(), value) || |
| 2381 BindsToGivenConstant(mask_op->right(), value)) { |
| 2382 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 |
| 2383 // so we need to negate original comparison. |
| 2384 *negate = true; |
| 2385 return true; |
| 2386 } |
| 2387 |
| 2388 return false; |
2328 } | 2389 } |
2329 | 2390 |
2330 | 2391 |
2331 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { | 2392 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { |
2332 Isolate* isolate = flow_graph->isolate(); | 2393 Isolate* isolate = flow_graph->isolate(); |
2333 // Only handle strict-compares. | 2394 // Only handle strict-compares. |
2334 if (comparison()->IsStrictCompare()) { | 2395 if (comparison()->IsStrictCompare()) { |
2335 bool negated = false; | 2396 bool negated = false; |
2336 Definition* replacement = | 2397 Definition* replacement = |
2337 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated); | 2398 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated); |
(...skipping 27 matching lines...) Expand all Loading... |
2365 } | 2426 } |
2366 // Clear the comparison's temp index and ssa temp index since the | 2427 // Clear the comparison's temp index and ssa temp index since the |
2367 // value of the comparison is not used outside the branch anymore. | 2428 // value of the comparison is not used outside the branch anymore. |
2368 ASSERT(comp->input_use_list() == NULL); | 2429 ASSERT(comp->input_use_list() == NULL); |
2369 comp->ClearSSATempIndex(); | 2430 comp->ClearSSATempIndex(); |
2370 comp->ClearTempIndex(); | 2431 comp->ClearTempIndex(); |
2371 } | 2432 } |
2372 } else if (comparison()->IsEqualityCompare() && | 2433 } else if (comparison()->IsEqualityCompare() && |
2373 comparison()->operation_cid() == kSmiCid) { | 2434 comparison()->operation_cid() == kSmiCid) { |
2374 BinarySmiOpInstr* bit_and = NULL; | 2435 BinarySmiOpInstr* bit_and = NULL; |
2375 if (RecognizeTestPattern(comparison()->left(), comparison()->right())) { | 2436 bool negate = false; |
| 2437 if (RecognizeTestPattern(comparison()->left(), |
| 2438 comparison()->right(), |
| 2439 &negate)) { |
2376 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); | 2440 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); |
2377 } else if (RecognizeTestPattern(comparison()->right(), | 2441 } else if (RecognizeTestPattern(comparison()->right(), |
2378 comparison()->left())) { | 2442 comparison()->left(), |
| 2443 &negate)) { |
2379 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); | 2444 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); |
2380 } | 2445 } |
2381 if (bit_and != NULL) { | 2446 if (bit_and != NULL) { |
2382 if (FLAG_trace_optimization) { | 2447 if (FLAG_trace_optimization) { |
2383 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); | 2448 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); |
2384 } | 2449 } |
2385 TestSmiInstr* test = new TestSmiInstr( | 2450 TestSmiInstr* test = new TestSmiInstr( |
2386 comparison()->token_pos(), | 2451 comparison()->token_pos(), |
2387 comparison()->kind(), | 2452 negate ? Token::NegateComparison(comparison()->kind()) |
| 2453 : comparison()->kind(), |
2388 bit_and->left()->Copy(isolate), | 2454 bit_and->left()->Copy(isolate), |
2389 bit_and->right()->Copy(isolate)); | 2455 bit_and->right()->Copy(isolate)); |
2390 ASSERT(!CanDeoptimize()); | 2456 ASSERT(!CanDeoptimize()); |
2391 RemoveEnvironment(); | 2457 RemoveEnvironment(); |
2392 flow_graph->CopyDeoptTarget(this, bit_and); | 2458 flow_graph->CopyDeoptTarget(this, bit_and); |
2393 SetComparison(test); | 2459 SetComparison(test); |
2394 bit_and->RemoveFromGraph(); | 2460 bit_and->RemoveFromGraph(); |
2395 } | 2461 } |
2396 } | 2462 } |
2397 return this; | 2463 return this; |
(...skipping 1122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3520 case Token::kTRUNCDIV: return 0; | 3586 case Token::kTRUNCDIV: return 0; |
3521 case Token::kMOD: return 1; | 3587 case Token::kMOD: return 1; |
3522 default: UNIMPLEMENTED(); return -1; | 3588 default: UNIMPLEMENTED(); return -1; |
3523 } | 3589 } |
3524 } | 3590 } |
3525 | 3591 |
3526 | 3592 |
3527 #undef __ | 3593 #undef __ |
3528 | 3594 |
3529 } // namespace dart | 3595 } // namespace dart |
OLD | NEW |