1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/crankshaft/hydrogen-store-elimination.h" 6 7 #include "src/crankshaft/hydrogen-instructions.h" 8 9 namespace v8 { 10 namespace internal { 11 12 #define TRACE(x) if (FLAG_trace_store_elimination) PrintF x 13 14 // Performs a block-by-block local analysis for removable stores. 15 void HStoreEliminationPhase::Run() { 16 GVNFlagSet flags; // Use GVN flags as an approximation for some instructions. 17 flags.RemoveAll(); 18 19 flags.Add(kArrayElements); 20 flags.Add(kArrayLengths); 21 flags.Add(kStringLengths); 22 flags.Add(kBackingStoreFields); 23 flags.Add(kDoubleArrayElements); 24 flags.Add(kDoubleFields); 25 flags.Add(kElementsPointer); 26 flags.Add(kInobjectFields); 27 flags.Add(kExternalMemory); 28 flags.Add(kStringChars); 29 flags.Add(kTypedArrayElements); 30 31 for (int i = 0; i < graph()->blocks()->length(); i++) { 32 unobserved_.Rewind(0); 33 HBasicBlock* block = graph()->blocks()->at(i); 34 if (!block->IsReachable()) continue; 35 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { 36 HInstruction* instr = it.Current(); 37 if (instr->CheckFlag(HValue::kIsDead)) continue; 38 39 switch (instr->opcode()) { 40 case HValue::kStoreNamedField: 41 // Remove any unobserved stores overwritten by this store. 42 ProcessStore(HStoreNamedField::cast(instr)); 43 break; 44 case HValue::kLoadNamedField: 45 // Observe any unobserved stores on this object + field. 46 ProcessLoad(HLoadNamedField::cast(instr)); 47 break; 48 default: 49 ProcessInstr(instr, flags); 50 break; 51 } 52 } 53 } 54 } 55 56 57 void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) { 58 HValue* object = store->object()->ActualValue(); 59 int i = 0; 60 while (i < unobserved_.length()) { 61 HStoreNamedField* prev = unobserved_.at(i); 62 if (aliasing_->MustAlias(object, prev->object()->ActualValue()) && 63 prev->CanBeReplacedWith(store)) { 64 // This store is guaranteed to overwrite the previous store. 65 prev->DeleteAndReplaceWith(NULL); 66 TRACE(("++ Unobserved store S%d overwritten by S%d\n", 67 prev->id(), store->id())); 68 unobserved_.Remove(i); 69 } else { 70 i++; 71 } 72 } 73 // Only non-transitioning stores are removable. 74 if (!store->has_transition()) { 75 TRACE(("-- Might remove store S%d\n", store->id())); 76 unobserved_.Add(store, zone()); 77 } 78 } 79 80 81 void HStoreEliminationPhase::ProcessLoad(HLoadNamedField* load) { 82 HValue* object = load->object()->ActualValue(); 83 int i = 0; 84 while (i < unobserved_.length()) { 85 HStoreNamedField* prev = unobserved_.at(i); 86 if (aliasing_->MayAlias(object, prev->object()->ActualValue()) && 87 load->access().Equals(prev->access())) { 88 TRACE(("-- Observed store S%d by load L%d\n", prev->id(), load->id())); 89 unobserved_.Remove(i); 90 } else { 91 i++; 92 } 93 } 94 } 95 96 97 void HStoreEliminationPhase::ProcessInstr(HInstruction* instr, 98 GVNFlagSet flags) { 99 if (unobserved_.length() == 0) return; // Nothing to do. 100 if (instr->CanDeoptimize()) { 101 TRACE(("-- Observed stores at I%d (%s might deoptimize)\n", 102 instr->id(), instr->Mnemonic())); 103 unobserved_.Rewind(0); 104 return; 105 } 106 if (instr->CheckChangesFlag(kNewSpacePromotion)) { 107 TRACE(("-- Observed stores at I%d (%s might GC)\n", 108 instr->id(), instr->Mnemonic())); 109 unobserved_.Rewind(0); 110 return; 111 } 112 if (instr->DependsOnFlags().ContainsAnyOf(flags)) { 113 TRACE(("-- Observed stores at I%d (GVN flags of %s)\n", 114 instr->id(), instr->Mnemonic())); 115 unobserved_.Rewind(0); 116 return; 117 } 118 } 119 120 } // namespace internal 121 } // namespace v8 122