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

Side by Side Diff: src/bounds-check-elimination.cc

Issue 17568015: New array bounds check elimination pass (focused on induction variables and bitwise operations). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed review comments. Created 7 years, 5 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.
titzer 2013/07/02 13:45:06 Please name this file with a "hydrogen-" prefix. "
Massi 2013/07/08 11:55:07 hydrogen-bounds-check-removal.cc is just as long a
titzer 2013/07/10 16:34:18 Ok.
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.h"
29
30 namespace v8 {
31 namespace internal {
32
33 class InductionVariableBlocksTable BASE_EMBEDDED {
34 public:
35 class Element {
titzer 2013/07/02 13:45:06 I find it hard to understand why this class serves
Massi 2013/07/08 11:55:07 Added comments.
36 public:
37 static const int kNoBlock = -1;
38
39 HBasicBlock* block() { return block_; }
titzer 2013/07/02 13:45:06 Why do you have accessors for all this state in th
Massi 2013/07/08 11:55:07 Removed unneeded accessors.
40 void set_block(HBasicBlock* block) { block_ = block; }
41 int current_successor() { return current_successor_; }
42 int backtrack_to() { return backtrack_to_; }
43 bool is_start() { return is_start_; }
44 bool is_proper_exit() { return is_proper_exit_; }
45 bool is_in_loop() { return is_in_loop_; }
46 bool has_check() { return has_check_; }
47 void set_has_check() { has_check_ = true; }
48 InductionVariableLimitUpdate* additional_limit() {
49 return &additional_limit_;
50 }
51
52 void InitializeLoop(InductionVariableData* data) {
53 ASSERT(data->limit() != NULL);
54 HLoopInformation* loop = data->phi()->block()->current_loop();
55 current_successor_ = kNoBlock;
56 backtrack_to_ = kNoBlock;
57 is_start_ = (block() == loop->loop_header());
58 is_proper_exit_ = (block() == data->induction_exit_target());
59 is_in_loop_ = loop->IsNestedInThisLoop(block()->current_loop());
60 has_check_ = false;
61 }
62
63 void ClearIterationData() {
64 current_successor_ = kNoBlock;
65 backtrack_to_ = kNoBlock;
66 }
67
68 int CurrentSuccessorBlock() {
69 if (current_successor_ < block()->end()->SuccessorCount()) {
70 return block()->end()->SuccessorAt(current_successor_)->block_id();
71 } else {
72 return kNoBlock;
73 }
74 }
75
76 int PerformStep(int from_block, bool* failure, bool* unsafe) {
77 if (!is_in_loop()) {
78 if (!is_proper_exit()) {
79 *unsafe = true;
80 }
81 return from_block;
82 }
83
84 if (is_start() &&
85 from_block != kNoBlock &&
86 from_block != CurrentSuccessorBlock()) {
87 *failure = true;
88 return from_block;
89 }
90
91 if (has_check()) {
92 return from_block;
93 }
94
95 if (current_successor_ == kNoBlock) {
96 backtrack_to_ = from_block;
97 }
98 current_successor_++;
99
100 if (CurrentSuccessorBlock() != kNoBlock) {
101 return CurrentSuccessorBlock();
102 } else {
103 return backtrack_to();
104 }
105 }
106
107 Element()
titzer 2013/07/02 13:45:06 At the very least the constructor should accept th
Massi 2013/07/08 11:55:07 I don't think I can do it because this is the elem
108 : block_(NULL), current_successor_(kNoBlock), backtrack_to_(kNoBlock),
109 is_start_(false), is_proper_exit_(false), has_check_(false),
110 additional_limit_() {}
111
112 private:
113 HBasicBlock* block_;
114 int current_successor_;
115 int backtrack_to_;
116 bool is_start_;
117 bool is_proper_exit_;
118 bool is_in_loop_;
119 bool has_check_;
120 InductionVariableLimitUpdate additional_limit_;
121 };
122
123 HGraph* graph() { return graph_; }
124 HBasicBlock* loop_header() { return loop_header_; }
125 Element* at(int index) { return &(elements_.at(index)); }
126 Element* at(HBasicBlock* block) { return at(block->block_id()); }
127
128 void add_check_at(int index) {
129 at(index)->set_has_check();
130 }
131 void add_check_at(HBasicBlock* block) {
132 add_check_at(block->block_id());
133 }
134
135 void InitializeLoop(InductionVariableData* data) {
136 for (int i = 0; i < graph()->blocks()->length(); i++) {
137 at(i)->InitializeLoop(data);
138 }
139 loop_header_ = data->phi()->block()->current_loop()->loop_header();
140 }
141
142 void ClearIterationData() {
143 ASSERT(loop_header() != NULL);
144 HLoopInformation* loop = loop_header()->loop_information();
145 for (int i = 0; i < loop->blocks()->length(); i++) {
146 at(loop->blocks()->at(i)->block_id())->ClearIterationData();
147 }
148 }
149
150 bool LoopPathsAreChecked(bool* unsafe) {
151 bool failure = false;
152 *unsafe = false;
153 int previous_block = Element::kNoBlock;
154 int current_block = loop_header()->block_id();
155 while (current_block != Element::kNoBlock) {
156 int next_block = at(current_block)->PerformStep(previous_block,
157 &failure, unsafe);
158 previous_block = current_block;
159 current_block = next_block;
160 if (failure) return false;
161 }
162 return true;
163 }
164
165 void AddCheck(HBoundsCheck* check) {
166 at(check->block()->block_id())->set_has_check();
167 }
168
169 explicit InductionVariableBlocksTable(HGraph* graph)
170 : graph_(graph), loop_header_(NULL),
171 elements_(graph->blocks()->length(), graph->zone()) {
172 for (int i = 0; i < graph->blocks()->length(); i++) {
173 Element element;
174 element.set_block(graph->blocks()->at(i));
175 elements_.Add(element, graph->zone());
176 ASSERT(at(i)->block()->block_id() == i);
177 }
178 }
179
180 void ProcessRelatedChecks(
181 InductionVariableData::InductionVariableCheck* check,
182 InductionVariableData* data) {
183 HValue* length = check->check()->length();
184 ClearIterationData();
185 check->set_processed();
186 HBasicBlock* header =
187 data->phi()->block()->current_loop()->loop_header();
188 HBasicBlock* pre_header = header->predecessors()->at(0);
189 if (!data->limit()->IsInteger32Constant()) {
190 HBasicBlock* limit_block = data->limit()->block();
191 if (limit_block != pre_header &&
192 !limit_block->Dominates(pre_header)) {
193 return;
194 }
195 }
196 if (!(data->limit()->representation().Equals(
197 length->representation()) ||
198 data->limit()->IsInteger32Constant())) {
199 return;
200 }
201 if (check->check()->length()->block() != pre_header &&
202 !check->check()->length()->block()->Dominates(pre_header)) {
203 return;
204 }
205
206 for (InductionVariableData::InductionVariableCheck* current_check = check;
207 current_check != NULL;
208 current_check = current_check->next()) {
209 if (current_check->check()->length() != length) continue;
210
211 add_check_at(current_check->check()->block());
212 current_check->set_processed();
213 }
214
215 bool unsafe;
216 bool failure = !LoopPathsAreChecked(&unsafe);
217
218 if (failure || (unsafe && !graph()->use_optimistic_licm())) {
219 return;
220 }
221
222 bool has_upper_constant_limit = true;
223 InductionVariableData::InductionVariableCheck* current_check = check;
224 int32_t upper_constant_limit =
225 current_check != NULL && current_check->HasUpperLimit() ?
226 current_check->upper_limit() : 0;
227 while (current_check != NULL) {
228 if (check->HasUpperLimit()) {
229 if (check->upper_limit() != upper_constant_limit) {
230 has_upper_constant_limit = false;
231 }
232 } else {
233 has_upper_constant_limit = false;
234 }
235
236 current_check->check()->set_skip_check();
237 current_check = current_check->next();
238 }
239
240 HValue* limit = data->limit();
241
242 if (has_upper_constant_limit) {
243 HConstant* new_limit = new(pre_header->graph()->zone()) HConstant(
244 upper_constant_limit, length->representation());
245 new_limit->InsertBefore(pre_header->end());
246 limit = new_limit;
247 }
248 if (limit->IsInteger32Constant() &&
249 limit->block() != pre_header &&
250 !limit->block()->Dominates(pre_header)) {
251 HConstant* new_limit = new(pre_header->graph()->zone()) HConstant(
252 limit->GetInteger32Constant(), length->representation());
253 new_limit->InsertBefore(pre_header->end());
254 limit = new_limit;
255 }
256 HBoundsCheck* hoisted_check = new(pre_header->zone()) HBoundsCheck(
257 limit, check->check()->length());
258 hoisted_check->InsertBefore(pre_header->end());
259 hoisted_check->set_allow_equality(true);
260 }
261
262 private:
263 HGraph* graph_;
264 HBasicBlock* loop_header_;
265 ZoneList<Element> elements_;
titzer 2013/07/10 16:34:18 I think you could get away with a plain-old C arra
266 };
267
268
269 void HGraph::CollectInductionVariableData(
270 HBasicBlock* bb,
271 InductionVariableBlocksTable* table) {
272 bool additional_limit = false;
273
274 for (int i = 0; i < bb->phis()->length(); i++) {
275 HPhi* phi = bb->phis()->at(i);
276 phi->DetectInductionVariable();
277 }
278
279 additional_limit = InductionVariableData::ComputeInductionVariableLimit(
280 bb, table->at(bb)->additional_limit());
281
282 if (additional_limit) {
283 table->at(bb)->additional_limit()->updated_variable->
284 UpdateAdditionalLimit(table->at(bb)->additional_limit());
285 }
286
287 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) {
288 if (!i->IsBoundsCheck()) continue;
289 HBoundsCheck* check = HBoundsCheck::cast(i);
290 InductionVariableData::BitwiseDecompositionResult decomposition;
291 InductionVariableData::DecomposeBitwise(check->index(), &decomposition);
292 if (!decomposition.base->IsPhi()) continue;
293 HPhi* phi = HPhi::cast(decomposition.base);
294
295 if (!phi->IsInductionVariable()) continue;
296 InductionVariableData* data = phi->induction_variable_data();
297
298 // For now ignore loops decrementing the index.
299 if (data->increment() <= 0) continue;
300 if (!data->lower_limit_is_non_negative_constant()) continue;
301
302 // TODO(mmassi): skip OSR values for check->length().
303 if (check->length() == data->limit() ||
304 check->length() == data->additional_upper_limit()) {
305 check->set_skip_check();
306 continue;
307 }
308
309 if (!phi->IsLimitedInductionVariable()) continue;
310
311 int32_t limit = data->ComputeUpperLimit(decomposition.and_mask,
312 decomposition.or_mask);
313 phi->induction_variable_data()->AddCheck(check, limit);
314 }
315
316 for (int i = 0; i < bb->dominated_blocks()->length(); i++) {
317 CollectInductionVariableData(bb->dominated_blocks()->at(i), table);
318 }
319
320 if (additional_limit) {
321 table->at(bb->block_id())->additional_limit()->updated_variable->
322 UpdateAdditionalLimit(table->at(bb->block_id())->additional_limit());
323 }
324 }
325
326
327 void HGraph::EliminateRedundantBoundsChecksUsingInductionVariables(
328 HBasicBlock* bb,
329 InductionVariableBlocksTable* table) {
330 for (int i = 0; i < bb->phis()->length(); i++) {
331 HPhi* phi = bb->phis()->at(i);
332 if (!phi->IsLimitedInductionVariable()) continue;
333
334 InductionVariableData* induction_data = phi->induction_variable_data();
335 InductionVariableData::ChecksRelatedToLength* current_length_group =
336 induction_data->checks();
337 while (current_length_group != NULL) {
338 current_length_group->CloseCurrentBlock();
339 InductionVariableData::InductionVariableCheck* current_base_check =
340 current_length_group->checks();
341 table->InitializeLoop(induction_data);
342
343 while (current_base_check != NULL) {
344 table->ProcessRelatedChecks(current_base_check, induction_data);
345 while (current_base_check != NULL && current_base_check->processed()) {
346 current_base_check = current_base_check->next();
347 }
348 }
349
350 current_length_group = current_length_group->next();
351 }
352 }
353 }
354
355
356 void HGraph::EliminateRedundantBoundsChecksUsingInductionVariables() {
357 InductionVariableBlocksTable table(this);
358 CollectInductionVariableData(entry_block(), &table);
359 for (int i = 0; i < blocks()->length(); i++) {
360 EliminateRedundantBoundsChecksUsingInductionVariables(blocks()->at(i),
361 &table);
362 }
363 }
364
365 } } // namespace v8::internal
366
OLDNEW
« no previous file with comments | « src/arm/lithium-codegen-arm.cc ('k') | src/flag-definitions.h » ('j') | src/hydrogen.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698