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

Side by Side 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 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 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 free_list_head_ = head; 1474 free_list_head_ = head;
1475 } 1475 }
1476 } else { 1476 } else {
1477 present_flags_.Add(value->gvn_flags()); // Keep it. 1477 present_flags_.Add(value->gvn_flags()); // Keep it.
1478 } 1478 }
1479 } 1479 }
1480 } 1480 }
1481 } 1481 }
1482 1482
1483 1483
1484 void HValueMap::KillAll() {
1485 present_flags_.RemoveAll();
1486
1487 if (count_ == 0) return;
1488
1489 for (int i = 0; i < array_size_; ++i) {
1490 HValue* value = array_[i].value;
1491 if (value != NULL) {
1492 // Clear list of collisions first, so we know if it becomes empty.
1493 int next;
1494 for (int current = array_[i].next; current != kNil; current = next) {
1495 next = lists_[current].next;
1496 // Drop it.
1497 count_--;
1498 lists_[current].next = free_list_head_;
1499 free_list_head_ = current;
1500 }
1501 array_[i].next = kNil;
1502
1503 // Now drop directly indexed element.
1504 count_--;
1505 array_[i].value = NULL;
1506 }
1507 }
1508 ASSERT(count_ == 0);
1509 }
1510
1511
1484 HValue* HValueMap::Lookup(HValue* value) const { 1512 HValue* HValueMap::Lookup(HValue* value) const {
1485 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); 1513 uint32_t hash = static_cast<uint32_t>(value->Hashcode());
1486 uint32_t pos = Bound(hash); 1514 uint32_t pos = Bound(hash);
1487 if (array_[pos].value != NULL) { 1515 if (array_[pos].value != NULL) {
1488 if (array_[pos].value->Equals(value)) return array_[pos].value; 1516 if (array_[pos].value->Equals(value)) return array_[pos].value;
1489 int next = array_[pos].next; 1517 int next = array_[pos].next;
1490 while (next != kNil) { 1518 while (next != kNil) {
1491 if (lists_[next].value->Equals(value)) return lists_[next].value; 1519 if (lists_[next].value->Equals(value)) return lists_[next].value;
1492 next = lists_[next].next; 1520 next = lists_[next].next;
1493 } 1521 }
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after
2237 dominated); 2265 dominated);
2238 successor_map->Kill(side_effects_on_all_paths); 2266 successor_map->Kill(side_effects_on_all_paths);
2239 successor_dominators->Kill(side_effects_on_all_paths); 2267 successor_dominators->Kill(side_effects_on_all_paths);
2240 } 2268 }
2241 } 2269 }
2242 current = next; 2270 current = next;
2243 } 2271 }
2244 } 2272 }
2245 2273
2246 2274
2275 class HArrayPrefetchHint BASE_EMBEDDED {
2276 public:
2277 explicit HArrayPrefetchHint(HGraph* graph) :
2278 graph_(graph), zone_(graph->zone()), induction_vars_(4, zone_) {
2279 value_map_ = new(zone_) HValueMap(zone_);
2280 }
2281
2282 void Analyze();
2283
2284 private:
2285 class HIntInductionVar {
2286 public:
2287 HIntInductionVar(HValue* value, int32_t step)
2288 : value_(value), step_(step) { }
2289
2290 HValue* value_;
2291 int32_t step_;
2292 };
2293
2294 void TraceArrayPrefetchHint(const char* msg, ...);
2295 HValue* LookupOrInsert(HValue* value, HInstruction* insert_place);
2296 void ProcessLoopBlock(HBasicBlock* block, HBasicBlock* loop_header);
2297 bool AnalyzeInductionVars(HBasicBlock* loop_header);
2298 bool IsInductionVar(HValue* value, int32_t* step);
2299
2300 HGraph* graph_;
2301 Zone* zone_;
2302 HValueMap* value_map_;
2303 // A "conservative" list of the integer induction vars in the processed loop.
2304 ZoneList<HIntInductionVar> induction_vars_;
2305 };
2306
2307
2308 void HArrayPrefetchHint::TraceArrayPrefetchHint(const char* msg, ...) {
2309 if (FLAG_trace_prefetch_hint) {
2310 va_list arguments;
2311 va_start(arguments, msg);
2312 OS::VPrint(msg, arguments);
2313 va_end(arguments);
2314 }
2315 }
2316
2317
2318 // Implement a naive CSE for the newly generated instructions during the
2319 // Array prefetch hint phase which is performed after GVN/LICM because
2320 // it depends on LICM to generate more "obvious" loop invariants.
2321 // Alternatively, if we perform the array prefetch hint phase before GVN/LICM,
2322 // we don't need this trick but we may be not catching some cases with
2323 // non-obvious loop invariants, as we don't want to perform similar expensive
2324 // analysis as LICM does.
2325 // Performing iterative GVN (like GVN->Array prefetch hints->GVN) is too
2326 // overkill to be considered.
2327 HValue* HArrayPrefetchHint::LookupOrInsert(HValue* value,
2328 HInstruction* insert_place) {
2329 ASSERT(value->IsInstruction());
2330 HValue* cached = value_map_->Lookup(value);
2331 if (cached == NULL) {
2332 HInstruction* instr = HInstruction::cast(value);
2333 instr->InsertBefore(insert_place);
2334 value_map_->Add(instr, zone_);
2335 cached = value;
2336 }
2337 return cached;
2338 }
2339
2340
2341 bool HArrayPrefetchHint::IsInductionVar(HValue* value, int32_t* step) {
2342 for (int i = 0; i < induction_vars_.length(); i++) {
2343 if (induction_vars_[i].value_ == value) {
2344 *step = induction_vars_[i].step_;
2345 return true;
2346 }
2347 }
2348 return false;
2349 }
2350
2351
2352 bool HArrayPrefetchHint::AnalyzeInductionVars(HBasicBlock* loop_header) {
2353 induction_vars_.Clear();
2354
2355 HBasicBlock* pre_header = loop_header->predecessors()->at(0);
2356 for (int i = 0; i < loop_header->phis()->length(); i++) {
2357 HPhi* phi = loop_header->phis()->at(i);
2358 // Only consider the obvious induction variables because
2359 // we really don't want to perform expensive analysis here.
2360 if (phi->OperandCount() == 2 &&
2361 !phi->OperandAt(0)->IsDefinedAfter(pre_header) &&
2362 phi->representation().IsInteger32()) {
2363 HValue* var_update = phi->OperandAt(1);
2364 // We only consider the "linear" integer induction variable for now.
2365 if (var_update->IsAdd() || var_update->IsSub()) {
2366 HValue* left_value = HBinaryOperation::cast(var_update)->left();
2367 HValue* right_value = HBinaryOperation::cast(var_update)->right();
2368 int32_t step_value = 0;
2369
2370 if (left_value == phi && right_value->IsConstant()) {
2371 // The most common cases, like "i++" or "i--".
2372 step_value = HConstant::cast(right_value)->Integer32Value();
2373 if (var_update->IsSub()) step_value = -step_value;
2374 } else if (var_update->IsAdd() &&
2375 left_value->IsConstant() && right_value == phi) {
2376 // Abnormal things like "i = 1 + i".
2377 step_value = HConstant::cast(left_value)->Integer32Value();
2378 }
2379
2380 if (step_value != 0) {
2381 induction_vars_.Add(HIntInductionVar(phi, step_value), zone_);
2382 TraceArrayPrefetchHint(
2383 "Found linear integer induction variable for B%d: %d, step: %d\n",
2384 loop_header->block_id(), phi->id(), step_value);
2385 }
2386 }
2387 }
2388 }
2389
2390 return (induction_vars_.length() > 0);
2391 }
2392
2393
2394 void HArrayPrefetchHint::ProcessLoopBlock(
2395 HBasicBlock* block, HBasicBlock* loop_header) {
2396
2397 TraceArrayPrefetchHint("Array prefetch hint for B%d\n",
2398 block->block_id());
2399
2400 HBasicBlock* pre_header = loop_header->predecessors()->at(0);
2401 HInstruction* instr = block->first();
2402 while (instr != NULL) {
2403 HInstruction* next = instr->next();
2404 // TODO(yxian): Probably use a kUseArrayPrefetchHint flag if there are
2405 // other kinds of instructions to be taken in.
2406 if (instr->IsLoadKeyed()) {
2407 int32_t step_value = 0;
2408 TraceArrayPrefetchHint("Checking instruction %d (%s)\n",
2409 instr->id(),
2410 instr->Mnemonic());
2411 HValue* key = HLoadKeyed::cast(instr)->key();
2412 if (key->IsBoundsCheck()) key = HBoundsCheck::cast(key)->index();
2413 HValue* prefetch_distance = NULL;
2414 bool new_instr = true;
2415 if (IsInductionVar(key, &step_value)) {
2416 prefetch_distance = new(zone_)
2417 HConstant(step_value, Representation::Integer32());
2418 } else if (key->representation().IsInteger32() &&
2419 (key->IsAdd() || key->IsSub() || key->IsMul() || key->IsDiv())) {
2420 HBinaryOperation* arith = HBinaryOperation::cast(key);
2421 HValue* left = arith->left();
2422 HValue* right = arith->right();
2423 HValue* invariant = NULL;
2424
2425 if (IsInductionVar(left, &step_value) &&
2426 !right->IsDefinedAfter(pre_header)) {
2427 invariant = right;
2428 } else if (IsInductionVar(right, &step_value) &&
2429 !left->IsDefinedAfter(pre_header)) {
2430 invariant = left;
2431 }
2432
2433 if (invariant != NULL) {
2434 if (key->IsAdd()) {
2435 prefetch_distance = new(zone_)
2436 HConstant(step_value, Representation::Integer32());
2437 } else if (key->IsSub()) {
2438 int32_t distance = invariant == left ? -step_value : step_value;
2439 prefetch_distance = new(zone_)
2440 HConstant(distance, Representation::Integer32());
2441 } else if (key->IsMul()) {
2442 // If the step_value is 1, we should just use the
2443 // "invariant" as the distance instead of creating new instr.
2444 if (step_value == 1) {
2445 prefetch_distance = invariant;
2446 new_instr = false;
2447 } else if (invariant->IsConstant()) {
2448 prefetch_distance = new(zone_) HConstant(
2449 step_value * HConstant::cast(invariant)->Integer32Value(),
2450 Representation::Integer32());
2451 } else {
2452 HValue* step = new(zone_)
2453 HConstant(step_value, Representation::Integer32());
2454 step = LookupOrInsert(step, pre_header->end());
2455 prefetch_distance = new(zone_)
2456 HMul(arith->context(), invariant, step);
2457 // This is definitely an integer32. As we perform this phase
2458 // after the representation inference phase, we need to specify
2459 // it explicitly.
2460 prefetch_distance->
2461 ChangeRepresentation(Representation::Integer32());
2462 }
2463 }
2464 }
2465 }
2466
2467 if (prefetch_distance != NULL) {
2468 if (new_instr) {
2469 prefetch_distance = LookupOrInsert(
2470 prefetch_distance, pre_header->end());
2471 }
2472
2473 TraceArrayPrefetchHint(
2474 "Inserting array prefetching hint for instruction %d: %d\n",
2475 instr->id(), prefetch_distance->id());
2476 HLoadKeyed::cast(instr)->SetPrefetchDistance(prefetch_distance);
2477 }
2478 }
2479 instr = next;
2480 }
2481 }
2482
2483
2484 void HArrayPrefetchHint::Analyze() {
2485 HPhase phase("H_Insert Array prefetching hints", graph_);
2486
2487 for (int i = 0; i < graph_->blocks()->length(); ++i) {
2488 HBasicBlock* block = graph_->blocks()->at(i);
2489 if (block->IsLoopHeader() && AnalyzeInductionVars(block)) {
2490 TraceArrayPrefetchHint("Try array prefetch hint for block B%d\n",
2491 block->block_id());
2492 value_map_->KillAll();
2493 HBasicBlock* last = block->loop_information()->GetLastBackEdge();
2494 for (int j = block->block_id(); j <= last->block_id(); ++j) {
2495 ProcessLoopBlock(graph_->blocks()->at(j), block);
2496 }
2497 }
2498 }
2499 }
2500
2501
2247 void HInferRepresentation::AddToWorklist(HValue* current) { 2502 void HInferRepresentation::AddToWorklist(HValue* current) {
2248 if (current->representation().IsTagged()) return; 2503 if (current->representation().IsTagged()) return;
2249 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; 2504 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
2250 if (in_worklist_.Contains(current->id())) return; 2505 if (in_worklist_.Contains(current->id())) return;
2251 worklist_.Add(current, zone()); 2506 worklist_.Add(current, zone());
2252 in_worklist_.Add(current->id()); 2507 in_worklist_.Add(current->id());
2253 } 2508 }
2254 2509
2255 2510
2256 void HInferRepresentation::Analyze() { 2511 void HInferRepresentation::Analyze() {
(...skipping 1052 matching lines...) Expand 10 before | Expand all | Expand 10 after
3309 bool removed_side_effects = gvn.Analyze(); 3564 bool removed_side_effects = gvn.Analyze();
3310 // Trigger a second analysis pass to further eliminate duplicate values that 3565 // Trigger a second analysis pass to further eliminate duplicate values that
3311 // could only be discovered by removing side-effect-generating instructions 3566 // could only be discovered by removing side-effect-generating instructions
3312 // during the first pass. 3567 // during the first pass.
3313 if (FLAG_smi_only_arrays && removed_side_effects) { 3568 if (FLAG_smi_only_arrays && removed_side_effects) {
3314 removed_side_effects = gvn.Analyze(); 3569 removed_side_effects = gvn.Analyze();
3315 ASSERT(!removed_side_effects); 3570 ASSERT(!removed_side_effects);
3316 } 3571 }
3317 } 3572 }
3318 3573
3574 if (FLAG_array_prefetch_hint) {
3575 HArrayPrefetchHint arrayPrefetchHint(this);
3576 arrayPrefetchHint.Analyze();
3577 }
3578
3319 if (FLAG_use_range) { 3579 if (FLAG_use_range) {
3320 HRangeAnalysis rangeAnalysis(this); 3580 HRangeAnalysis rangeAnalysis(this);
3321 rangeAnalysis.Analyze(); 3581 rangeAnalysis.Analyze();
3322 } 3582 }
3323 ComputeMinusZeroChecks(); 3583 ComputeMinusZeroChecks();
3324 3584
3325 // Eliminate redundant stack checks on backwards branches. 3585 // Eliminate redundant stack checks on backwards branches.
3326 HStackCheckEliminator sce(this); 3586 HStackCheckEliminator sce(this);
3327 sce.Process(); 3587 sce.Process();
3328 3588
(...skipping 1241 matching lines...) Expand 10 before | Expand all | Expand 10 after
4570 set_current_block(loop_successor); 4830 set_current_block(loop_successor);
4571 Drop(5); 4831 Drop(5);
4572 4832
4573 set_current_block(loop_body); 4833 set_current_block(loop_body);
4574 4834
4575 HValue* key = AddInstruction( 4835 HValue* key = AddInstruction(
4576 new(zone()) HLoadKeyed( 4836 new(zone()) HLoadKeyed(
4577 environment()->ExpressionStackAt(2), // Enum cache. 4837 environment()->ExpressionStackAt(2), // Enum cache.
4578 environment()->ExpressionStackAt(0), // Iteration index. 4838 environment()->ExpressionStackAt(0), // Iteration index.
4579 environment()->ExpressionStackAt(0), 4839 environment()->ExpressionStackAt(0),
4840 graph()->GetConstantUndefined(),
4580 FAST_ELEMENTS)); 4841 FAST_ELEMENTS));
4581 4842
4582 // Check if the expected map still matches that of the enumerable. 4843 // Check if the expected map still matches that of the enumerable.
4583 // If not just deoptimize. 4844 // If not just deoptimize.
4584 AddInstruction(new(zone()) HCheckMapValue( 4845 AddInstruction(new(zone()) HCheckMapValue(
4585 environment()->ExpressionStackAt(4), 4846 environment()->ExpressionStackAt(4),
4586 environment()->ExpressionStackAt(3))); 4847 environment()->ExpressionStackAt(3)));
4587 4848
4588 Bind(each_var, key); 4849 Bind(each_var, key);
4589 4850
(...skipping 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after
6053 break; 6314 break;
6054 } 6315 }
6055 return new(zone()) HStoreKeyed(external_elements, 6316 return new(zone()) HStoreKeyed(external_elements,
6056 checked_key, 6317 checked_key,
6057 val, 6318 val,
6058 elements_kind); 6319 elements_kind);
6059 } else { 6320 } else {
6060 ASSERT(val == NULL); 6321 ASSERT(val == NULL);
6061 HLoadKeyed* load = 6322 HLoadKeyed* load =
6062 new(zone()) HLoadKeyed( 6323 new(zone()) HLoadKeyed(
6063 external_elements, checked_key, dependency, elements_kind); 6324 external_elements, checked_key, dependency,
6325 graph()->GetConstantUndefined(), elements_kind);
6064 if (FLAG_opt_safe_uint32_operations && 6326 if (FLAG_opt_safe_uint32_operations &&
6065 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6327 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
6066 graph()->RecordUint32Instruction(load); 6328 graph()->RecordUint32Instruction(load);
6067 } 6329 }
6068 return load; 6330 return load;
6069 } 6331 }
6070 } 6332 }
6071 6333
6072 6334
6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, 6335 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
(...skipping 18 matching lines...) Expand all
6092 elements, checked_key, val, elements_kind); 6354 elements, checked_key, val, elements_kind);
6093 default: 6355 default:
6094 UNREACHABLE(); 6356 UNREACHABLE();
6095 return NULL; 6357 return NULL;
6096 } 6358 }
6097 } 6359 }
6098 // It's an element load (!is_store). 6360 // It's an element load (!is_store).
6099 return new(zone()) HLoadKeyed(elements, 6361 return new(zone()) HLoadKeyed(elements,
6100 checked_key, 6362 checked_key,
6101 load_dependency, 6363 load_dependency,
6364 graph()->GetConstantUndefined(),
6102 elements_kind); 6365 elements_kind);
6103 } 6366 }
6104 6367
6105 6368
6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 6369 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
6107 HValue* key, 6370 HValue* key,
6108 HValue* val, 6371 HValue* val,
6109 HValue* dependency, 6372 HValue* dependency,
6110 Handle<Map> map, 6373 Handle<Map> map,
6111 bool is_store) { 6374 bool is_store) {
(...skipping 3947 matching lines...) Expand 10 before | Expand all | Expand 10 after
10059 } 10322 }
10060 } 10323 }
10061 10324
10062 #ifdef DEBUG 10325 #ifdef DEBUG
10063 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10326 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10064 if (allocator_ != NULL) allocator_->Verify(); 10327 if (allocator_ != NULL) allocator_->Verify();
10065 #endif 10328 #endif
10066 } 10329 }
10067 10330
10068 } } // namespace v8::internal 10331 } } // 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