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/hydrogen-instructions.h" 6 #include "src/hydrogen-store-elimination.h" 7 8 namespace v8 { 9 namespace internal { 10 11 #define TRACE(x) if (FLAG_trace_store_elimination) PrintF x 12 13 // Performs a block-by-block local analysis for removable stores. 14 void HStoreEliminationPhase::Run() { 15 GVNFlagSet flags; // Use GVN flags as an approximation for some instructions. 16 flags.RemoveAll(); 17 18 flags.Add(kArrayElements); 19 flags.Add(kArrayLengths); 20 flags.Add(kStringLengths); 21 flags.Add(kBackingStoreFields); 22 flags.Add(kDoubleArrayElements); 23 flags.Add(kDoubleFields); 24 flags.Add(kElementsPointer); 25 flags.Add(kInobjectFields); 26 flags.Add(kExternalMemory); 27 flags.Add(kStringChars); 28 flags.Add(kTypedArrayElements); 29 30 for (int i = 0; i < graph()->blocks()->length(); i++) { 31 unobserved_.Rewind(0); 32 HBasicBlock* block = graph()->blocks()->at(i); 33 if (!block->IsReachable()) continue; 34 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { 35 HInstruction* instr = it.Current(); 36 if (instr->CheckFlag(HValue::kIsDead)) continue; 37 38 // TODO(titzer): eliminate unobserved HStoreKeyed instructions too. 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 // TODO(titzer): remove map word clearing from folded allocations. 71 i++; 72 } 73 } 74 // Only non-transitioning stores are removable. 75 if (!store->has_transition()) { 76 TRACE(("-- Might remove store S%d\n", store->id())); 77 unobserved_.Add(store, zone()); 78 } 79 } 80 81 82 void HStoreEliminationPhase::ProcessLoad(HLoadNamedField* load) { 83 HValue* object = load->object()->ActualValue(); 84 int i = 0; 85 while (i < unobserved_.length()) { 86 HStoreNamedField* prev = unobserved_.at(i); 87 if (aliasing_->MayAlias(object, prev->object()->ActualValue()) && 88 load->access().Equals(prev->access())) { 89 TRACE(("-- Observed store S%d by load L%d\n", prev->id(), load->id())); 90 unobserved_.Remove(i); 91 } else { 92 i++; 93 } 94 } 95 } 96 97 98 void HStoreEliminationPhase::ProcessInstr(HInstruction* instr, 99 GVNFlagSet flags) { 100 if (unobserved_.length() == 0) return; // Nothing to do. 101 if (instr->CanDeoptimize()) { 102 TRACE(("-- Observed stores at I%d (%s might deoptimize)\n", 103 instr->id(), instr->Mnemonic())); 104 unobserved_.Rewind(0); 105 return; 106 } 107 if (instr->CheckChangesFlag(kNewSpacePromotion)) { 108 TRACE(("-- Observed stores at I%d (%s might GC)\n", 109 instr->id(), instr->Mnemonic())); 110 unobserved_.Rewind(0); 111 return; 112 } 113 if (instr->DependsOnFlags().ContainsAnyOf(flags)) { 114 TRACE(("-- Observed stores at I%d (GVN flags of %s)\n", 115 instr->id(), instr->Mnemonic())); 116 unobserved_.Rewind(0); 117 return; 118 } 119 } 120 121 } } // namespace v8::internal 122