| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 case NON_STRICT_ARGUMENTS_ELEMENTS: | 685 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 686 UNREACHABLE(); | 686 UNREACHABLE(); |
| 687 break; | 687 break; |
| 688 } | 688 } |
| 689 return new(zone) HStoreKeyed(external_elements, checked_key, | 689 return new(zone) HStoreKeyed(external_elements, checked_key, |
| 690 val, elements_kind); | 690 val, elements_kind); |
| 691 } else { | 691 } else { |
| 692 ASSERT(val == NULL); | 692 ASSERT(val == NULL); |
| 693 HLoadKeyed* load = | 693 HLoadKeyed* load = |
| 694 new(zone) HLoadKeyed( | 694 new(zone) HLoadKeyed( |
| 695 external_elements, checked_key, dependency, elements_kind); | 695 external_elements, checked_key, dependency, |
| 696 graph()->GetConstantUndefined(), elements_kind); |
| 696 if (FLAG_opt_safe_uint32_operations && | 697 if (FLAG_opt_safe_uint32_operations && |
| 697 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { | 698 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { |
| 698 graph()->RecordUint32Instruction(load); | 699 graph()->RecordUint32Instruction(load); |
| 699 } | 700 } |
| 700 return load; | 701 return load; |
| 701 } | 702 } |
| 702 } | 703 } |
| 703 | 704 |
| 704 | 705 |
| 705 HInstruction* HGraphBuilder::BuildFastElementAccess( | 706 HInstruction* HGraphBuilder::BuildFastElementAccess( |
| (...skipping 19 matching lines...) Expand all Loading... |
| 725 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); | 726 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); |
| 726 default: | 727 default: |
| 727 UNREACHABLE(); | 728 UNREACHABLE(); |
| 728 return NULL; | 729 return NULL; |
| 729 } | 730 } |
| 730 } | 731 } |
| 731 // It's an element load (!is_store). | 732 // It's an element load (!is_store). |
| 732 return new(zone) HLoadKeyed(elements, | 733 return new(zone) HLoadKeyed(elements, |
| 733 checked_key, | 734 checked_key, |
| 734 load_dependency, | 735 load_dependency, |
| 736 graph()->GetConstantUndefined(), |
| 735 elements_kind); | 737 elements_kind); |
| 736 } | 738 } |
| 737 | 739 |
| 738 | 740 |
| 739 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 741 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 740 HValue* object, | 742 HValue* object, |
| 741 HValue* key, | 743 HValue* key, |
| 742 HValue* val, | 744 HValue* val, |
| 743 HCheckMaps* mapcheck, | 745 HCheckMaps* mapcheck, |
| 744 bool is_js_array, | 746 bool is_js_array, |
| (...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1654 free_list_head_ = head; | 1656 free_list_head_ = head; |
| 1655 } | 1657 } |
| 1656 } else { | 1658 } else { |
| 1657 present_flags_.Add(value->gvn_flags()); // Keep it. | 1659 present_flags_.Add(value->gvn_flags()); // Keep it. |
| 1658 } | 1660 } |
| 1659 } | 1661 } |
| 1660 } | 1662 } |
| 1661 } | 1663 } |
| 1662 | 1664 |
| 1663 | 1665 |
| 1666 void HValueMap::KillAll() { |
| 1667 present_flags_.RemoveAll(); |
| 1668 |
| 1669 if (count_ == 0) return; |
| 1670 |
| 1671 for (int i = 0; i < array_size_; ++i) { |
| 1672 HValue* value = array_[i].value; |
| 1673 if (value != NULL) { |
| 1674 // Clear list of collisions first, so we know if it becomes empty. |
| 1675 int next; |
| 1676 for (int current = array_[i].next; current != kNil; current = next) { |
| 1677 next = lists_[current].next; |
| 1678 // Drop it. |
| 1679 count_--; |
| 1680 lists_[current].next = free_list_head_; |
| 1681 free_list_head_ = current; |
| 1682 } |
| 1683 array_[i].next = kNil; |
| 1684 |
| 1685 // Now drop directly indexed element. |
| 1686 count_--; |
| 1687 array_[i].value = NULL; |
| 1688 } |
| 1689 } |
| 1690 ASSERT(count_ == 0); |
| 1691 } |
| 1692 |
| 1693 |
| 1664 HValue* HValueMap::Lookup(HValue* value) const { | 1694 HValue* HValueMap::Lookup(HValue* value) const { |
| 1665 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); | 1695 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); |
| 1666 uint32_t pos = Bound(hash); | 1696 uint32_t pos = Bound(hash); |
| 1667 if (array_[pos].value != NULL) { | 1697 if (array_[pos].value != NULL) { |
| 1668 if (array_[pos].value->Equals(value)) return array_[pos].value; | 1698 if (array_[pos].value->Equals(value)) return array_[pos].value; |
| 1669 int next = array_[pos].next; | 1699 int next = array_[pos].next; |
| 1670 while (next != kNil) { | 1700 while (next != kNil) { |
| 1671 if (lists_[next].value->Equals(value)) return lists_[next].value; | 1701 if (lists_[next].value->Equals(value)) return lists_[next].value; |
| 1672 next = lists_[next].next; | 1702 next = lists_[next].next; |
| 1673 } | 1703 } |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2417 dominated); | 2447 dominated); |
| 2418 successor_map->Kill(side_effects_on_all_paths); | 2448 successor_map->Kill(side_effects_on_all_paths); |
| 2419 successor_dominators->Kill(side_effects_on_all_paths); | 2449 successor_dominators->Kill(side_effects_on_all_paths); |
| 2420 } | 2450 } |
| 2421 } | 2451 } |
| 2422 current = next; | 2452 current = next; |
| 2423 } | 2453 } |
| 2424 } | 2454 } |
| 2425 | 2455 |
| 2426 | 2456 |
| 2457 class HArrayPrefetchHint BASE_EMBEDDED { |
| 2458 public: |
| 2459 explicit HArrayPrefetchHint(HGraph* graph) : |
| 2460 graph_(graph), zone_(graph->zone()), induction_vars_(4, zone_) { |
| 2461 value_map_ = new(zone_) HValueMap(zone_); |
| 2462 } |
| 2463 |
| 2464 void Analyze(); |
| 2465 |
| 2466 private: |
| 2467 class HIntInductionVar { |
| 2468 public: |
| 2469 HIntInductionVar(HValue* value, int32_t step) |
| 2470 : value_(value), step_(step) { } |
| 2471 |
| 2472 HValue* value_; |
| 2473 int32_t step_; |
| 2474 }; |
| 2475 |
| 2476 void TraceArrayPrefetchHint(const char* msg, ...); |
| 2477 HValue* LookupOrInsert(HValue* value, HInstruction* insert_place); |
| 2478 void ProcessLoopBlock(HBasicBlock* block, HBasicBlock* loop_header); |
| 2479 bool AnalyzeInductionVars(HBasicBlock* loop_header); |
| 2480 bool IsInductionVar(HValue* value, int32_t* step); |
| 2481 |
| 2482 HGraph* graph_; |
| 2483 Zone* zone_; |
| 2484 HValueMap* value_map_; |
| 2485 // A "conservative" list of the integer induction vars in the processed loop. |
| 2486 ZoneList<HIntInductionVar> induction_vars_; |
| 2487 }; |
| 2488 |
| 2489 |
| 2490 void HArrayPrefetchHint::TraceArrayPrefetchHint(const char* msg, ...) { |
| 2491 if (FLAG_trace_prefetch_hint) { |
| 2492 va_list arguments; |
| 2493 va_start(arguments, msg); |
| 2494 OS::VPrint(msg, arguments); |
| 2495 va_end(arguments); |
| 2496 } |
| 2497 } |
| 2498 |
| 2499 |
| 2500 // Implement a naive CSE for the newly generated instructions during the |
| 2501 // Array prefetch hint phase which is performed after GVN/LICM because |
| 2502 // it depends on LICM to generate more "obvious" loop invariants. |
| 2503 // Alternatively, if we perform the array prefetch hint phase before GVN/LICM, |
| 2504 // we don't need this trick but we may be not catching some cases with |
| 2505 // non-obvious loop invariants, as we don't want to perform similar expensive |
| 2506 // analysis as LICM does. |
| 2507 // Performing iterative GVN (like GVN->Array prefetch hints->GVN) is too |
| 2508 // overkill to be considered. |
| 2509 HValue* HArrayPrefetchHint::LookupOrInsert(HValue* value, |
| 2510 HInstruction* insert_place) { |
| 2511 ASSERT(value->IsInstruction()); |
| 2512 HValue* cached = value_map_->Lookup(value); |
| 2513 if (cached == NULL) { |
| 2514 HInstruction* instr = HInstruction::cast(value); |
| 2515 instr->InsertBefore(insert_place); |
| 2516 value_map_->Add(instr, zone_); |
| 2517 cached = value; |
| 2518 } |
| 2519 return cached; |
| 2520 } |
| 2521 |
| 2522 |
| 2523 bool HArrayPrefetchHint::IsInductionVar(HValue* value, int32_t* step) { |
| 2524 for (int i = 0; i < induction_vars_.length(); i++) { |
| 2525 if (induction_vars_[i].value_ == value) { |
| 2526 *step = induction_vars_[i].step_; |
| 2527 return true; |
| 2528 } |
| 2529 } |
| 2530 return false; |
| 2531 } |
| 2532 |
| 2533 |
| 2534 bool HArrayPrefetchHint::AnalyzeInductionVars(HBasicBlock* loop_header) { |
| 2535 induction_vars_.Clear(); |
| 2536 |
| 2537 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
| 2538 for (int i = 0; i < loop_header->phis()->length(); i++) { |
| 2539 HPhi* phi = loop_header->phis()->at(i); |
| 2540 // Only consider the obvious induction variables because |
| 2541 // we really don't want to perform expensive analysis here. |
| 2542 if (phi->OperandCount() == 2 && |
| 2543 !phi->OperandAt(0)->IsDefinedAfter(pre_header) && |
| 2544 phi->representation().IsInteger32()) { |
| 2545 HValue* var_update = phi->OperandAt(1); |
| 2546 // We only consider the "linear" integer induction variable for now. |
| 2547 if (var_update->IsAdd() || var_update->IsSub()) { |
| 2548 HValue* left_value = HBinaryOperation::cast(var_update)->left(); |
| 2549 HValue* right_value = HBinaryOperation::cast(var_update)->right(); |
| 2550 int32_t step_value = 0; |
| 2551 |
| 2552 if (left_value == phi && right_value->IsConstant()) { |
| 2553 // The most common cases, like "i++" or "i--". |
| 2554 step_value = HConstant::cast(right_value)->Integer32Value(); |
| 2555 if (var_update->IsSub()) step_value = -step_value; |
| 2556 } else if (var_update->IsAdd() && |
| 2557 left_value->IsConstant() && right_value == phi) { |
| 2558 // Abnormal things like "i = 1 + i". |
| 2559 step_value = HConstant::cast(left_value)->Integer32Value(); |
| 2560 } |
| 2561 |
| 2562 if (step_value != 0) { |
| 2563 induction_vars_.Add(HIntInductionVar(phi, step_value), zone_); |
| 2564 TraceArrayPrefetchHint( |
| 2565 "Found linear integer induction variable for B%d: %d, step: %d\n", |
| 2566 loop_header->block_id(), phi->id(), step_value); |
| 2567 } |
| 2568 } |
| 2569 } |
| 2570 } |
| 2571 |
| 2572 return (induction_vars_.length() > 0); |
| 2573 } |
| 2574 |
| 2575 |
| 2576 void HArrayPrefetchHint::ProcessLoopBlock( |
| 2577 HBasicBlock* block, HBasicBlock* loop_header) { |
| 2578 |
| 2579 TraceArrayPrefetchHint("Array prefetch hint for B%d\n", |
| 2580 block->block_id()); |
| 2581 |
| 2582 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
| 2583 HInstruction* instr = block->first(); |
| 2584 while (instr != NULL) { |
| 2585 HInstruction* next = instr->next(); |
| 2586 // TODO(yxian): Probably use a kUseArrayPrefetchHint flag if there are |
| 2587 // other kinds of instructions to be taken in. |
| 2588 if (instr->IsLoadKeyed()) { |
| 2589 int32_t step_value = 0; |
| 2590 TraceArrayPrefetchHint("Checking instruction %d (%s)\n", |
| 2591 instr->id(), |
| 2592 instr->Mnemonic()); |
| 2593 HValue* key = HLoadKeyed::cast(instr)->key(); |
| 2594 if (key->IsBoundsCheck()) key = HBoundsCheck::cast(key)->index(); |
| 2595 HValue* prefetch_distance = NULL; |
| 2596 bool new_instr = true; |
| 2597 if (IsInductionVar(key, &step_value)) { |
| 2598 prefetch_distance = new(zone_) |
| 2599 HConstant(step_value, Representation::Integer32()); |
| 2600 } else if (key->representation().IsInteger32() && |
| 2601 (key->IsAdd() || key->IsSub() || key->IsMul() || key->IsDiv())) { |
| 2602 HBinaryOperation* arith = HBinaryOperation::cast(key); |
| 2603 HValue* left = arith->left(); |
| 2604 HValue* right = arith->right(); |
| 2605 HValue* invariant = NULL; |
| 2606 |
| 2607 if (IsInductionVar(left, &step_value) && |
| 2608 !right->IsDefinedAfter(pre_header)) { |
| 2609 invariant = right; |
| 2610 } else if (IsInductionVar(right, &step_value) && |
| 2611 !left->IsDefinedAfter(pre_header)) { |
| 2612 invariant = left; |
| 2613 } |
| 2614 |
| 2615 if (invariant != NULL) { |
| 2616 if (key->IsAdd()) { |
| 2617 prefetch_distance = new(zone_) |
| 2618 HConstant(step_value, Representation::Integer32()); |
| 2619 } else if (key->IsSub()) { |
| 2620 int32_t distance = invariant == left ? -step_value : step_value; |
| 2621 prefetch_distance = new(zone_) |
| 2622 HConstant(distance, Representation::Integer32()); |
| 2623 } else if (key->IsMul()) { |
| 2624 // If the step_value is 1, we should just use the |
| 2625 // "invariant" as the distance instead of creating new instr. |
| 2626 if (step_value == 1) { |
| 2627 prefetch_distance = invariant; |
| 2628 new_instr = false; |
| 2629 } else if (invariant->IsConstant()) { |
| 2630 prefetch_distance = new(zone_) HConstant( |
| 2631 step_value * HConstant::cast(invariant)->Integer32Value(), |
| 2632 Representation::Integer32()); |
| 2633 } else { |
| 2634 HValue* step = new(zone_) |
| 2635 HConstant(step_value, Representation::Integer32()); |
| 2636 step = LookupOrInsert(step, pre_header->end()); |
| 2637 prefetch_distance = new(zone_) |
| 2638 HMul(arith->context(), invariant, step); |
| 2639 // This is definitely an integer32. As we perform this phase |
| 2640 // after the representation inference phase, we need to specify |
| 2641 // it explicitly. |
| 2642 prefetch_distance-> |
| 2643 ChangeRepresentation(Representation::Integer32()); |
| 2644 } |
| 2645 } |
| 2646 } |
| 2647 } |
| 2648 |
| 2649 if (prefetch_distance != NULL) { |
| 2650 if (new_instr) { |
| 2651 prefetch_distance = LookupOrInsert( |
| 2652 prefetch_distance, pre_header->end()); |
| 2653 } |
| 2654 |
| 2655 TraceArrayPrefetchHint( |
| 2656 "Inserting array prefetching hint for instruction %d: %d\n", |
| 2657 instr->id(), prefetch_distance->id()); |
| 2658 HLoadKeyed::cast(instr)->SetPrefetchDistance(prefetch_distance); |
| 2659 } |
| 2660 } |
| 2661 instr = next; |
| 2662 } |
| 2663 } |
| 2664 |
| 2665 |
| 2666 void HArrayPrefetchHint::Analyze() { |
| 2667 HPhase phase("H_Insert Array prefetching hints", graph_); |
| 2668 |
| 2669 for (int i = 0; i < graph_->blocks()->length(); ++i) { |
| 2670 HBasicBlock* block = graph_->blocks()->at(i); |
| 2671 if (block->IsLoopHeader() && AnalyzeInductionVars(block)) { |
| 2672 TraceArrayPrefetchHint("Try array prefetch hint for block B%d\n", |
| 2673 block->block_id()); |
| 2674 value_map_->KillAll(); |
| 2675 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); |
| 2676 for (int j = block->block_id(); j <= last->block_id(); ++j) { |
| 2677 ProcessLoopBlock(graph_->blocks()->at(j), block); |
| 2678 } |
| 2679 } |
| 2680 } |
| 2681 } |
| 2682 |
| 2683 |
| 2427 void HInferRepresentation::AddToWorklist(HValue* current) { | 2684 void HInferRepresentation::AddToWorklist(HValue* current) { |
| 2428 if (current->representation().IsTagged()) return; | 2685 if (current->representation().IsTagged()) return; |
| 2429 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; | 2686 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; |
| 2430 if (in_worklist_.Contains(current->id())) return; | 2687 if (in_worklist_.Contains(current->id())) return; |
| 2431 worklist_.Add(current, zone()); | 2688 worklist_.Add(current, zone()); |
| 2432 in_worklist_.Add(current->id()); | 2689 in_worklist_.Add(current->id()); |
| 2433 } | 2690 } |
| 2434 | 2691 |
| 2435 | 2692 |
| 2436 void HInferRepresentation::Analyze() { | 2693 void HInferRepresentation::Analyze() { |
| (...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3486 bool removed_side_effects = gvn.Analyze(); | 3743 bool removed_side_effects = gvn.Analyze(); |
| 3487 // Trigger a second analysis pass to further eliminate duplicate values that | 3744 // Trigger a second analysis pass to further eliminate duplicate values that |
| 3488 // could only be discovered by removing side-effect-generating instructions | 3745 // could only be discovered by removing side-effect-generating instructions |
| 3489 // during the first pass. | 3746 // during the first pass. |
| 3490 if (FLAG_smi_only_arrays && removed_side_effects) { | 3747 if (FLAG_smi_only_arrays && removed_side_effects) { |
| 3491 removed_side_effects = gvn.Analyze(); | 3748 removed_side_effects = gvn.Analyze(); |
| 3492 ASSERT(!removed_side_effects); | 3749 ASSERT(!removed_side_effects); |
| 3493 } | 3750 } |
| 3494 } | 3751 } |
| 3495 | 3752 |
| 3753 if (FLAG_array_prefetch_hint) { |
| 3754 HArrayPrefetchHint arrayPrefetchHint(this); |
| 3755 arrayPrefetchHint.Analyze(); |
| 3756 } |
| 3757 |
| 3496 if (FLAG_use_range) { | 3758 if (FLAG_use_range) { |
| 3497 HRangeAnalysis rangeAnalysis(this); | 3759 HRangeAnalysis rangeAnalysis(this); |
| 3498 rangeAnalysis.Analyze(); | 3760 rangeAnalysis.Analyze(); |
| 3499 } | 3761 } |
| 3500 ComputeMinusZeroChecks(); | 3762 ComputeMinusZeroChecks(); |
| 3501 | 3763 |
| 3502 // Eliminate redundant stack checks on backwards branches. | 3764 // Eliminate redundant stack checks on backwards branches. |
| 3503 HStackCheckEliminator sce(this); | 3765 HStackCheckEliminator sce(this); |
| 3504 sce.Process(); | 3766 sce.Process(); |
| 3505 | 3767 |
| (...skipping 1256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4762 set_current_block(loop_successor); | 5024 set_current_block(loop_successor); |
| 4763 Drop(5); | 5025 Drop(5); |
| 4764 | 5026 |
| 4765 set_current_block(loop_body); | 5027 set_current_block(loop_body); |
| 4766 | 5028 |
| 4767 HValue* key = AddInstruction( | 5029 HValue* key = AddInstruction( |
| 4768 new(zone()) HLoadKeyed( | 5030 new(zone()) HLoadKeyed( |
| 4769 environment()->ExpressionStackAt(2), // Enum cache. | 5031 environment()->ExpressionStackAt(2), // Enum cache. |
| 4770 environment()->ExpressionStackAt(0), // Iteration index. | 5032 environment()->ExpressionStackAt(0), // Iteration index. |
| 4771 environment()->ExpressionStackAt(0), | 5033 environment()->ExpressionStackAt(0), |
| 5034 graph()->GetConstantUndefined(), |
| 4772 FAST_ELEMENTS)); | 5035 FAST_ELEMENTS)); |
| 4773 | 5036 |
| 4774 // Check if the expected map still matches that of the enumerable. | 5037 // Check if the expected map still matches that of the enumerable. |
| 4775 // If not just deoptimize. | 5038 // If not just deoptimize. |
| 4776 AddInstruction(new(zone()) HCheckMapValue( | 5039 AddInstruction(new(zone()) HCheckMapValue( |
| 4777 environment()->ExpressionStackAt(4), | 5040 environment()->ExpressionStackAt(4), |
| 4778 environment()->ExpressionStackAt(3))); | 5041 environment()->ExpressionStackAt(3))); |
| 4779 | 5042 |
| 4780 Bind(each_var, key); | 5043 Bind(each_var, key); |
| 4781 | 5044 |
| (...skipping 5418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10200 } | 10463 } |
| 10201 } | 10464 } |
| 10202 | 10465 |
| 10203 #ifdef DEBUG | 10466 #ifdef DEBUG |
| 10204 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10467 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10205 if (allocator_ != NULL) allocator_->Verify(); | 10468 if (allocator_ != NULL) allocator_->Verify(); |
| 10206 #endif | 10469 #endif |
| 10207 } | 10470 } |
| 10208 | 10471 |
| 10209 } } // namespace v8::internal | 10472 } } // namespace v8::internal |
| OLD | NEW |