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

Unified Diff: src/hydrogen.cc

Issue 11299328: Implement basic array prefetching hints in Hydrogen. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 8 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen.cc
===================================================================
--- src/hydrogen.cc (revision 13123)
+++ src/hydrogen.cc (working copy)
@@ -1481,6 +1481,34 @@
}
+void HValueMap::KillAll() {
+ present_flags_.RemoveAll();
+
+ if (count_ == 0) return;
+
+ for (int i = 0; i < array_size_; ++i) {
+ HValue* value = array_[i].value;
+ if (value != NULL) {
+ // Clear list of collisions first, so we know if it becomes empty.
+ int next;
+ for (int current = array_[i].next; current != kNil; current = next) {
+ next = lists_[current].next;
+ // Drop it.
+ count_--;
+ lists_[current].next = free_list_head_;
+ free_list_head_ = current;
+ }
+ array_[i].next = kNil;
+
+ // Now drop directly indexed element.
+ count_--;
+ array_[i].value = NULL;
+ }
+ }
+ ASSERT(count_ == 0);
+}
+
+
HValue* HValueMap::Lookup(HValue* value) const {
uint32_t hash = static_cast<uint32_t>(value->Hashcode());
uint32_t pos = Bound(hash);
@@ -2244,6 +2272,233 @@
}
+class HArrayPrefetchHint BASE_EMBEDDED {
+ public:
+ explicit HArrayPrefetchHint(HGraph* graph) :
+ graph_(graph), zone_(graph->zone()), induction_vars_(4, zone_) {
+ value_map_ = new(zone_) HValueMap(zone_);
+ }
+
+ void Analyze();
+
+ private:
+ class HIntInductionVar {
+ public:
+ HIntInductionVar(HValue* value, int32_t step)
+ : value_(value), step_(step) { }
+
+ HValue* value_;
+ int32_t step_;
+ };
+
+ void TraceArrayPrefetchHint(const char* msg, ...);
+ HValue* LookupOrInsert(HValue* value, HInstruction* insert_place);
+ void ProcessLoopBlock(HBasicBlock* block, HBasicBlock* loop_header);
+ bool AnalyzeInductionVars(HBasicBlock* loop_header);
+ bool IsInductionVar(HValue* value, int32_t* step);
+
+ HGraph* graph_;
+ Zone* zone_;
+ HValueMap* value_map_;
+ // A "conservative" list of the integer induction vars in the processed loop.
+ ZoneList<HIntInductionVar> induction_vars_;
+};
+
+
+void HArrayPrefetchHint::TraceArrayPrefetchHint(const char* msg, ...) {
+ if (FLAG_trace_prefetch_hint) {
+ va_list arguments;
+ va_start(arguments, msg);
+ OS::VPrint(msg, arguments);
+ va_end(arguments);
+ }
+}
+
+
+// Implement a naive CSE for the newly generated instructions during the
+// Array prefetch hint phase which is performed after GVN/LICM because
+// it depends on LICM to generate more "obvious" loop invariants.
+// Alternatively, if we perform the array prefetch hint phase before GVN/LICM,
+// we don't need this trick but we may be not catching some cases with
+// non-obvious loop invariants, as we don't want to perform similar expensive
+// analysis as LICM does.
+// Performing iterative GVN (like GVN->Array prefetch hints->GVN) is too
+// overkill to be considered.
+HValue* HArrayPrefetchHint::LookupOrInsert(HValue* value,
+ HInstruction* insert_place) {
+ ASSERT(value->IsInstruction());
+ HValue* cached = value_map_->Lookup(value);
+ if (cached == NULL) {
+ HInstruction* instr = HInstruction::cast(value);
+ instr->InsertBefore(insert_place);
+ value_map_->Add(instr, zone_);
+ cached = value;
+ }
+ return cached;
+}
+
+
+bool HArrayPrefetchHint::IsInductionVar(HValue* value, int32_t* step) {
+ for (int i = 0; i < induction_vars_.length(); i++) {
+ if (induction_vars_[i].value_ == value) {
+ *step = induction_vars_[i].step_;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool HArrayPrefetchHint::AnalyzeInductionVars(HBasicBlock* loop_header) {
+ induction_vars_.Clear();
+
+ HBasicBlock* pre_header = loop_header->predecessors()->at(0);
+ for (int i = 0; i < loop_header->phis()->length(); i++) {
+ HPhi* phi = loop_header->phis()->at(i);
+ // Only consider the obvious induction variables because
+ // we really don't want to perform expensive analysis here.
+ if (phi->OperandCount() == 2 &&
+ !phi->OperandAt(0)->IsDefinedAfter(pre_header) &&
+ phi->representation().IsInteger32()) {
+ HValue* var_update = phi->OperandAt(1);
+ // We only consider the "linear" integer induction variable for now.
+ if (var_update->IsAdd() || var_update->IsSub()) {
+ HValue* left_value = HBinaryOperation::cast(var_update)->left();
+ HValue* right_value = HBinaryOperation::cast(var_update)->right();
+ int32_t step_value = 0;
+
+ if (left_value == phi && right_value->IsConstant()) {
+ // The most common cases, like "i++" or "i--".
+ step_value = HConstant::cast(right_value)->Integer32Value();
+ if (var_update->IsSub()) step_value = -step_value;
+ } else if (var_update->IsAdd() &&
+ left_value->IsConstant() && right_value == phi) {
+ // Abnormal things like "i = 1 + i".
+ step_value = HConstant::cast(left_value)->Integer32Value();
+ }
+
+ if (step_value != 0) {
+ induction_vars_.Add(HIntInductionVar(phi, step_value), zone_);
+ TraceArrayPrefetchHint(
+ "Found linear integer induction variable for B%d: %d, step: %d\n",
+ loop_header->block_id(), phi->id(), step_value);
+ }
+ }
+ }
+ }
+
+ return (induction_vars_.length() > 0);
+}
+
+
+void HArrayPrefetchHint::ProcessLoopBlock(
+ HBasicBlock* block, HBasicBlock* loop_header) {
+
+ TraceArrayPrefetchHint("Array prefetch hint for B%d\n",
+ block->block_id());
+
+ HBasicBlock* pre_header = loop_header->predecessors()->at(0);
+ HInstruction* instr = block->first();
+ while (instr != NULL) {
+ HInstruction* next = instr->next();
+ // TODO(yxian): Probably use a kUseArrayPrefetchHint flag if there are
+ // other kinds of instructions to be taken in.
+ if (instr->IsLoadKeyed()) {
+ int32_t step_value = 0;
+ TraceArrayPrefetchHint("Checking instruction %d (%s)\n",
+ instr->id(),
+ instr->Mnemonic());
+ HValue* key = HLoadKeyed::cast(instr)->key();
+ if (key->IsBoundsCheck()) key = HBoundsCheck::cast(key)->index();
+ HValue* prefetch_distance = NULL;
+ bool new_instr = true;
+ if (IsInductionVar(key, &step_value)) {
+ prefetch_distance = new(zone_)
+ HConstant(step_value, Representation::Integer32());
+ } else if (key->representation().IsInteger32() &&
+ (key->IsAdd() || key->IsSub() || key->IsMul() || key->IsDiv())) {
+ HBinaryOperation* arith = HBinaryOperation::cast(key);
+ HValue* left = arith->left();
+ HValue* right = arith->right();
+ HValue* invariant = NULL;
+
+ if (IsInductionVar(left, &step_value) &&
+ !right->IsDefinedAfter(pre_header)) {
+ invariant = right;
+ } else if (IsInductionVar(right, &step_value) &&
+ !left->IsDefinedAfter(pre_header)) {
+ invariant = left;
+ }
+
+ if (invariant != NULL) {
+ if (key->IsAdd()) {
+ prefetch_distance = new(zone_)
+ HConstant(step_value, Representation::Integer32());
+ } else if (key->IsSub()) {
+ int32_t distance = invariant == left ? -step_value : step_value;
+ prefetch_distance = new(zone_)
+ HConstant(distance, Representation::Integer32());
+ } else if (key->IsMul()) {
+ // If the step_value is 1, we should just use the
+ // "invariant" as the distance instead of creating new instr.
+ if (step_value == 1) {
+ prefetch_distance = invariant;
+ new_instr = false;
+ } else if (invariant->IsConstant()) {
+ prefetch_distance = new(zone_) HConstant(
+ step_value * HConstant::cast(invariant)->Integer32Value(),
+ Representation::Integer32());
+ } else {
+ HValue* step = new(zone_)
+ HConstant(step_value, Representation::Integer32());
+ step = LookupOrInsert(step, pre_header->end());
+ prefetch_distance = new(zone_)
+ HMul(arith->context(), invariant, step);
+ // This is definitely an integer32. As we perform this phase
+ // after the representation inference phase, we need to specify
+ // it explicitly.
+ prefetch_distance->
+ ChangeRepresentation(Representation::Integer32());
+ }
+ }
+ }
+ }
+
+ if (prefetch_distance != NULL) {
+ if (new_instr) {
+ prefetch_distance = LookupOrInsert(
+ prefetch_distance, pre_header->end());
+ }
+
+ TraceArrayPrefetchHint(
+ "Inserting array prefetching hint for instruction %d: %d\n",
+ instr->id(), prefetch_distance->id());
+ HLoadKeyed::cast(instr)->SetPrefetchDistance(prefetch_distance);
+ }
+ }
+ instr = next;
+ }
+}
+
+
+void HArrayPrefetchHint::Analyze() {
+ HPhase phase("H_Insert Array prefetching hints", graph_);
+
+ for (int i = 0; i < graph_->blocks()->length(); ++i) {
+ HBasicBlock* block = graph_->blocks()->at(i);
+ if (block->IsLoopHeader() && AnalyzeInductionVars(block)) {
+ TraceArrayPrefetchHint("Try array prefetch hint for block B%d\n",
+ block->block_id());
+ value_map_->KillAll();
+ HBasicBlock* last = block->loop_information()->GetLastBackEdge();
+ for (int j = block->block_id(); j <= last->block_id(); ++j) {
+ ProcessLoopBlock(graph_->blocks()->at(j), block);
+ }
+ }
+ }
+}
+
+
void HInferRepresentation::AddToWorklist(HValue* current) {
if (current->representation().IsTagged()) return;
if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
@@ -3316,6 +3571,11 @@
}
}
+ if (FLAG_array_prefetch_hint) {
+ HArrayPrefetchHint arrayPrefetchHint(this);
+ arrayPrefetchHint.Analyze();
+ }
+
if (FLAG_use_range) {
HRangeAnalysis rangeAnalysis(this);
rangeAnalysis.Analyze();
@@ -4577,6 +4837,7 @@
environment()->ExpressionStackAt(2), // Enum cache.
environment()->ExpressionStackAt(0), // Iteration index.
environment()->ExpressionStackAt(0),
+ graph()->GetConstantUndefined(),
FAST_ELEMENTS));
// Check if the expected map still matches that of the enumerable.
@@ -6060,7 +6321,8 @@
ASSERT(val == NULL);
HLoadKeyed* load =
new(zone()) HLoadKeyed(
- external_elements, checked_key, dependency, elements_kind);
+ external_elements, checked_key, dependency,
+ graph()->GetConstantUndefined(), elements_kind);
if (FLAG_opt_safe_uint32_operations &&
elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
graph()->RecordUint32Instruction(load);
@@ -6099,6 +6361,7 @@
return new(zone()) HLoadKeyed(elements,
checked_key,
load_dependency,
+ graph()->GetConstantUndefined(),
elements_kind);
}
« 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