Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: src/hydrogen.cc

Issue 11411351: Implement basic array prefetching hints in Hydrogen. Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698