| 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 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |