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

Side by Side Diff: src/hydrogen-load-elimination.cc

Issue 24117004: Implement local load/store elimination on basic blocks. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 3 months 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
OLDNEW
(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-alias-analysis.h"
29 #include "hydrogen-load-elimination.h"
30 #include "hydrogen-instructions.h"
31
32 namespace v8 {
33 namespace internal {
34
35 static const int kMaxTrackedFields = 16;
36 static const int kMaxTrackedObjects = 5;
37
38 // An element in the field approximation list.
39 class HFieldApprox : public ZoneObject {
Michael Starzinger 2013/09/12 20:04:25 nit: Can we use the full name HFieldApproximation?
40 public: // Just a data blob.
41 HValue* object_;
42 HLoadNamedField* last_load_;
43 HValue* last_value_;
44 HFieldApprox *next_;
Michael Starzinger 2013/09/12 20:04:25 nit: Asterisk sticks to the left.
45 };
46
47
48 // The main datastructure used during load/store elimination. Each in-object
49 // field is tracked separately. For each field, store a list of known field
50 // values for known objects.
51 class HLoadElimTable {
Michael Starzinger 2013/09/12 20:04:25 nit: Can we use the full name HLoadEliminationTabl
52 public:
53 HLoadElimTable(Zone* zone, HAliasAnalyzer* aliasing)
54 : zone_(zone), fields_(kMaxTrackedFields, zone), aliasing_(aliasing) { }
55
56 // Process a load instruction, updating internal table state. If a previous
57 // load or store for this object and field exists, return the new value with
58 // which the load should be replaced. Otherwise, return {instr}.
59 HValue* load(HLoadNamedField* instr) {
60 int field = FieldOf(instr->access());
61 if (field < 0) return instr;
62
63 HValue* object = aliasing_->ActualValue(instr->object());
64 HFieldApprox* approx = FindOrCreate(object, field);
65
66 if (approx->last_value_ == NULL) {
67 // Load is not redundant. Fill out a new entry.
68 approx->last_load_ = instr;
69 approx->last_value_ = instr;
70 return instr;
71 } else {
72 // Eliminate the load. Reuse previously stored value or load instruction.
73 return approx->last_value_;
74 }
75 }
76
77 // Process a store instruction, updating internal table state. If a previous
78 // store to the same object and field makes this store redundant (e.g. because
79 // the stored values are the same), return NULL indicating that this store
80 // instruction is redundant. Otherwise, return {instr}.
81 HValue* store(HStoreNamedField* instr) {
82 int field = FieldOf(instr->access());
83 if (field < 0) return instr;
84
85 HValue* object = aliasing_->ActualValue(instr->object());
86 HValue* value = instr->value();
87
88 // Kill non-equivalent may-alias entries.
89 KillFieldInternal(object, field, value);
90 HFieldApprox* approx = FindOrCreate(object, field);
91
92 if (approx->last_value_ != value) {
93 // The store is not redundant. Update the entry.
94 approx->last_load_ = NULL;
95 approx->last_value_ = value;
96 return instr;
97 } else {
98 // The store is redundant because the field already has this value.
99 return NULL;
100 }
101 }
102
103 // Kill everything in this table.
104 void Kill() {
105 fields_.Rewind(0);
106 }
107
108 // Kill everything potentially affected by the given store.
109 void Kill(HStoreNamedField* store) {
Michael Starzinger 2013/09/12 20:04:25 This method is never called, let's drop it.
110 int field = FieldOf(store->access());
111 if (field >= 0 && field < fields_.length()) {
112 HValue* object = aliasing_->ActualValue(store->object());
113 KillFieldInternal(object, field, store->value());
114 }
115 }
116
117 // Find or create an entry for the given object and field pair.
118 HFieldApprox* FindOrCreate(HValue* object, int field) {
119 EnsureFields(field + 1);
120
121 // Search for a field approximation for this object.
122 HFieldApprox* approx = fields_[field];
123 int count = 0;
124 while (approx != NULL) {
125 if (aliasing_->MustAlias(object, approx->object_)) return approx;
126 count++;
127 approx = approx->next_;
128 }
129
130 if (count >= kMaxTrackedObjects) {
131 // Pull the last entry off the end and repurpose it for this object.
132 approx = ReuseLastApprox(field);
133 } else {
134 // Allocate a new entry.
135 approx = new(zone_) HFieldApprox();
136 }
137
138 // Insert the entry at the head of the list.
139 approx->object_ = object;
140 approx->last_load_ = NULL;
141 approx->last_value_ = NULL;
142 approx->next_ = fields_[field];
143 fields_[field] = approx;
144
145 return approx;
146 }
147
148 // Kill all entries for a given field that _may_ alias the given object
149 // and do _not_ have the given value.
150 void KillFieldInternal(HValue* object, int field, HValue* value) {
151 if (field >= fields_.length()) return; // Nothing to do.
152
153 HFieldApprox* approx = fields_[field];
154 HFieldApprox* prev = NULL;
155 while (approx != NULL) {
156 if (aliasing_->MayAlias(object, approx->object_)) {
157 if (approx->last_value_ != value) {
158 // Kill an aliasing entry that doesn't agree on the value.
159 if (prev != NULL) {
160 prev->next_ = approx->next_;
161 } else {
162 fields_[field] = approx->next_;
163 }
164 approx = approx->next_;
165 continue;
166 }
167 }
168 prev = approx;
169 approx = approx->next_;
170 }
171 }
172
173 // Remove the last approximation for a field so that it can be reused.
174 // We reuse the last entry because it was the first inserted and is
175 // thus farthest away from the current instruction.
176 HFieldApprox* ReuseLastApprox(int field) {
177 HFieldApprox* approx = fields_[field];
178 ASSERT(approx != NULL);
179
180 HFieldApprox* prev = NULL;
181 while (approx->next_ != NULL) {
182 prev = approx;
183 approx = approx->next_;
184 }
185 if (prev != NULL) prev->next_ = NULL;
186 return approx;
187 }
188
189 // Ensure internal storage for the given number of fields.
190 void EnsureFields(int num_fields) {
191 while (fields_.length() < num_fields) fields_.Add(NULL, zone_);
192 }
193
194 // Compute the field index for the given object access; -1 if not tracked.
195 int FieldOf(HObjectAccess access) {
196 // Only track kMaxTrackedFields in-object fields.
197 if (!access.IsInobject()) return -1;
198 int offset = access.offset();
199 if (offset >= kMaxTrackedFields * kPointerSize) return -1;
200 ASSERT((offset % kPointerSize) == 0); // Assume aligned accesses.
201 return offset / kPointerSize;
202 }
203
204 // Print this table to stdout.
205 void Print() {
206 for (int i = 0; i < fields_.length(); i++) {
207 PrintF(" field %d: ", i);
208 for (HFieldApprox* a = fields_[i]; a != NULL; a = a->next_) {
209 PrintF("[o%d =", a->object_->id());
210 if (a->last_load_ != NULL) PrintF(" L%d", a->last_load_->id());
211 if (a->last_value_ != NULL) PrintF(" v%d", a->last_value_->id());
212 PrintF("] ");
213 }
214 PrintF("\n");
215 }
216 }
217
218 Zone* zone_;
Michael Starzinger 2013/09/12 20:04:25 nit: Make the field private. Maybe even make the i
219 ZoneList<HFieldApprox*> fields_;
220 HAliasAnalyzer* aliasing_;
221 };
222
223
224 void HLoadEliminationPhase::Run() {
225 for (int i = 0; i < graph()->blocks()->length(); i++) {
226 HBasicBlock* block = graph()->blocks()->at(i);
227 EliminateLoads(block);
228 }
229 }
230
231
232 // For code de-uglification.
233 #define TRACE(x) if (FLAG_trace_load_elimination) PrintF x
234
235
236 // Eliminate loads and stores local to a block.
237 void HLoadEliminationPhase::EliminateLoads(HBasicBlock* block) {
238 HAliasAnalyzer aliasing;
239 HLoadElimTable table(zone(), &aliasing);
240
241 TRACE(("-- load-elim B%d -------------------------------------------------\n",
242 block->block_id()));
243
244 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
245 bool changed = false;
246 HInstruction* instr = it.Current();
247
248 switch (instr->opcode()) {
249 case HValue::kLoadNamedField: {
Michael Starzinger 2013/09/12 20:04:25 style: Indent cases by one level.
250 HLoadNamedField* load = HLoadNamedField::cast(instr);
251 TRACE((" process L%d field %d (o%d)\n",
252 instr->id(),
253 table.FieldOf(load->access()),
254 table.aliasing_->ActualValue(load->object())->id()));
255 HValue* result = table.load(load);
256 if (result != instr) {
257 // The load can be replaced with a previous load or a value.
258 TRACE((" replace L%d -> v%d\n", instr->id(), result->id()));
259 instr->DeleteAndReplaceWith(result);
260 }
261 changed = true;
262 break;
263 }
264 case HValue::kStoreNamedField: {
265 HStoreNamedField* store = HStoreNamedField::cast(instr);
266 TRACE((" process S%d field %d (o%d) = v%d\n",
267 instr->id(),
268 table.FieldOf(store->access()),
269 table.aliasing_->ActualValue(store->object())->id(),
270 store->value()->id()));
271 HValue* result = table.store(store);
Michael Starzinger 2013/09/12 20:04:25 An HStoreNamedField with a transition also changes
272 if (result == NULL) {
273 // The store is redundant. Remove it.
274 TRACE((" remove S%d\n", instr->id()));
275 instr->DeleteAndReplaceWith(NULL);
276 }
277 changed = true;
278 break;
279 }
280 default: {
281 if (instr->CheckGVNFlag(kChangesInobjectFields)) {
282 TRACE((" kill-all i%d\n", instr->id()));
283 table.Kill();
284 }
285 }
286 // Improvements possible:
287 // - learn from HCheckMaps for field 0
288 // - remove unobservable stores (write-after-write)
289 }
290
291 if (changed && FLAG_trace_load_elimination) {
292 table.Print();
293 }
294 }
295 }
296
297
298 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698