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

Side by Side Diff: runtime/vm/flow_graph_range_analysis.cc

Issue 472303002: Revert "Switch to a fix-point based range analysis to improve its precision." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 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
« no previous file with comments | « runtime/vm/flow_graph_range_analysis.h ('k') | runtime/vm/flow_graph_range_analysis_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_range_analysis.h" 5 #include "vm/flow_graph_range_analysis.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/il_printer.h" 8 #include "vm/il_printer.h"
9 9
10 namespace dart { 10 namespace dart {
11 11
12 DEFINE_FLAG(bool, array_bounds_check_elimination, true, 12 DEFINE_FLAG(bool, array_bounds_check_elimination, true,
13 "Eliminate redundant bounds checks."); 13 "Eliminate redundant bounds checks.");
14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); 14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
15 DEFINE_FLAG(bool, trace_integer_ir_selection, false, 15 DEFINE_FLAG(bool, trace_integer_ir_selection, false,
16 "Print integer IR selection optimization pass."); 16 "Print integer IR selection optimization pass.");
17 DECLARE_FLAG(bool, trace_constant_propagation); 17 DECLARE_FLAG(bool, trace_constant_propagation);
18 18
19 // Quick access to the locally defined isolate() method. 19 // Quick access to the locally defined isolate() method.
20 #define I (isolate()) 20 #define I (isolate())
21 21
22 void RangeAnalysis::Analyze() { 22 void RangeAnalysis::Analyze() {
23 CollectValues(); 23 CollectValues();
24 InsertConstraints(); 24 InsertConstraints();
25 InferRanges(); 25 InferRanges();
26 EliminateRedundantBoundsChecks();
27 MarkUnreachableBlocks();
28
29 IntegerInstructionSelector iis(flow_graph_); 26 IntegerInstructionSelector iis(flow_graph_);
30 iis.Select(); 27 iis.Select();
31
32 RemoveConstraints(); 28 RemoveConstraints();
33 } 29 }
34 30
35 31
36 void RangeAnalysis::CollectValues() { 32 void RangeAnalysis::CollectValues() {
37 const GrowableArray<Definition*>& initial = 33 const GrowableArray<Definition*>& initial =
38 *flow_graph_->graph_entry()->initial_definitions(); 34 *flow_graph_->graph_entry()->initial_definitions();
39 for (intptr_t i = 0; i < initial.length(); ++i) { 35 for (intptr_t i = 0; i < initial.length(); ++i) {
40 Definition* current = initial[i]; 36 Definition* current = initial[i];
41 if (current->Type()->ToCid() == kSmiCid) { 37 if (current->Type()->ToCid() == kSmiCid) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 Definition* defn = current->AsDefinition(); 78 Definition* defn = current->AsDefinition();
83 if (defn != NULL) { 79 if (defn != NULL) {
84 if ((defn->Type()->ToCid() == kSmiCid) && 80 if ((defn->Type()->ToCid() == kSmiCid) &&
85 (defn->ssa_temp_index() != -1)) { 81 (defn->ssa_temp_index() != -1)) {
86 values_.Add(defn); 82 values_.Add(defn);
87 } else if ((defn->IsMintDefinition()) && 83 } else if ((defn->IsMintDefinition()) &&
88 (defn->ssa_temp_index() != -1)) { 84 (defn->ssa_temp_index() != -1)) {
89 values_.Add(defn); 85 values_.Add(defn);
90 } 86 }
91 } else if (current->IsCheckSmi()) { 87 } else if (current->IsCheckSmi()) {
92 if (current->Canonicalize(flow_graph_) == NULL) {
93 instr_it.RemoveCurrentFromGraph();
94 continue;
95 }
96 smi_checks_.Add(current->AsCheckSmi()); 88 smi_checks_.Add(current->AsCheckSmi());
97 } else if (current->IsCheckArrayBound()) {
98 bounds_checks_.Add(current->AsCheckArrayBound());
99 } 89 }
100 } 90 }
101 } 91 }
102 } 92 }
103 93
104 94
105 // Returns true if use is dominated by the given instruction. 95 // Returns true if use is dominated by the given instruction.
106 // Note: uses that occur at instruction itself are not dominated by it. 96 // Note: uses that occur at instruction itself are not dominated by it.
107 static bool IsDominatedUse(Instruction* dom, Value* use) { 97 static bool IsDominatedUse(Instruction* dom, Value* use) {
108 BlockEntryInstr* dom_block = dom->GetBlock(); 98 BlockEntryInstr* dom_block = dom->GetBlock();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 return Token::kILLEGAL; 153 return Token::kILLEGAL;
164 } 154 }
165 } 155 }
166 156
167 157
168 // Given a boundary (right operand) and a comparison operation return 158 // Given a boundary (right operand) and a comparison operation return
169 // a symbolic range constraint for the left operand of the comparison assuming 159 // a symbolic range constraint for the left operand of the comparison assuming
170 // that it evaluated to true. 160 // that it evaluated to true.
171 // For example for the comparison a < b symbol a is constrained with range 161 // For example for the comparison a < b symbol a is constrained with range
172 // [Smi::kMinValue, b - 1]. 162 // [Smi::kMinValue, b - 1].
173 Range* RangeAnalysis::ConstraintSmiRange(Token::Kind op, Definition* boundary) { 163 Range* RangeAnalysis::ConstraintRange(Token::Kind op, Definition* boundary) {
174 switch (op) { 164 switch (op) {
175 case Token::kEQ: 165 case Token::kEQ:
176 return new(I) Range(RangeBoundary::FromDefinition(boundary), 166 return new(I) Range(RangeBoundary::FromDefinition(boundary),
177 RangeBoundary::FromDefinition(boundary)); 167 RangeBoundary::FromDefinition(boundary));
178 case Token::kNE: 168 case Token::kNE:
179 return new(I) Range(Range::Full(RangeBoundary::kRangeBoundarySmi)); 169 return Range::Unknown();
180 case Token::kLT: 170 case Token::kLT:
181 return new(I) Range(RangeBoundary::MinSmi(), 171 return new(I) Range(RangeBoundary::MinSmi(),
182 RangeBoundary::FromDefinition(boundary, -1)); 172 RangeBoundary::FromDefinition(boundary, -1));
183 case Token::kGT: 173 case Token::kGT:
184 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1), 174 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1),
185 RangeBoundary::MaxSmi()); 175 RangeBoundary::MaxSmi());
186 case Token::kLTE: 176 case Token::kLTE:
187 return new(I) Range(RangeBoundary::MinSmi(), 177 return new(I) Range(RangeBoundary::MinSmi(),
188 RangeBoundary::FromDefinition(boundary)); 178 RangeBoundary::FromDefinition(boundary));
189 case Token::kGTE: 179 case Token::kGTE:
190 return new(I) Range(RangeBoundary::FromDefinition(boundary), 180 return new(I) Range(RangeBoundary::FromDefinition(boundary),
191 RangeBoundary::MaxSmi()); 181 RangeBoundary::MaxSmi());
192 default: 182 default:
193 UNREACHABLE(); 183 UNREACHABLE();
194 return NULL; 184 return Range::Unknown();
195 } 185 }
196 } 186 }
197 187
198 188
199 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, 189 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn,
200 Range* constraint_range, 190 Range* constraint_range,
201 Instruction* after) { 191 Instruction* after) {
202 // No need to constrain constants. 192 // No need to constrain constants.
203 if (defn->IsConstant()) return NULL; 193 if (defn->IsConstant()) return NULL;
204 194
205 // Check if the value is already constrained to avoid inserting duplicated 195 ConstraintInstr* constraint = new(I) ConstraintInstr(
206 // constraints.
207 ConstraintInstr* constraint = after->next()->AsConstraint();
208 while (constraint != NULL) {
209 if ((constraint->value()->definition() == defn) &&
210 constraint->constraint()->Equals(constraint_range)) {
211 return NULL;
212 }
213 constraint = constraint->next()->AsConstraint();
214 }
215
216 constraint = new(I) ConstraintInstr(
217 new(I) Value(defn), constraint_range); 196 new(I) Value(defn), constraint_range);
218 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue); 197 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue);
219 RenameDominatedUses(defn, constraint, constraint); 198 RenameDominatedUses(defn, constraint, constraint);
220 constraints_.Add(constraint); 199 constraints_.Add(constraint);
221 return constraint; 200 return constraint;
222 } 201 }
223 202
224 203
225 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { 204 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) {
226 BranchInstr* branch = use->instruction()->AsBranch(); 205 BranchInstr* branch = use->instruction()->AsBranch();
(...skipping 10 matching lines...) Expand all
237 ASSERT(use->use_index() == 1); // Right operand. 216 ASSERT(use->use_index() == 1); // Right operand.
238 boundary = rel_op->InputAt(0)->definition(); 217 boundary = rel_op->InputAt(0)->definition();
239 // InsertConstraintFor assumes that defn is left operand of a 218 // InsertConstraintFor assumes that defn is left operand of a
240 // comparison if it is right operand flip the comparison. 219 // comparison if it is right operand flip the comparison.
241 op_kind = FlipComparison(rel_op->kind()); 220 op_kind = FlipComparison(rel_op->kind());
242 } 221 }
243 222
244 // Constrain definition at the true successor. 223 // Constrain definition at the true successor.
245 ConstraintInstr* true_constraint = 224 ConstraintInstr* true_constraint =
246 InsertConstraintFor(defn, 225 InsertConstraintFor(defn,
247 ConstraintSmiRange(op_kind, boundary), 226 ConstraintRange(op_kind, boundary),
248 branch->true_successor()); 227 branch->true_successor());
249 // Mark true_constraint an artificial use of boundary. This ensures 228 // Mark true_constraint an artificial use of boundary. This ensures
250 // that constraint's range is recalculated if boundary's range changes. 229 // that constraint's range is recalculated if boundary's range changes.
251 if (true_constraint != NULL) { 230 if (true_constraint != NULL) {
252 true_constraint->AddDependency(boundary); 231 true_constraint->AddDependency(boundary);
253 true_constraint->set_target(branch->true_successor()); 232 true_constraint->set_target(branch->true_successor());
254 } 233 }
255 234
256 // Constrain definition with a negated condition at the false successor. 235 // Constrain definition with a negated condition at the false successor.
257 ConstraintInstr* false_constraint = 236 ConstraintInstr* false_constraint =
258 InsertConstraintFor( 237 InsertConstraintFor(
259 defn, 238 defn,
260 ConstraintSmiRange(Token::NegateComparison(op_kind), boundary), 239 ConstraintRange(Token::NegateComparison(op_kind), boundary),
261 branch->false_successor()); 240 branch->false_successor());
262 // Mark false_constraint an artificial use of boundary. This ensures 241 // Mark false_constraint an artificial use of boundary. This ensures
263 // that constraint's range is recalculated if boundary's range changes. 242 // that constraint's range is recalculated if boundary's range changes.
264 if (false_constraint != NULL) { 243 if (false_constraint != NULL) {
265 false_constraint->AddDependency(boundary); 244 false_constraint->AddDependency(boundary);
266 false_constraint->set_target(branch->false_successor()); 245 false_constraint->set_target(branch->false_successor());
267 } 246 }
268 } 247 }
269 } 248 }
270 249
(...skipping 27 matching lines...) Expand all
298 Definition* index = check->index()->definition(); 277 Definition* index = check->index()->definition();
299 constraint_range = new(I) Range( 278 constraint_range = new(I) Range(
300 RangeBoundary::FromDefinition(index, 1), 279 RangeBoundary::FromDefinition(index, 1),
301 RangeBoundary::MaxSmi()); 280 RangeBoundary::MaxSmi());
302 } 281 }
303 InsertConstraintFor(defn, constraint_range, check); 282 InsertConstraintFor(defn, constraint_range, check);
304 } 283 }
305 284
306 285
307 void RangeAnalysis::InsertConstraints() { 286 void RangeAnalysis::InsertConstraints() {
308 Range* smi_range = new(I) Range(
309 Range::Full(RangeBoundary::kRangeBoundarySmi));
310
311 for (intptr_t i = 0; i < smi_checks_.length(); i++) { 287 for (intptr_t i = 0; i < smi_checks_.length(); i++) {
312 CheckSmiInstr* check = smi_checks_[i]; 288 CheckSmiInstr* check = smi_checks_[i];
313 ConstraintInstr* constraint = 289 ConstraintInstr* constraint =
314 InsertConstraintFor(check->value()->definition(), 290 InsertConstraintFor(check->value()->definition(),
315 smi_range, 291 Range::UnknownSmi(),
316 check); 292 check);
317 if (constraint == NULL) { 293 if (constraint == NULL) {
318 // No constraint was needed. 294 // No constraint was needed.
319 continue; 295 continue;
320 } 296 }
321 if (!check->value()->definition()->IsBoxInteger()) {
322 constraint->set_range(Range::Full(RangeBoundary::kRangeBoundarySmi));
323 }
324
325 // Mark the constraint's value's reaching type as smi. 297 // Mark the constraint's value's reaching type as smi.
326 CompileType* smi_compile_type = 298 CompileType* smi_compile_type =
327 ZoneCompileType::Wrap(CompileType::FromCid(kSmiCid)); 299 ZoneCompileType::Wrap(CompileType::FromCid(kSmiCid));
328 constraint->value()->SetReachingType(smi_compile_type); 300 constraint->value()->SetReachingType(smi_compile_type);
329 } 301 }
330 302
331 for (intptr_t i = 0; i < values_.length(); i++) { 303 for (intptr_t i = 0; i < values_.length(); i++) {
332 InsertConstraintsFor(values_[i]); 304 InsertConstraintsFor(values_[i]);
333 } 305 }
334 306
335 for (intptr_t i = 0; i < constraints_.length(); i++) { 307 for (intptr_t i = 0; i < constraints_.length(); i++) {
336 InsertConstraintsFor(constraints_[i]); 308 InsertConstraintsFor(constraints_[i]);
337 } 309 }
338 } 310 }
339 311
340 312
341 static Definition* UnwrapConstraint(Definition* defn) { 313 void RangeAnalysis::ResetWorklist() {
314 if (marked_defns_ == NULL) {
315 marked_defns_ = new(I) BitVector(flow_graph_->current_ssa_temp_index());
316 } else {
317 marked_defns_->Clear();
318 }
319 worklist_.Clear();
320 }
321
322
323 void RangeAnalysis::MarkDefinition(Definition* defn) {
324 // Unwrap constrained value.
342 while (defn->IsConstraint()) { 325 while (defn->IsConstraint()) {
343 defn = defn->AsConstraint()->value()->definition(); 326 defn = defn->AsConstraint()->value()->definition();
344 } 327 }
345 return defn; 328
346 } 329 if (!marked_defns_->Contains(defn->ssa_temp_index())) {
347 330 worklist_.Add(defn);
348 331 marked_defns_->Add(defn->ssa_temp_index());
349 static bool AreEqualDefinitions(Definition* a, Definition* b) { 332 }
350 a = UnwrapConstraint(a); 333 }
351 b = UnwrapConstraint(b); 334
352 return (a == b) || 335
353 (a->AllowsCSE() && 336 RangeAnalysis::Direction RangeAnalysis::ToDirection(Value* val) {
354 a->Dependencies().IsNone() && 337 if (val->BindsToConstant()) {
355 b->AllowsCSE() && 338 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? kPositive
356 b->Dependencies().IsNone() && 339 : kNegative;
357 a->Equals(b)); 340 } else if (val->definition()->range() != NULL) {
358 } 341 Range* range = val->definition()->range();
359 342 if (Range::ConstantMin(range).ConstantValue() >= 0) {
360 343 return kPositive;
361 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { 344 } else if (Range::ConstantMax(range).ConstantValue() <= 0) {
362 return a.IsSymbol() && b.IsSymbol() && 345 return kNegative;
363 AreEqualDefinitions(a.symbol(), b.symbol()); 346 }
364 } 347 }
365 348 return kUnknown;
366 349 }
367 // Given the current range of a phi and a newly computed range check 350
368 // if it is growing towards negative infinity, if it does widen it to 351
369 // MinSmi. 352 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header,
370 static RangeBoundary WidenMin(const Range* range, const Range* new_range) { 353 PhiInstr* var) {
371 RangeBoundary min = range->min(); 354 BitVector* loop_info = loop_header->loop_info();
372 RangeBoundary new_min = new_range->min(); 355
373 356 Definition* initial_value = NULL;
374 if (min.IsSymbol()) { 357 Direction direction = kUnknown;
375 if (min.LowerBound().OverflowedSmi()) { 358
376 return RangeBoundary::MinSmi(); 359 ResetWorklist();
377 } else if (DependOnSameSymbol(min, new_min)) { 360 MarkDefinition(var);
378 return min.offset() <= new_min.offset() ? min : RangeBoundary::MinSmi(); 361 while (!worklist_.is_empty()) {
379 } else if (min.SmiUpperBound() <= new_min.SmiLowerBound()) { 362 Definition* defn = worklist_.RemoveLast();
380 return min; 363
381 } 364 if (defn->IsPhi()) {
382 } 365 PhiInstr* phi = defn->AsPhi();
383 366 for (intptr_t i = 0; i < phi->InputCount(); i++) {
384 min = Range::ConstantMinSmi(range); 367 Definition* defn = phi->InputAt(i)->definition();
385 new_min = Range::ConstantMinSmi(new_range); 368
386 369 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) {
387 return (min.ConstantValue() <= new_min.ConstantValue()) ? 370 // The value is coming from outside of the loop.
388 min : RangeBoundary::MinSmi(); 371 if (initial_value == NULL) {
389 } 372 initial_value = defn;
390 373 continue;
391 // Given the current range of a phi and a newly computed range check 374 } else if (initial_value == defn) {
392 // if it is growing towards positive infinity, if it does widen it to 375 continue;
393 // MaxSmi. 376 } else {
394 static RangeBoundary WidenMax(const Range* range, const Range* new_range) { 377 return NULL;
395 RangeBoundary max = range->max(); 378 }
396 RangeBoundary new_max = new_range->max(); 379 }
397 380
398 if (max.IsSymbol()) { 381 MarkDefinition(defn);
399 if (max.UpperBound().OverflowedSmi()) { 382 }
400 return RangeBoundary::MaxSmi(); 383 } else if (defn->IsBinarySmiOp()) {
401 } else if (DependOnSameSymbol(max, new_max)) { 384 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp();
402 return max.offset() >= new_max.offset() ? max : RangeBoundary::MaxSmi(); 385
403 } else if (max.SmiLowerBound() >= new_max.SmiUpperBound()) { 386 switch (binary_op->op_kind()) {
404 return max; 387 case Token::kADD: {
405 } 388 const Direction growth_right =
406 } 389 ToDirection(binary_op->right());
407 390 if (growth_right != kUnknown) {
408 max = Range::ConstantMaxSmi(range); 391 UpdateDirection(&direction, growth_right);
409 new_max = Range::ConstantMaxSmi(new_range); 392 MarkDefinition(binary_op->left()->definition());
410 393 break;
411 return (max.ConstantValue() >= new_max.ConstantValue()) ? 394 }
412 max : RangeBoundary::MaxSmi(); 395
413 } 396 const Direction growth_left =
414 397 ToDirection(binary_op->left());
415 398 if (growth_left != kUnknown) {
416 // Given the current range of a phi and a newly computed range check 399 UpdateDirection(&direction, growth_left);
417 // if we can perform narrowing: use newly computed minimum to improve precision 400 MarkDefinition(binary_op->right()->definition());
418 // of the computed range. We do it only if current minimum was widened and is 401 break;
419 // equal to MinSmi. 402 }
420 // Newly computed minimum is expected to be greater of equal then old one as 403
421 // we are running after widening phase. 404 return NULL;
422 static RangeBoundary NarrowMin(const Range* range, const Range* new_range) { 405 }
423 #ifdef DEBUG 406
424 const RangeBoundary min = Range::ConstantMinSmi(range); 407 case Token::kSUB: {
425 const RangeBoundary new_min = Range::ConstantMinSmi(new_range); 408 const Direction growth_right =
426 ASSERT(min.ConstantValue() <= new_min.ConstantValue()); 409 ToDirection(binary_op->right());
427 #endif 410 if (growth_right != kUnknown) {
428 // TODO(vegorov): consider using negative infinity to indicate widened bound. 411 UpdateDirection(&direction, Invert(growth_right));
429 return range->min().IsSmiMinimumOrBelow() ? new_range->min() : range->min(); 412 MarkDefinition(binary_op->left()->definition());
430 } 413 break;
431 414 }
432 415 return NULL;
433 // Given the current range of a phi and a newly computed range check 416 }
434 // if we can perform narrowing: use newly computed maximum to improve precision 417
435 // of the computed range. We do it only if current maximum was widened and is 418 default:
436 // equal to MaxSmi. 419 return NULL;
437 // Newly computed minimum is expected to be greater of equal then old one as 420 }
438 // we are running after widening phase. 421 } else {
439 static RangeBoundary NarrowMax(const Range* range, const Range* new_range) { 422 return NULL;
440 #ifdef DEBUG 423 }
441 const RangeBoundary max = Range::ConstantMaxSmi(range); 424 }
442 const RangeBoundary new_max = Range::ConstantMaxSmi(new_range); 425
443 ASSERT(max.ConstantValue() >= new_max.ConstantValue()); 426
444 #endif 427 // We transitively discovered all dependencies of the given phi
445 // TODO(vegorov): consider using positive infinity to indicate widened bound. 428 // and confirmed that it depends on a single value coming from outside of
446 return range->max().IsSmiMaximumOrAbove() ? new_range->max() : range->max(); 429 // the loop and some linear combinations of itself.
447 } 430 // Compute the range based on initial value and the direction of the growth.
448 431 switch (direction) {
449 432 case kPositive:
450 char RangeAnalysis::OpPrefix(JoinOperator op) { 433 return new(I) Range(RangeBoundary::FromDefinition(initial_value),
451 switch (op) { 434 RangeBoundary::MaxSmi());
452 case WIDEN: return 'W'; 435
453 case NARROW: return 'N'; 436 case kNegative:
454 case NONE: return 'I'; 437 return new(I) Range(RangeBoundary::MinSmi(),
455 } 438 RangeBoundary::FromDefinition(initial_value));
439
440 case kUnknown:
441 case kBoth:
442 return Range::UnknownSmi();
443 }
444
456 UNREACHABLE(); 445 UNREACHABLE();
457 return ' '; 446 return NULL;
458 } 447 }
459 448
460 449
461 bool RangeAnalysis::InferRange(JoinOperator op, 450 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) {
462 Definition* defn, 451 JoinEntryInstr* join = block->AsJoinEntry();
463 intptr_t iteration) { 452 if (join != NULL) {
464 Range range; 453 const bool is_loop_header = (join->loop_info() != NULL);
465 defn->InferRange(&range); 454 for (PhiIterator it(join); !it.Done(); it.Advance()) {
466 455 PhiInstr* phi = it.Current();
467 if (!Range::IsUnknown(&range)) { 456 if (definitions_->Contains(phi->ssa_temp_index())) {
468 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { 457 if (is_loop_header) {
469 // TODO(vegorov): we are currently supporting only smi phis. 458 // Try recognizing simple induction variables.
470 ASSERT(defn->Type()->ToCid() == kSmiCid); 459 Range* range = InferInductionVariableRange(join, phi);
471 if (op == WIDEN) { 460 if (range != NULL) {
472 range = Range(WidenMin(defn->range(), &range), 461 phi->range_ = range;
473 WidenMax(defn->range(), &range)); 462 continue;
474 } else if (op == NARROW) { 463 }
475 range = Range(NarrowMin(defn->range(), &range), 464 }
476 NarrowMax(defn->range(), &range)); 465
477 } 466 phi->InferRange();
478 } 467 }
479 468 }
480 if (!range.Equals(defn->range())) { 469 }
481 if (FLAG_trace_range_analysis) { 470
482 OS::Print("%c [%" Pd "] %s: %s => %s\n", 471 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
483 OpPrefix(op), 472 Instruction* current = it.Current();
484 iteration, 473
485 defn->ToCString(), 474 Definition* defn = current->AsDefinition();
486 Range::ToCString(defn->range()), 475 if ((defn != NULL) &&
487 Range::ToCString(&range)); 476 (defn->ssa_temp_index() != -1) &&
488 } 477 definitions_->Contains(defn->ssa_temp_index())) {
489 defn->set_range(range); 478 defn->InferRange();
490 return true; 479 } else if (FLAG_array_bounds_check_elimination &&
491 } 480 current->IsCheckArrayBound()) {
492 } 481 CheckArrayBoundInstr* check = current->AsCheckArrayBound();
493 482 RangeBoundary array_length =
494 return false; 483 RangeBoundary::FromDefinition(check->length()->definition());
495 } 484 if (check->IsRedundant(array_length)) {
496 485 it.RemoveCurrentFromGraph();
497 486 }
498 void RangeAnalysis::CollectDefinitions(BlockEntryInstr* block, BitVector* set) { 487 }
499 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 488 }
500 !block_it.Done(); 489
501 block_it.Advance()) { 490 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
502 BlockEntryInstr* block = block_it.Current(); 491 InferRangesRecursive(block->dominated_blocks()[i]);
503 492 }
504 JoinEntryInstr* join = block->AsJoinEntry();
505 if (join != NULL) {
506 for (PhiIterator it(join); !it.Done(); it.Advance()) {
507 PhiInstr* phi = it.Current();
508 if (set->Contains(phi->ssa_temp_index())) {
509 definitions_.Add(phi);
510 }
511 }
512 }
513
514 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
515 Definition* defn = it.Current()->AsDefinition();
516 if ((defn != NULL) &&
517 (defn->ssa_temp_index() != -1) &&
518 set->Contains(defn->ssa_temp_index())) {
519 definitions_.Add(defn);
520 }
521 }
522 }
523 }
524
525
526 void RangeAnalysis::Iterate(JoinOperator op, intptr_t max_iterations) {
527 // TODO(vegorov): switch to worklist if this becomes performance bottleneck.
528 intptr_t iteration = 0;
529 bool changed;
530 do {
531 changed = false;
532 for (intptr_t i = 0; i < definitions_.length(); i++) {
533 Definition* defn = definitions_[i];
534 if (InferRange(op, defn, iteration)) {
535 changed = true;
536 }
537 }
538
539 iteration++;
540 } while (changed && (iteration < max_iterations));
541 } 493 }
542 494
543 495
544 void RangeAnalysis::InferRanges() { 496 void RangeAnalysis::InferRanges() {
545 if (FLAG_trace_range_analysis) { 497 if (FLAG_trace_range_analysis) {
546 FlowGraphPrinter::PrintGraph("Range Analysis (BEFORE)", flow_graph_); 498 OS::Print("---- before range analysis -------\n");
547 } 499 FlowGraphPrinter printer(*flow_graph_);
548 500 printer.PrintBlocks();
501 }
549 // Initialize bitvector for quick filtering of int values. 502 // Initialize bitvector for quick filtering of int values.
550 BitVector* set = new(I) BitVector(flow_graph_->current_ssa_temp_index()); 503 definitions_ =
504 new(I) BitVector(flow_graph_->current_ssa_temp_index());
551 for (intptr_t i = 0; i < values_.length(); i++) { 505 for (intptr_t i = 0; i < values_.length(); i++) {
552 set->Add(values_[i]->ssa_temp_index()); 506 definitions_->Add(values_[i]->ssa_temp_index());
553 } 507 }
554 for (intptr_t i = 0; i < constraints_.length(); i++) { 508 for (intptr_t i = 0; i < constraints_.length(); i++) {
555 set->Add(constraints_[i]->ssa_temp_index()); 509 definitions_->Add(constraints_[i]->ssa_temp_index());
556 } 510 }
557 511
558 // Collect integer definitions (including constraints) in the reverse 512 // Infer initial values of ranges.
559 // postorder. This improves convergence speed compared to iterating
560 // values_ and constraints_ array separately.
561 const GrowableArray<Definition*>& initial = 513 const GrowableArray<Definition*>& initial =
562 *flow_graph_->graph_entry()->initial_definitions(); 514 *flow_graph_->graph_entry()->initial_definitions();
563 for (intptr_t i = 0; i < initial.length(); ++i) { 515 for (intptr_t i = 0; i < initial.length(); ++i) {
564 Definition* definition = initial[i]; 516 Definition* definition = initial[i];
565 if (set->Contains(definition->ssa_temp_index())) { 517 if (definitions_->Contains(definition->ssa_temp_index())) {
566 definitions_.Add(definition); 518 definition->InferRange();
567 } 519 }
568 } 520 }
569 CollectDefinitions(flow_graph_->graph_entry(), set); 521 InferRangesRecursive(flow_graph_->graph_entry());
570
571 // Perform an iteration of range inference just propagating ranges
572 // through the graph as-is without applying widening or narrowing.
573 // This helps to improve precision of initial bounds.
574 Iterate(NONE, 1);
575
576 // Perform fix-point iteration of range inference applying widening
577 // operator to phis to ensure fast convergence.
578 // Widening simply maps growing bounds to the respective range bound.
579 Iterate(WIDEN, kMaxInt32);
580 522
581 if (FLAG_trace_range_analysis) { 523 if (FLAG_trace_range_analysis) {
582 FlowGraphPrinter::PrintGraph("Range Analysis (WIDEN)", flow_graph_); 524 OS::Print("---- after range analysis -------\n");
583 } 525 FlowGraphPrinter printer(*flow_graph_);
584 526 printer.PrintBlocks();
585 // Perform fix-point iteration of range inference applying narrowing 527 }
586 // to phis to compute more accurate range. 528 }
587 // Narrowing only improves those boundaries that were widened up to 529
588 // range boundary and leaves other boundaries intact.
589 Iterate(NARROW, kMaxInt32);
590
591 if (FLAG_trace_range_analysis) {
592 FlowGraphPrinter::PrintGraph("Range Analysis (AFTER)", flow_graph_);
593 }
594 }
595
596
597 void RangeAnalysis::EliminateRedundantBoundsChecks() {
598 if (FLAG_array_bounds_check_elimination) {
599 for (intptr_t i = 0; i < bounds_checks_.length(); i++) {
600 CheckArrayBoundInstr* check = bounds_checks_[i];
601 RangeBoundary array_length =
602 RangeBoundary::FromDefinition(check->length()->definition());
603 if (check->IsRedundant(array_length)) {
604 check->RemoveFromGraph();
605 }
606 }
607 }
608 }
609
610
611 void RangeAnalysis::MarkUnreachableBlocks() {
612 for (intptr_t i = 0; i < constraints_.length(); i++) {
613 if (Range::IsUnknown(constraints_[i]->range())) {
614 TargetEntryInstr* target = constraints_[i]->target();
615 if (target == NULL) {
616 // TODO(vegorov): replace Constraint with an uncoditional
617 // deoptimization and kill all dominated dead code.
618 continue;
619 }
620
621 BranchInstr* branch =
622 target->PredecessorAt(0)->last_instruction()->AsBranch();
623 if (target == branch->true_successor()) {
624 // True unreachable.
625 if (FLAG_trace_constant_propagation) {
626 OS::Print("Range analysis: True unreachable (B%" Pd ")\n",
627 branch->true_successor()->block_id());
628 }
629 branch->set_constant_target(branch->false_successor());
630 } else {
631 ASSERT(target == branch->false_successor());
632 // False unreachable.
633 if (FLAG_trace_constant_propagation) {
634 OS::Print("Range analysis: False unreachable (B%" Pd ")\n",
635 branch->false_successor()->block_id());
636 }
637 branch->set_constant_target(branch->true_successor());
638 }
639 }
640 }
641 }
642
643 530
644 void RangeAnalysis::RemoveConstraints() { 531 void RangeAnalysis::RemoveConstraints() {
645 for (intptr_t i = 0; i < constraints_.length(); i++) { 532 for (intptr_t i = 0; i < constraints_.length(); i++) {
646 Definition* def = constraints_[i]->value()->definition(); 533 Definition* def = constraints_[i]->value()->definition();
647 // Some constraints might be constraining constraints. Unwind the chain of 534 // Some constraints might be constraining constraints. Unwind the chain of
648 // constraints until we reach the actual definition. 535 // constraints until we reach the actual definition.
649 while (def->IsConstraint()) { 536 while (def->IsConstraint()) {
650 def = def->AsConstraint()->value()->definition(); 537 def = def->AsConstraint()->value()->definition();
651 } 538 }
652 constraints_[i]->ReplaceUsesWith(def); 539 constraints_[i]->ReplaceUsesWith(def);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 } 800 }
914 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); 801 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs);
915 } 802 }
916 803
917 804
918 RangeBoundary RangeBoundary::LowerBound() const { 805 RangeBoundary RangeBoundary::LowerBound() const {
919 if (IsInfinity()) { 806 if (IsInfinity()) {
920 return NegativeInfinity(); 807 return NegativeInfinity();
921 } 808 }
922 if (IsConstant()) return *this; 809 if (IsConstant()) return *this;
923 return Add(Range::ConstantMinSmi(symbol()->range()), 810 return Add(Range::ConstantMin(symbol()->range()),
924 RangeBoundary::FromConstant(offset_), 811 RangeBoundary::FromConstant(offset_),
925 NegativeInfinity()); 812 NegativeInfinity());
926 } 813 }
927 814
928 815
929 RangeBoundary RangeBoundary::UpperBound() const { 816 RangeBoundary RangeBoundary::UpperBound() const {
930 if (IsInfinity()) { 817 if (IsInfinity()) {
931 return PositiveInfinity(); 818 return PositiveInfinity();
932 } 819 }
933 if (IsConstant()) return *this; 820 if (IsConstant()) return *this;
934 821 return Add(Range::ConstantMax(symbol()->range()),
935 return Add(Range::ConstantMaxSmi(symbol()->range()),
936 RangeBoundary::FromConstant(offset_), 822 RangeBoundary::FromConstant(offset_),
937 PositiveInfinity()); 823 PositiveInfinity());
938 } 824 }
939 825
940 826
941 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, 827 RangeBoundary RangeBoundary::Add(const RangeBoundary& a,
942 const RangeBoundary& b, 828 const RangeBoundary& b,
943 const RangeBoundary& overflow) { 829 const RangeBoundary& overflow) {
944 if (a.IsInfinity() || b.IsInfinity()) return overflow; 830 if (a.IsInfinity() || b.IsInfinity()) return overflow;
945 831
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 884
999 const int64_t offset = a.offset() - b.ConstantValue(); 885 const int64_t offset = a.offset() - b.ConstantValue();
1000 886
1001 *result = RangeBoundary::FromDefinition(a.symbol(), offset); 887 *result = RangeBoundary::FromDefinition(a.symbol(), offset);
1002 return true; 888 return true;
1003 } 889 }
1004 return false; 890 return false;
1005 } 891 }
1006 892
1007 893
894 static Definition* UnwrapConstraint(Definition* defn) {
895 while (defn->IsConstraint()) {
896 defn = defn->AsConstraint()->value()->definition();
897 }
898 return defn;
899 }
900
901
902 static bool AreEqualDefinitions(Definition* a, Definition* b) {
903 a = UnwrapConstraint(a);
904 b = UnwrapConstraint(b);
905 return (a == b) ||
906 (a->AllowsCSE() &&
907 a->Dependencies().IsNone() &&
908 b->AllowsCSE() &&
909 b->Dependencies().IsNone() &&
910 a->Equals(b));
911 }
912
913
914 // Returns true if two range boundaries refer to the same symbol.
915 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) {
916 return a.IsSymbol() && b.IsSymbol() &&
917 AreEqualDefinitions(a.symbol(), b.symbol());
918 }
919
920
1008 bool RangeBoundary::Equals(const RangeBoundary& other) const { 921 bool RangeBoundary::Equals(const RangeBoundary& other) const {
1009 if (IsConstant() && other.IsConstant()) { 922 if (IsConstant() && other.IsConstant()) {
1010 return ConstantValue() == other.ConstantValue(); 923 return ConstantValue() == other.ConstantValue();
1011 } else if (IsInfinity() && other.IsInfinity()) { 924 } else if (IsInfinity() && other.IsInfinity()) {
1012 return kind() == other.kind(); 925 return kind() == other.kind();
1013 } else if (IsSymbol() && other.IsSymbol()) { 926 } else if (IsSymbol() && other.IsSymbol()) {
1014 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); 927 return (offset() == other.offset()) && DependOnSameSymbol(*this, other);
1015 } else if (IsUnknown() && other.IsUnknown()) { 928 } else if (IsUnknown() && other.IsUnknown()) {
1016 return true; 929 return true;
1017 } 930 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1137 1050
1138 const int64_t offset = range->min().offset() + a->offset(); 1051 const int64_t offset = range->min().offset() + a->offset();
1139 1052
1140 *a = CanonicalizeBoundary( 1053 *a = CanonicalizeBoundary(
1141 RangeBoundary::FromDefinition(range->min().symbol(), offset), 1054 RangeBoundary::FromDefinition(range->min().symbol(), offset),
1142 RangeBoundary::NegativeInfinity()); 1055 RangeBoundary::NegativeInfinity());
1143 1056
1144 return true; 1057 return true;
1145 } 1058 }
1146 1059
1147 typedef bool (*BoundaryOp)(RangeBoundary*);
1148 1060
1149 static bool CanonicalizeForComparison(RangeBoundary* a, 1061 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b,
1150 RangeBoundary* b, 1062 RangeSize size) {
1151 BoundaryOp op, 1063 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity()));
1152 const RangeBoundary& overflow) { 1064 ASSERT(!a.IsUnknown() || !b.IsUnknown());
1153 if (!a->IsSymbol() || !b->IsSymbol()) { 1065 if (a.IsUnknown() && !b.IsUnknown()) {
1154 return false; 1066 return b;
1067 }
1068 if (!a.IsUnknown() && b.IsUnknown()) {
1069 return a;
1070 }
1071 if (size == kRangeBoundarySmi) {
1072 if (a.IsSmiMaximumOrAbove() && !b.IsSmiMaximumOrAbove()) {
1073 return b;
1074 }
1075 if (!a.IsSmiMaximumOrAbove() && b.IsSmiMaximumOrAbove()) {
1076 return a;
1077 }
1078 } else {
1079 ASSERT(size == kRangeBoundaryInt64);
1080 if (a.IsMaximumOrAbove() && !b.IsMaximumOrAbove()) {
1081 return b;
1082 }
1083 if (!a.IsMaximumOrAbove() && b.IsMaximumOrAbove()) {
1084 return a;
1085 }
1155 } 1086 }
1156 1087
1157 if (DependOnSameSymbol(*a, *b)) {
1158 return true;
1159 }
1160
1161
1162 RangeBoundary canonical_a = CanonicalizeBoundary(*a, overflow);
1163 RangeBoundary canonical_b = CanonicalizeBoundary(*b, overflow);
1164
1165 do {
1166 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1167 *a = canonical_a;
1168 *b = canonical_b;
1169 return true;
1170 }
1171 } while (op(&canonical_a) || op(&canonical_b));
1172
1173 return false;
1174 }
1175
1176
1177 RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) {
1178 if (a.Equals(b)) { 1088 if (a.Equals(b)) {
1179 return b; 1089 return b;
1180 } 1090 }
1181 1091
1182 if (CanonicalizeForComparison(&a, 1092 {
1183 &b, 1093 RangeBoundary canonical_a =
1184 &CanonicalizeMinBoundary, 1094 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity());
1185 RangeBoundary::NegativeInfinity())) { 1095 RangeBoundary canonical_b =
1096 CanonicalizeBoundary(b, RangeBoundary::PositiveInfinity());
1097 do {
1098 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1099 a = canonical_a;
1100 b = canonical_b;
1101 break;
1102 }
1103 } while (CanonicalizeMaxBoundary(&canonical_a) ||
1104 CanonicalizeMaxBoundary(&canonical_b));
1105 }
1106
1107 if (DependOnSameSymbol(a, b)) {
1186 return (a.offset() <= b.offset()) ? a : b; 1108 return (a.offset() <= b.offset()) ? a : b;
1187 } 1109 }
1188 1110
1189 const int64_t inf_a = a.SmiLowerBound(); 1111 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue();
1190 const int64_t inf_b = b.SmiLowerBound(); 1112 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue();
1191 const int64_t sup_a = a.SmiUpperBound();
1192 const int64_t sup_b = b.SmiUpperBound();
1193 1113
1194 if ((sup_a <= inf_b) && !a.LowerBound().OverflowedSmi()) { 1114 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b));
1195 return a;
1196 } else if ((sup_b <= inf_a) && !b.LowerBound().OverflowedSmi()) {
1197 return b;
1198 } else {
1199 return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b));
1200 }
1201 } 1115 }
1202 1116
1203 1117
1204 RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) { 1118 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b,
1119 RangeSize size) {
1120 ASSERT(!(a.IsPositiveInfinity() || b.IsPositiveInfinity()));
1121 ASSERT(!a.IsUnknown() || !b.IsUnknown());
1122 if (a.IsUnknown() && !b.IsUnknown()) {
1123 return b;
1124 }
1125 if (!a.IsUnknown() && b.IsUnknown()) {
1126 return a;
1127 }
1128 if (size == kRangeBoundarySmi) {
1129 if (a.IsSmiMinimumOrBelow() && !b.IsSmiMinimumOrBelow()) {
1130 return b;
1131 }
1132 if (!a.IsSmiMinimumOrBelow() && b.IsSmiMinimumOrBelow()) {
1133 return a;
1134 }
1135 } else {
1136 ASSERT(size == kRangeBoundaryInt64);
1137 if (a.IsMinimumOrBelow() && !b.IsMinimumOrBelow()) {
1138 return b;
1139 }
1140 if (!a.IsMinimumOrBelow() && b.IsMinimumOrBelow()) {
1141 return a;
1142 }
1143 }
1205 if (a.Equals(b)) { 1144 if (a.Equals(b)) {
1206 return b; 1145 return b;
1207 } 1146 }
1208 1147
1209 if (CanonicalizeForComparison(&a, 1148 {
1210 &b, 1149 RangeBoundary canonical_a =
1211 &CanonicalizeMaxBoundary, 1150 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity());
1212 RangeBoundary::PositiveInfinity())) { 1151 RangeBoundary canonical_b =
1213 return (a.offset() >= b.offset()) ? a : b; 1152 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity());
1153
1154 do {
1155 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1156 a = canonical_a;
1157 b = canonical_b;
1158 break;
1159 }
1160 } while (CanonicalizeMinBoundary(&canonical_a) ||
1161 CanonicalizeMinBoundary(&canonical_b));
1214 } 1162 }
1215 1163
1216 const int64_t inf_a = a.SmiLowerBound(); 1164 if (DependOnSameSymbol(a, b)) {
1217 const int64_t inf_b = b.SmiLowerBound(); 1165 return (a.offset() <= b.offset()) ? b : a;
1218 const int64_t sup_a = a.SmiUpperBound(); 1166 }
1219 const int64_t sup_b = b.SmiUpperBound();
1220 1167
1221 if ((sup_a <= inf_b) && !b.UpperBound().OverflowedSmi()) { 1168 const int64_t max_a = a.LowerBound().Clamp(size).ConstantValue();
1222 return b; 1169 const int64_t max_b = b.LowerBound().Clamp(size).ConstantValue();
1223 } else if ((sup_b <= inf_a) && !a.UpperBound().OverflowedSmi()) { 1170
1224 return a; 1171 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b));
1225 } else {
1226 return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b));
1227 }
1228 } 1172 }
1229 1173
1230 1174
1231 RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) {
1232 ASSERT(!a.IsPositiveInfinity() && !b.IsPositiveInfinity());
1233 ASSERT(!a.IsUnknown() && !b.IsUnknown());
1234
1235 if (a.Equals(b)) {
1236 return a;
1237 }
1238
1239 if (a.IsSmiMinimumOrBelow()) {
1240 return b;
1241 } else if (b.IsSmiMinimumOrBelow()) {
1242 return a;
1243 }
1244
1245 if (CanonicalizeForComparison(&a,
1246 &b,
1247 &CanonicalizeMinBoundary,
1248 RangeBoundary::NegativeInfinity())) {
1249 return (a.offset() >= b.offset()) ? a : b;
1250 }
1251
1252 const int64_t inf_a = a.SmiLowerBound();
1253 const int64_t inf_b = b.SmiLowerBound();
1254
1255 return (inf_a >= inf_b) ? a : b;
1256 }
1257
1258
1259 RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) {
1260 ASSERT(!a.IsNegativeInfinity() && !b.IsNegativeInfinity());
1261 ASSERT(!a.IsUnknown() && !b.IsUnknown());
1262
1263 if (a.Equals(b)) {
1264 return a;
1265 }
1266
1267 if (a.IsSmiMaximumOrAbove()) {
1268 return b;
1269 } else if (b.IsSmiMaximumOrAbove()) {
1270 return a;
1271 }
1272
1273 if (CanonicalizeForComparison(&a,
1274 &b,
1275 &CanonicalizeMaxBoundary,
1276 RangeBoundary::PositiveInfinity())) {
1277 return (a.offset() <= b.offset()) ? a : b;
1278 }
1279
1280 const int64_t sup_a = a.SmiUpperBound();
1281 const int64_t sup_b = b.SmiUpperBound();
1282
1283 return (sup_a <= sup_b) ? a : b;
1284 }
1285
1286
1287 int64_t RangeBoundary::ConstantValue() const { 1175 int64_t RangeBoundary::ConstantValue() const {
1288 ASSERT(IsConstant()); 1176 ASSERT(IsConstant());
1289 return value_; 1177 return value_;
1290 } 1178 }
1291 1179
1292 1180
1293 bool Range::IsPositive() const { 1181 bool Range::IsPositive() const {
1294 if (min().IsNegativeInfinity()) { 1182 if (min().IsNegativeInfinity()) {
1295 return false; 1183 return false;
1296 } 1184 }
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1458 } 1346 }
1459 1347
1460 return false; 1348 return false;
1461 } 1349 }
1462 1350
1463 1351
1464 static bool IsArrayLength(Definition* defn) { 1352 static bool IsArrayLength(Definition* defn) {
1465 if (defn == NULL) { 1353 if (defn == NULL) {
1466 return false; 1354 return false;
1467 } 1355 }
1468 LoadFieldInstr* load = UnwrapConstraint(defn)->AsLoadField(); 1356 LoadFieldInstr* load = defn->AsLoadField();
1469 return (load != NULL) && load->IsImmutableLengthLoad(); 1357 return (load != NULL) && load->IsImmutableLengthLoad();
1470 } 1358 }
1471 1359
1472 1360
1473 void Range::Add(const Range* left_range, 1361 void Range::Add(const Range* left_range,
1474 const Range* right_range, 1362 const Range* right_range,
1475 RangeBoundary* result_min, 1363 RangeBoundary* result_min,
1476 RangeBoundary* result_max, 1364 RangeBoundary* result_max,
1477 Definition* left_defn) { 1365 Definition* left_defn) {
1478 ASSERT(left_range != NULL); 1366 ASSERT(left_range != NULL);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1550 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { 1438 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) {
1551 const int64_t r_min = 1439 const int64_t r_min =
1552 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; 1440 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
1553 *result_min = RangeBoundary::FromConstant(r_min); 1441 *result_min = RangeBoundary::FromConstant(r_min);
1554 const int64_t r_max = 1442 const int64_t r_max =
1555 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; 1443 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
1556 *result_max = RangeBoundary::FromConstant(r_max); 1444 *result_max = RangeBoundary::FromConstant(r_max);
1557 return true; 1445 return true;
1558 } 1446 }
1559 } 1447 }
1560
1561 // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range.
1562 if (OnlyPositiveOrZero(*left_range, *right_range) ||
1563 OnlyNegativeOrZero(*left_range, *right_range)) {
1564 *result_min = RangeBoundary::FromConstant(0);
1565 *result_max = RangeBoundary::PositiveInfinity();
1566 return true;
1567 }
1568
1569 return false; 1448 return false;
1570 } 1449 }
1571 1450
1572 1451
1573 // Both the a and b ranges are >= 0. 1452 // Both the a and b ranges are >= 0.
1574 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { 1453 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) {
1575 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); 1454 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0);
1576 } 1455 }
1577 1456
1578 1457
1579 // Both the a and b ranges are <= 0. 1458 // Both the a and b ranges are <= 0.
1580 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { 1459 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) {
1581 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); 1460 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0);
1582 } 1461 }
1583 1462
1584 1463
1585 // Return the maximum absolute value included in range. 1464 // Return the maximum absolute value included in range.
1586 int64_t Range::ConstantAbsMax(const Range* range) { 1465 int64_t Range::ConstantAbsMax(const Range* range) {
1587 if (range == NULL) { 1466 if (range == NULL) {
1588 return RangeBoundary::kMax; 1467 return RangeBoundary::kMax;
1589 } 1468 }
1590 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); 1469 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue());
1591 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); 1470 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue());
1592 return Utils::Maximum(abs_min, abs_max); 1471 return Utils::Maximum(abs_min, abs_max);
1593 } 1472 }
1594 1473
1595 1474
1596 void Range::BinaryOp(const Token::Kind op, 1475 Range* Range::BinaryOp(const Token::Kind op,
1597 const Range* left_range, 1476 const Range* left_range,
1598 const Range* right_range, 1477 const Range* right_range,
1599 Definition* left_defn, 1478 Definition* left_defn) {
1600 Range* result) {
1601 ASSERT(left_range != NULL); 1479 ASSERT(left_range != NULL);
1602 ASSERT(right_range != NULL); 1480 ASSERT(right_range != NULL);
1603 1481
1604 // Both left and right ranges are finite. 1482 // Both left and right ranges are finite.
1605 ASSERT(left_range->IsFinite()); 1483 ASSERT(left_range->IsFinite());
1606 ASSERT(right_range->IsFinite()); 1484 ASSERT(right_range->IsFinite());
1607 1485
1608 RangeBoundary min; 1486 RangeBoundary min;
1609 RangeBoundary max; 1487 RangeBoundary max;
1610 ASSERT(min.IsUnknown() && max.IsUnknown()); 1488 ASSERT(min.IsUnknown() && max.IsUnknown());
1611 1489
1612 switch (op) { 1490 switch (op) {
1613 case Token::kADD: 1491 case Token::kADD:
1614 Range::Add(left_range, right_range, &min, &max, left_defn); 1492 Range::Add(left_range, right_range, &min, &max, left_defn);
1615 break; 1493 break;
1616 case Token::kSUB: 1494 case Token::kSUB:
1617 Range::Sub(left_range, right_range, &min, &max, left_defn); 1495 Range::Sub(left_range, right_range, &min, &max, left_defn);
1618 break; 1496 break;
1619 case Token::kMUL: { 1497 case Token::kMUL: {
1620 if (!Range::Mul(left_range, right_range, &min, &max)) { 1498 if (!Range::Mul(left_range, right_range, &min, &max)) {
1621 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); 1499 return NULL;
1622 return;
1623 } 1500 }
1624 break; 1501 break;
1625 } 1502 }
1626 case Token::kSHL: { 1503 case Token::kSHL: {
1627 Range::Shl(left_range, right_range, &min, &max); 1504 Range::Shl(left_range, right_range, &min, &max);
1628 break; 1505 break;
1629 } 1506 }
1630 case Token::kSHR: { 1507 case Token::kSHR: {
1631 Range::Shr(left_range, right_range, &min, &max); 1508 Range::Shr(left_range, right_range, &min, &max);
1632 break; 1509 break;
1633 } 1510 }
1634 case Token::kBIT_AND: 1511 case Token::kBIT_AND:
1635 if (!Range::And(left_range, right_range, &min, &max)) { 1512 if (!Range::And(left_range, right_range, &min, &max)) {
1636 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); 1513 return NULL;
1637 return;
1638 } 1514 }
1639 break; 1515 break;
1640 default: 1516 default:
1641 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); 1517 return NULL;
1642 return; 1518 break;
1643 } 1519 }
1644 1520
1645 ASSERT(!min.IsUnknown() && !max.IsUnknown()); 1521 ASSERT(!min.IsUnknown() && !max.IsUnknown());
1646 1522
1647 *result = Range(min, max); 1523 return new Range(min, max);
1648 } 1524 }
1649 1525
1650 1526
1651 void Definition::set_range(const Range& range) { 1527 void Definition::InferRange() {
1652 if (range_ == NULL) {
1653 range_ = new Range();
1654 }
1655 *range_ = range;
1656 }
1657
1658
1659 void Definition::InferRange(Range* range) {
1660 if (Type()->ToCid() == kSmiCid) { 1528 if (Type()->ToCid() == kSmiCid) {
1661 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); 1529 if (range_ == NULL) {
1530 range_ = Range::UnknownSmi();
1531 }
1662 } else if (IsMintDefinition()) { 1532 } else if (IsMintDefinition()) {
1663 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); 1533 if (range_ == NULL) {
1534 range_ = Range::Unknown();
1535 }
1664 } else { 1536 } else {
1665 // Only Smi and Mint supported. 1537 // Only Smi and Mint supported.
1666 UNREACHABLE(); 1538 UNREACHABLE();
1667 } 1539 }
1668 } 1540 }
1669 1541
1670 1542
1671 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { 1543 void PhiInstr::InferRange() {
1672 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); 1544 RangeBoundary new_min;
1545 RangeBoundary new_max;
1546
1547 ASSERT(Type()->ToCid() == kSmiCid);
1548
1549 for (intptr_t i = 0; i < InputCount(); i++) {
1550 Range* input_range = InputAt(i)->definition()->range();
1551 if (input_range == NULL) {
1552 range_ = Range::UnknownSmi();
1553 return;
1554 }
1555
1556 if (new_min.IsUnknown()) {
1557 new_min = Range::ConstantMin(input_range);
1558 } else {
1559 new_min = RangeBoundary::Min(new_min,
1560 Range::ConstantMinSmi(input_range),
1561 RangeBoundary::kRangeBoundarySmi);
1562 }
1563
1564 if (new_max.IsUnknown()) {
1565 new_max = Range::ConstantMax(input_range);
1566 } else {
1567 new_max = RangeBoundary::Max(new_max,
1568 Range::ConstantMaxSmi(input_range),
1569 RangeBoundary::kRangeBoundarySmi);
1570 }
1571 }
1572
1573 ASSERT(new_min.IsUnknown() == new_max.IsUnknown());
1574 if (new_min.IsUnknown()) {
1575 range_ = Range::UnknownSmi();
1576 return;
1577 }
1578
1579 range_ = new Range(new_min, new_max);
1673 } 1580 }
1674 1581
1675 1582
1676 // Given the range and definition update the range so that 1583 void ConstantInstr::InferRange() {
1677 // it covers both original range and defintions range.
1678 //
1679 // The following should also hold:
1680 //
1681 // [_|_, _|_] U a = a U [_|_, _|_] = a
1682 //
1683 static void Join(Range* range, Definition* defn) {
1684 if (Range::IsUnknown(defn->range())) {
1685 return;
1686 }
1687
1688 if (Range::IsUnknown(range)) {
1689 *range = *defn->range();
1690 return;
1691 }
1692
1693 Range other = *defn->range();
1694
1695 // Handle patterns where range already depends on defn as a symbol:
1696 //
1697 // (..., S+o] U range(S) and [S+o, ...) U range(S)
1698 //
1699 // To improve precision of the computed join use [S, S] instead of
1700 // using range(S). It will be canonicalized away by JoinMin/JoinMax
1701 // functions.
1702 Definition* unwrapped = UnwrapConstraint(defn);
1703 if (DependsOnSymbol(range->min(), unwrapped) ||
1704 DependsOnSymbol(range->max(), unwrapped)) {
1705 other = Range(RangeBoundary::FromDefinition(defn, 0),
1706 RangeBoundary::FromDefinition(defn, 0));
1707 }
1708
1709 // First try to compare ranges based on their upper and lower bounds.
1710 const int64_t inf_range = range->min().SmiLowerBound();
1711 const int64_t inf_other = other.min().SmiLowerBound();
1712 const int64_t sup_range = range->max().SmiUpperBound();
1713 const int64_t sup_other = other.max().SmiUpperBound();
1714
1715 if (sup_range <= inf_other) {
1716 // The range is fully below defn's range. Keep the minimum and
1717 // expand the maximum.
1718 range->set_max(other.max());
1719 } else if (sup_other <= inf_range) {
1720 // The range is fully above defn's range. Keep the maximum and
1721 // expand the minimum.
1722 range->set_min(other.min());
1723 } else {
1724 // Can't compare ranges as whole. Join minimum and maximum separately.
1725 *range = Range(RangeBoundary::JoinMin(range->min(), other.min()),
1726 RangeBoundary::JoinMax(range->max(), other.max()));
1727 }
1728 }
1729
1730
1731 // When assigning range to a phi we must take care to avoid self-reference
1732 // cycles when phi's range depends on the phi itself.
1733 // To prevent such cases we impose additional restriction on symbols that
1734 // can be used as boundaries for phi's range: they must dominate
1735 // phi's definition.
1736 static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block,
1737 const RangeBoundary& a,
1738 const RangeBoundary& limit) {
1739 if (!a.IsSymbol() || a.symbol()->GetBlock()->Dominates(phi_block)) {
1740 return a;
1741 }
1742
1743 // Symbol does not dominate phi. Try unwrapping constraint and check again.
1744 Definition* unwrapped = UnwrapConstraint(a.symbol());
1745 if ((unwrapped != a.symbol()) &&
1746 unwrapped->GetBlock()->Dominates(phi_block)) {
1747 return RangeBoundary::FromDefinition(unwrapped, a.offset());
1748 }
1749
1750 return limit;
1751 }
1752
1753
1754 void PhiInstr::InferRange(Range* range) {
1755 ASSERT(Type()->ToCid() == kSmiCid);
1756 for (intptr_t i = 0; i < InputCount(); i++) {
1757 Join(range, InputAt(i)->definition());
1758 }
1759
1760 BlockEntryInstr* phi_block = GetBlock();
1761 range->set_min(EnsureAcyclicSymbol(
1762 phi_block, range->min(), RangeBoundary::MinSmi()));
1763 range->set_max(EnsureAcyclicSymbol(
1764 phi_block, range->max(), RangeBoundary::MaxSmi()));
1765 }
1766
1767
1768 void ConstantInstr::InferRange(Range* range) {
1769 if (value_.IsSmi()) { 1584 if (value_.IsSmi()) {
1770 int64_t value = Smi::Cast(value_).Value(); 1585 if (range_ == NULL) {
1771 *range = Range(RangeBoundary::FromConstant(value), 1586 int64_t value = Smi::Cast(value_).Value();
1772 RangeBoundary::FromConstant(value)); 1587 range_ = new Range(RangeBoundary::FromConstant(value),
1588 RangeBoundary::FromConstant(value));
1589 }
1773 } else if (value_.IsMint()) { 1590 } else if (value_.IsMint()) {
1774 int64_t value = Mint::Cast(value_).value(); 1591 if (range_ == NULL) {
1775 *range = Range(RangeBoundary::FromConstant(value), 1592 int64_t value = Mint::Cast(value_).value();
1776 RangeBoundary::FromConstant(value)); 1593 range_ = new Range(RangeBoundary::FromConstant(value),
1594 RangeBoundary::FromConstant(value));
1595 }
1777 } else { 1596 } else {
1778 // Only Smi and Mint supported. 1597 // Only Smi and Mint supported.
1779 UNREACHABLE(); 1598 UNREACHABLE();
1780 } 1599 }
1781 } 1600 }
1782 1601
1783 1602
1784 void ConstraintInstr::InferRange(Range* range) { 1603 void UnboxIntegerInstr::InferRange() {
1785 // Only constraining smi values. 1604 if (range_ == NULL) {
1786 ASSERT(value()->IsSmiValue()); 1605 Definition* unboxed = value()->definition();
1787 1606 ASSERT(unboxed != NULL);
1788 Range* value_range = value()->definition()->range(); 1607 Range* range = unboxed->range();
1789 if (Range::IsUnknown(value_range)) { 1608 if (range == NULL) {
1790 return; 1609 range_ = Range::Unknown();
1791 } 1610 return;
1792 1611 }
1793 // TODO(vegorov) check if precision of the analysis can be improved by 1612 range_ = new Range(range->min(), range->max());
1794 // recognizing intersections of the form:
1795 //
1796 // (..., S+x] ^ [S+x, ...) = [S+x, S+x]
1797 //
1798 Range result = value_range->Intersect(constraint());
1799 if (result.IsUnsatisfiable()) {
1800 return;
1801 }
1802
1803 *range = result;
1804 }
1805
1806
1807 void LoadFieldInstr::InferRange(Range* range) {
1808 switch (recognized_kind()) {
1809 case MethodRecognizer::kObjectArrayLength:
1810 case MethodRecognizer::kImmutableArrayLength:
1811 *range = Range(RangeBoundary::FromConstant(0),
1812 RangeBoundary::FromConstant(Array::kMaxElements));
1813 break;
1814
1815 case MethodRecognizer::kTypedDataLength:
1816 *range = Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi());
1817 break;
1818
1819 case MethodRecognizer::kStringBaseLength:
1820 *range = Range(RangeBoundary::FromConstant(0),
1821 RangeBoundary::FromConstant(String::kMaxElements));
1822 break;
1823
1824 default:
1825 Definition::InferRange(range);
1826 } 1613 }
1827 } 1614 }
1828 1615
1829 1616
1617 void ConstraintInstr::InferRange() {
1618 Range* value_range = value()->definition()->range();
1830 1619
1831 void LoadIndexedInstr::InferRange(Range* range) { 1620 // Only constraining smi values.
1621 ASSERT(value()->IsSmiValue());
1622
1623 RangeBoundary min;
1624 RangeBoundary max;
1625
1626 {
1627 RangeBoundary value_min = (value_range == NULL) ?
1628 RangeBoundary() : value_range->min();
1629 RangeBoundary constraint_min = constraint()->min();
1630 min = RangeBoundary::Max(value_min, constraint_min,
1631 RangeBoundary::kRangeBoundarySmi);
1632 }
1633
1634 ASSERT(!min.IsUnknown());
1635
1636 {
1637 RangeBoundary value_max = (value_range == NULL) ?
1638 RangeBoundary() : value_range->max();
1639 RangeBoundary constraint_max = constraint()->max();
1640 max = RangeBoundary::Min(value_max, constraint_max,
1641 RangeBoundary::kRangeBoundarySmi);
1642 }
1643
1644 ASSERT(!max.IsUnknown());
1645
1646 range_ = new Range(min, max);
1647
1648 // Mark branches that generate unsatisfiable constraints as constant.
1649 if (target() != NULL && range_->IsUnsatisfiable()) {
1650 BranchInstr* branch =
1651 target()->PredecessorAt(0)->last_instruction()->AsBranch();
1652 if (target() == branch->true_successor()) {
1653 // True unreachable.
1654 if (FLAG_trace_constant_propagation) {
1655 OS::Print("Range analysis: True unreachable (B%" Pd ")\n",
1656 branch->true_successor()->block_id());
1657 }
1658 branch->set_constant_target(branch->false_successor());
1659 } else {
1660 ASSERT(target() == branch->false_successor());
1661 // False unreachable.
1662 if (FLAG_trace_constant_propagation) {
1663 OS::Print("Range analysis: False unreachable (B%" Pd ")\n",
1664 branch->false_successor()->block_id());
1665 }
1666 branch->set_constant_target(branch->true_successor());
1667 }
1668 }
1669 }
1670
1671
1672 void LoadFieldInstr::InferRange() {
1673 if ((range_ == NULL) &&
1674 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) ||
1675 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) {
1676 range_ = new Range(RangeBoundary::FromConstant(0),
1677 RangeBoundary::FromConstant(Array::kMaxElements));
1678 return;
1679 }
1680 if ((range_ == NULL) &&
1681 (recognized_kind() == MethodRecognizer::kTypedDataLength)) {
1682 range_ = new Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi());
1683 return;
1684 }
1685 if ((range_ == NULL) &&
1686 (recognized_kind() == MethodRecognizer::kStringBaseLength)) {
1687 range_ = new Range(RangeBoundary::FromConstant(0),
1688 RangeBoundary::FromConstant(String::kMaxElements));
1689 return;
1690 }
1691 Definition::InferRange();
1692 }
1693
1694
1695
1696 void LoadIndexedInstr::InferRange() {
1832 switch (class_id()) { 1697 switch (class_id()) {
1833 case kTypedDataInt8ArrayCid: 1698 case kTypedDataInt8ArrayCid:
1834 *range = Range(RangeBoundary::FromConstant(-128), 1699 range_ = new Range(RangeBoundary::FromConstant(-128),
1835 RangeBoundary::FromConstant(127)); 1700 RangeBoundary::FromConstant(127));
1836 break; 1701 break;
1837 case kTypedDataUint8ArrayCid: 1702 case kTypedDataUint8ArrayCid:
1838 case kTypedDataUint8ClampedArrayCid: 1703 case kTypedDataUint8ClampedArrayCid:
1839 case kExternalTypedDataUint8ArrayCid: 1704 case kExternalTypedDataUint8ArrayCid:
1840 case kExternalTypedDataUint8ClampedArrayCid: 1705 case kExternalTypedDataUint8ClampedArrayCid:
1841 *range = Range(RangeBoundary::FromConstant(0), 1706 range_ = new Range(RangeBoundary::FromConstant(0),
1842 RangeBoundary::FromConstant(255)); 1707 RangeBoundary::FromConstant(255));
1843 break; 1708 break;
1844 case kTypedDataInt16ArrayCid: 1709 case kTypedDataInt16ArrayCid:
1845 *range = Range(RangeBoundary::FromConstant(-32768), 1710 range_ = new Range(RangeBoundary::FromConstant(-32768),
1846 RangeBoundary::FromConstant(32767)); 1711 RangeBoundary::FromConstant(32767));
1847 break; 1712 break;
1848 case kTypedDataUint16ArrayCid: 1713 case kTypedDataUint16ArrayCid:
1849 *range = Range(RangeBoundary::FromConstant(0), 1714 range_ = new Range(RangeBoundary::FromConstant(0),
1850 RangeBoundary::FromConstant(65535)); 1715 RangeBoundary::FromConstant(65535));
1851 break; 1716 break;
1852 case kTypedDataInt32ArrayCid: 1717 case kTypedDataInt32ArrayCid:
1853 if (Typed32BitIsSmi()) { 1718 if (Typed32BitIsSmi()) {
1854 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); 1719 range_ = Range::UnknownSmi();
1855 } else { 1720 } else {
1856 *range = Range(RangeBoundary::FromConstant(kMinInt32), 1721 range_ = new Range(RangeBoundary::FromConstant(kMinInt32),
1857 RangeBoundary::FromConstant(kMaxInt32)); 1722 RangeBoundary::FromConstant(kMaxInt32));
1858 } 1723 }
1859 break; 1724 break;
1860 case kTypedDataUint32ArrayCid: 1725 case kTypedDataUint32ArrayCid:
1861 if (Typed32BitIsSmi()) { 1726 if (Typed32BitIsSmi()) {
1862 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); 1727 range_ = Range::UnknownSmi();
1863 } else { 1728 } else {
1864 *range = Range(RangeBoundary::FromConstant(0), 1729 range_ = new Range(RangeBoundary::FromConstant(0),
1865 RangeBoundary::FromConstant(kMaxUint32)); 1730 RangeBoundary::FromConstant(kMaxUint32));
1866 } 1731 }
1867 break; 1732 break;
1868 case kOneByteStringCid: 1733 case kOneByteStringCid:
1869 *range = Range(RangeBoundary::FromConstant(0), 1734 range_ = new Range(RangeBoundary::FromConstant(0),
1870 RangeBoundary::FromConstant(0xFF)); 1735 RangeBoundary::FromConstant(0xFF));
1871 break; 1736 break;
1872 case kTwoByteStringCid: 1737 case kTwoByteStringCid:
1873 *range = Range(RangeBoundary::FromConstant(0), 1738 range_ = new Range(RangeBoundary::FromConstant(0),
1874 RangeBoundary::FromConstant(0xFFFF)); 1739 RangeBoundary::FromConstant(0xFFFF));
1875 break; 1740 break;
1876 default: 1741 default:
1877 Definition::InferRange(range); 1742 Definition::InferRange();
1878 break; 1743 break;
1879 } 1744 }
1880 } 1745 }
1881 1746
1882 1747
1883 void IfThenElseInstr::InferRange(Range* range) { 1748 void IfThenElseInstr::InferRange() {
1884 const intptr_t min = Utils::Minimum(if_true_, if_false_); 1749 const intptr_t min = Utils::Minimum(if_true_, if_false_);
1885 const intptr_t max = Utils::Maximum(if_true_, if_false_); 1750 const intptr_t max = Utils::Maximum(if_true_, if_false_);
1886 *range = Range(RangeBoundary::FromConstant(min), 1751 range_ = new Range(RangeBoundary::FromConstant(min),
1887 RangeBoundary::FromConstant(max)); 1752 RangeBoundary::FromConstant(max));
1888 } 1753 }
1889 1754
1890 1755
1891 void BinarySmiOpInstr::InferRange(Range* range) { 1756 void BinarySmiOpInstr::InferRange() {
1892 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the 1757 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the
1893 // right and a non-constant on the left. 1758 // right and a non-constant on the left.
1894 Definition* left_defn = left()->definition(); 1759 Definition* left_defn = left()->definition();
1895 1760
1896 Range* left_range = left_defn->range(); 1761 Range* left_range = left_defn->range();
1897 Range* right_range = right()->definition()->range(); 1762 Range* right_range = right()->definition()->range();
1898 1763
1899 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { 1764 if ((left_range == NULL) || (right_range == NULL)) {
1765 range_ = Range::UnknownSmi();
1900 return; 1766 return;
1901 } 1767 }
1902 1768
1903 Range::BinaryOp(op_kind(), 1769 Range* possible_range = Range::BinaryOp(op_kind(),
1904 left_range, 1770 left_range,
1905 right_range, 1771 right_range,
1906 left_defn, 1772 left_defn);
1907 range);
1908 ASSERT(!Range::IsUnknown(range));
1909 1773
1774 if ((range_ == NULL) && (possible_range == NULL)) {
1775 // Initialize.
1776 range_ = Range::UnknownSmi();
1777 return;
1778 }
1779
1780 if (possible_range == NULL) {
1781 // Nothing new.
1782 return;
1783 }
1784
1785 range_ = possible_range;
1786
1787 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1910 // Calculate overflowed status before clamping. 1788 // Calculate overflowed status before clamping.
1911 const bool overflowed = range->min().LowerBound().OverflowedSmi() || 1789 const bool overflowed = range_->min().LowerBound().OverflowedSmi() ||
1912 range->max().UpperBound().OverflowedSmi(); 1790 range_->max().UpperBound().OverflowedSmi();
1913 set_overflow(overflowed); 1791 set_overflow(overflowed);
1914 1792
1915 // Clamp value to be within smi range. 1793 // Clamp value to be within smi range.
1916 range->Clamp(RangeBoundary::kRangeBoundarySmi); 1794 range_->Clamp(RangeBoundary::kRangeBoundarySmi);
1917 } 1795 }
1918 1796
1919 1797
1920 void BinaryMintOpInstr::InferRange(Range* range) { 1798 void BinaryMintOpInstr::InferRange() {
1921 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on 1799 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on
1922 // the right and a non-constant on the left. 1800 // the right and a non-constant on the left.
1923 Definition* left_defn = left()->definition(); 1801 Definition* left_defn = left()->definition();
1924 1802
1925 Range* left_range = left_defn->range(); 1803 Range* left_range = left_defn->range();
1926 Range* right_range = right()->definition()->range(); 1804 Range* right_range = right()->definition()->range();
1927 1805
1928 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { 1806 if ((left_range == NULL) || (right_range == NULL)) {
1807 range_ = Range::Unknown();
1929 return; 1808 return;
1930 } 1809 }
1931 1810
1932 Range::BinaryOp(op_kind(), 1811 Range* possible_range = Range::BinaryOp(op_kind(),
1933 left_range, 1812 left_range,
1934 right_range, 1813 right_range,
1935 left_defn, 1814 left_defn);
1936 range); 1815
1937 ASSERT(!Range::IsUnknown(range)); 1816 if ((range_ == NULL) && (possible_range == NULL)) {
1817 // Initialize.
1818 range_ = Range::Unknown();
1819 return;
1820 }
1821
1822 if (possible_range == NULL) {
1823 // Nothing new.
1824 return;
1825 }
1826
1827 range_ = possible_range;
1828
1829 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1938 1830
1939 // Calculate overflowed status before clamping. 1831 // Calculate overflowed status before clamping.
1940 const bool overflowed = range->min().LowerBound().OverflowedMint() || 1832 const bool overflowed = range_->min().LowerBound().OverflowedMint() ||
1941 range->max().UpperBound().OverflowedMint(); 1833 range_->max().UpperBound().OverflowedMint();
1942 set_can_overflow(overflowed); 1834 set_can_overflow(overflowed);
1943 1835
1944 // Clamp value to be within mint range. 1836 // Clamp value to be within mint range.
1945 range->Clamp(RangeBoundary::kRangeBoundaryInt64); 1837 range_->Clamp(RangeBoundary::kRangeBoundaryInt64);
1946 } 1838 }
1947 1839
1948 1840
1949 void ShiftMintOpInstr::InferRange(Range* range) { 1841 void ShiftMintOpInstr::InferRange() {
1950 Definition* left_defn = left()->definition(); 1842 Definition* left_defn = left()->definition();
1951 1843
1952 Range* left_range = left_defn->range(); 1844 Range* left_range = left_defn->range();
1953 Range* right_range = right()->definition()->range(); 1845 Range* right_range = right()->definition()->range();
1954 1846
1955 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { 1847 if ((left_range == NULL) || (right_range == NULL)) {
1848 range_ = Range::Unknown();
1956 return; 1849 return;
1957 } 1850 }
1958 1851
1959 Range::BinaryOp(op_kind(), 1852 Range* possible_range = Range::BinaryOp(op_kind(),
1960 left_range, 1853 left_range,
1961 right_range, 1854 right_range,
1962 left_defn, 1855 left_defn);
1963 range); 1856
1964 ASSERT(!Range::IsUnknown(range)); 1857 if ((range_ == NULL) && (possible_range == NULL)) {
1858 // Initialize.
1859 range_ = Range::Unknown();
1860 return;
1861 }
1862
1863 if (possible_range == NULL) {
1864 // Nothing new.
1865 return;
1866 }
1867
1868 range_ = possible_range;
1869
1870 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1965 1871
1966 // Calculate overflowed status before clamping. 1872 // Calculate overflowed status before clamping.
1967 const bool overflowed = range->min().LowerBound().OverflowedMint() || 1873 const bool overflowed = range_->min().LowerBound().OverflowedMint() ||
1968 range->max().UpperBound().OverflowedMint(); 1874 range_->max().UpperBound().OverflowedMint();
1969 set_can_overflow(overflowed); 1875 set_can_overflow(overflowed);
1970 1876
1971 // Clamp value to be within mint range. 1877 // Clamp value to be within mint range.
1972 range->Clamp(RangeBoundary::kRangeBoundaryInt64); 1878 range_->Clamp(RangeBoundary::kRangeBoundaryInt64);
1973 } 1879 }
1974 1880
1975 1881
1976 void BoxIntegerInstr::InferRange(Range* range) { 1882 void BoxIntegerInstr::InferRange() {
1977 Range* input_range = value()->definition()->range(); 1883 Range* input_range = value()->definition()->range();
1978 if (input_range != NULL) { 1884 if (input_range != NULL) {
1979 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && 1885 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() &&
1980 !input_range->max().UpperBound().OverflowedSmi(); 1886 !input_range->max().UpperBound().OverflowedSmi();
1981 set_is_smi(is_smi); 1887 set_is_smi(is_smi);
1982 // The output range is the same as the input range. 1888 // The output range is the same as the input range.
1983 *range = *input_range; 1889 range_ = input_range;
1984 } 1890 }
1985 } 1891 }
1986 1892
1987
1988 void UnboxIntegerInstr::InferRange(Range* range) {
1989 Range* value_range = value()->definition()->range();
1990 if (value_range != NULL) {
1991 *range = *value_range;
1992 } else if (!value()->definition()->IsMintDefinition() &&
1993 (value()->Type()->ToCid() != kSmiCid)) {
1994 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64);
1995 }
1996 }
1997
1998 1893
1999 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { 1894 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) {
2000 Range* index_range = index()->definition()->range(); 1895 Range* index_range = index()->definition()->range();
2001 1896
2002 // Range of the index is unknown can't decide if the check is redundant. 1897 // Range of the index is unknown can't decide if the check is redundant.
2003 if (index_range == NULL) { 1898 if (index_range == NULL) {
2004 return false; 1899 return false;
2005 } 1900 }
2006 1901
2007 // Range of the index is not positive. Check can't be redundant. 1902 // Range of the index is not positive. Check can't be redundant.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2042 } 1937 }
2043 } while (CanonicalizeMaxBoundary(&max) || 1938 } while (CanonicalizeMaxBoundary(&max) ||
2044 CanonicalizeMinBoundary(&canonical_length)); 1939 CanonicalizeMinBoundary(&canonical_length));
2045 1940
2046 // Failed to prove that maximum is bounded with array length. 1941 // Failed to prove that maximum is bounded with array length.
2047 return false; 1942 return false;
2048 } 1943 }
2049 1944
2050 1945
2051 } // namespace dart 1946 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_range_analysis.h ('k') | runtime/vm/flow_graph_range_analysis_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698