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

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

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

Powered by Google App Engine
This is Rietveld 408576698