Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the above copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the above | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | |
| 28 #include "hydrogen-store-elimination.h" | |
| 29 #include "hydrogen-instructions.h" | |
| 30 | |
| 31 namespace v8 { | |
| 32 namespace internal { | |
| 33 | |
| 34 #define TRACE(x) if (FLAG_trace_store_elimination) PrintF x | |
| 35 | |
| 36 // Performs a block-by-block local analysis for removable stores. | |
| 37 void HStoreEliminationPhase::Run() { | |
| 38 GVNFlagSet flags; // Use GVN flags as an approximation for some instructions. | |
| 39 flags.RemoveAll(); | |
| 40 | |
| 41 flags.Add(kDependsOnArrayElements); | |
| 42 flags.Add(kDependsOnArrayLengths); | |
| 43 flags.Add(kDependsOnStringLengths); | |
| 44 flags.Add(kDependsOnBackingStoreFields); | |
| 45 flags.Add(kDependsOnDoubleArrayElements); | |
| 46 flags.Add(kDependsOnDoubleFields); | |
| 47 flags.Add(kDependsOnElementsPointer); | |
| 48 flags.Add(kDependsOnInobjectFields); | |
| 49 flags.Add(kDependsOnExternalMemory); | |
| 50 | |
| 51 for (int i = 0; i < graph()->blocks()->length(); i++) { | |
| 52 unobserved_.Rewind(0); | |
| 53 HBasicBlock* block = graph()->blocks()->at(i); | |
| 54 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 55 HInstruction* instr = it.Current(); | |
| 56 | |
| 57 switch (instr->opcode()) { | |
| 58 case HValue::kStoreNamedField: | |
|
Hannes Payer (out of office)
2014/01/16 15:25:21
Can we also have that for keyed stores? Leave a TO
| |
| 59 // Remove any unobserved stores overwritten by this store. | |
| 60 ProcessStore(HStoreNamedField::cast(instr)); | |
| 61 break; | |
| 62 case HValue::kLoadNamedField: | |
| 63 // Observe any unobserved stores on this object + field. | |
| 64 ProcessLoad(HLoadNamedField::cast(instr)); | |
| 65 break; | |
| 66 default: | |
| 67 ProcessInstr(instr, flags); | |
| 68 break; | |
| 69 } | |
| 70 } | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 | |
| 75 void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) { | |
| 76 HValue* object = store->object()->ActualValue(); | |
| 77 int i = 0; | |
| 78 while (i < unobserved_.length()) { | |
| 79 HStoreNamedField* prev = unobserved_.at(i); | |
| 80 if (aliasing_->MustAlias(object, prev->object()->ActualValue()) && | |
| 81 store->access().Equals(prev->access())) { | |
| 82 // This store is guaranteed to overwrite the previous store. | |
| 83 prev->DeleteAndReplaceWith(NULL); | |
| 84 TRACE(("++ Unobserved store S%d overwritten by S%d\n", | |
| 85 prev->id(), store->id())); | |
| 86 unobserved_.Remove(i); | |
| 87 } else { | |
| 88 // TODO(titzer): remove map word clearing from folded allocations. | |
| 89 i++; | |
| 90 } | |
| 91 } | |
| 92 // Only non-transitioning stores are removable. | |
| 93 if (!store->has_transition()) { | |
| 94 TRACE(("-- Might remove store S%d\n", store->id())); | |
| 95 unobserved_.Add(store, zone()); | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 | |
| 100 void HStoreEliminationPhase::ProcessLoad(HLoadNamedField* load) { | |
| 101 HValue* object = load->object()->ActualValue(); | |
| 102 int i = 0; | |
| 103 while (i < unobserved_.length()) { | |
| 104 HStoreNamedField* prev = unobserved_.at(i); | |
| 105 if (aliasing_->MayAlias(object, prev->object()->ActualValue()) && | |
| 106 load->access().Equals(prev->access())) { | |
| 107 TRACE(("-- Observed store S%d by load L%d\n", prev->id(), load->id())); | |
| 108 unobserved_.Remove(i); | |
| 109 } else { | |
| 110 i++; | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 | |
| 116 static bool CanDeoptimize(HInstruction* instr) { | |
|
Hannes Payer (out of office)
2014/01/16 15:25:21
This function looks pretty fragile, is there a mor
| |
| 117 // TODO(titzer): most binops can allocate? | |
| 118 switch (instr->opcode()) { | |
| 119 case HValue::kAccessArgumentsAt: | |
| 120 case HValue::kAdd: | |
| 121 case HValue::kApplyArguments: | |
| 122 case HValue::kArgumentsElements: | |
| 123 case HValue::kArgumentsLength: | |
| 124 case HValue::kArgumentsObject: | |
| 125 // TODO(titzer): non-tagged inputs case HValue::kBitwise: | |
|
Hannes Payer (out of office)
2014/01/16 15:25:21
that looks broken
| |
| 126 case HValue::kBoundsCheckBaseIndexInformation: | |
| 127 case HValue::kCapturedObject: | |
| 128 // TODO(titzer): non-tagged inputs case HValue::kChange: | |
| 129 case HValue::kClampToUint8: | |
| 130 // TODO(titzer): non-tagged inputs case HValue::kCompareGeneric: | |
| 131 case HValue::kConstant: | |
| 132 case HValue::kContext: | |
| 133 case HValue::kDateField: | |
| 134 case HValue::kDebugBreak: | |
| 135 case HValue::kDeclareGlobals: | |
| 136 case HValue::kDiv: | |
| 137 case HValue::kDummyUse: | |
| 138 case HValue::kElementsKind: | |
| 139 case HValue::kEnterInlined: | |
| 140 case HValue::kEnvironmentMarker: | |
| 141 case HValue::kForceRepresentation: | |
| 142 case HValue::kForInCacheArray: | |
| 143 case HValue::kForInPrepareMap: | |
| 144 case HValue::kFunctionLiteral: | |
| 145 case HValue::kGetCachedArrayIndex: | |
| 146 case HValue::kGlobalObject: | |
| 147 case HValue::kGlobalReceiver: | |
| 148 case HValue::kGoto: | |
| 149 case HValue::kInnerAllocatedObject: | |
| 150 case HValue::kInstanceOf: | |
| 151 case HValue::kInstanceOfKnownGlobal: | |
| 152 case HValue::kInvokeFunction: | |
| 153 case HValue::kLeaveInlined: | |
| 154 case HValue::kLoadContextSlot: | |
| 155 case HValue::kLoadExternalArrayPointer: | |
| 156 case HValue::kLoadFieldByIndex: | |
| 157 case HValue::kLoadFunctionPrototype: | |
| 158 case HValue::kLoadGlobalCell: | |
| 159 case HValue::kLoadGlobalGeneric: | |
| 160 case HValue::kLoadKeyed: | |
| 161 case HValue::kLoadKeyedGeneric: | |
| 162 case HValue::kLoadNamedField: | |
| 163 case HValue::kLoadNamedGeneric: | |
| 164 case HValue::kLoadRoot: | |
| 165 case HValue::kMapEnumLength: | |
| 166 case HValue::kMathFloorOfDiv: | |
| 167 case HValue::kMathMinMax: | |
| 168 case HValue::kMod: | |
| 169 case HValue::kMul: | |
| 170 case HValue::kOsrEntry: | |
| 171 case HValue::kOuterContext: | |
| 172 case HValue::kParameter: | |
| 173 case HValue::kPower: | |
| 174 case HValue::kPushArgument: | |
| 175 case HValue::kRor: | |
| 176 case HValue::kSar: | |
| 177 case HValue::kSeqStringGetChar: | |
| 178 case HValue::kSeqStringSetChar: | |
| 179 case HValue::kShl: | |
| 180 case HValue::kShr: | |
| 181 case HValue::kSimulate: | |
| 182 case HValue::kStackCheck: | |
| 183 case HValue::kStoreCodeEntry: | |
| 184 case HValue::kStoreContextSlot: | |
| 185 case HValue::kStoreGlobalCell: | |
| 186 case HValue::kStoreGlobalGeneric: | |
| 187 case HValue::kStoreKeyed: | |
| 188 case HValue::kStoreKeyedGeneric: | |
| 189 case HValue::kStoreNamedField: | |
| 190 case HValue::kStoreNamedGeneric: | |
| 191 case HValue::kStringAdd: | |
| 192 case HValue::kStringCharCodeAt: | |
| 193 case HValue::kStringCharFromCode: | |
| 194 case HValue::kSub: | |
| 195 case HValue::kThisFunction: | |
| 196 case HValue::kToFastProperties: | |
| 197 case HValue::kTransitionElementsKind: | |
| 198 case HValue::kTrapAllocationMemento: | |
| 199 case HValue::kTypeof: | |
| 200 case HValue::kUnaryMathOperation: | |
| 201 case HValue::kUseConst: | |
| 202 case HValue::kWrapReceiver: | |
| 203 return false; | |
| 204 default: | |
| 205 return true; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 | |
| 210 void HStoreEliminationPhase::ProcessInstr(HInstruction* instr, | |
| 211 GVNFlagSet flags) { | |
| 212 if (unobserved_.length() == 0) return; // Nothing to do. | |
| 213 if (CanDeoptimize(instr)) { | |
| 214 TRACE(("-- Observed stores at I%d (might deoptimize)\n", instr->id())); | |
| 215 unobserved_.Rewind(0); | |
| 216 return; | |
| 217 } | |
| 218 if (instr->CheckGVNFlag(kChangesNewSpacePromotion)) { | |
| 219 TRACE(("-- Observed stores at I%d (might GC)\n", instr->id())); | |
| 220 unobserved_.Rewind(0); | |
| 221 return; | |
| 222 } | |
| 223 if (instr->gvn_flags().ContainsAnyOf(flags)) { | |
| 224 TRACE(("-- Observed stores at I%d (GVN flags)\n", instr->id())); | |
| 225 unobserved_.Rewind(0); | |
| 226 return; | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 } } // namespace v8::internal | |
| OLD | NEW |