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

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

Issue 477193002: Reland r39293. (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 #ifndef VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ 5 #ifndef VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
6 #define VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ 6 #define VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
7 7
8 #include "vm/flow_graph.h" 8 #include "vm/flow_graph.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 10
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 // Construct a RangeBoundary for the constant kMin value. 77 // Construct a RangeBoundary for the constant kMin value.
78 static RangeBoundary MinConstant() { 78 static RangeBoundary MinConstant() {
79 return FromConstant(kMin); 79 return FromConstant(kMin);
80 } 80 }
81 81
82 // Construct a RangeBoundary for the constant kMax value. 82 // Construct a RangeBoundary for the constant kMax value.
83 static RangeBoundary MaxConstant() { 83 static RangeBoundary MaxConstant() {
84 return FromConstant(kMax); 84 return FromConstant(kMax);
85 } 85 }
86 86
87 // Calculate the minimum of a and b within the given range. 87 // Given two boundaries a and b, select one of them as c so that
88 static RangeBoundary Min(RangeBoundary a, RangeBoundary b, RangeSize size); 88 //
89 static RangeBoundary Max(RangeBoundary a, RangeBoundary b, RangeSize size); 89 // inf {[a, ...) ^ [b, ...)} >= inf {c}
90 //
91 static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b);
92
93 // Given two boundaries a and b, select one of them as c so that
94 //
95 // sup {(..., a] ^ (..., b]} <= sup {c}
96 //
97 static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b);
98
99 // Given two boundaries a and b compute boundary c such that
100 //
101 // inf {[a, ...) U [b, ...)} >= inf {c}
102 //
103 // Try to select c such that it is as close to inf {[a, ...) U [b, ...)}
104 // as possible.
105 static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b);
106
107 // Given two boundaries a and b compute boundary c such that
108 //
109 // sup {(..., a] U (..., b]} <= sup {c}
110 //
111 // Try to select c such that it is as close to sup {(..., a] U (..., b]}
112 // as possible.
113 static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b);
90 114
91 // Returns true when this is a constant that is outside of Smi range. 115 // Returns true when this is a constant that is outside of Smi range.
92 bool OverflowedSmi() const { 116 bool OverflowedSmi() const {
93 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); 117 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity();
94 } 118 }
95 119
96 // Returns true if this outside mint range. 120 // Returns true if this outside mint range.
97 bool OverflowedMint() const { 121 bool OverflowedMint() const {
98 return IsInfinity(); 122 return IsInfinity();
99 } 123 }
(...skipping 12 matching lines...) Expand all
112 } 136 }
113 if (ConstantValue() >= Smi::kMaxValue) { 137 if (ConstantValue() >= Smi::kMaxValue) {
114 return MaxSmi(); 138 return MaxSmi();
115 } 139 }
116 } 140 }
117 // If this range is a symbolic range, we do not clamp it. 141 // If this range is a symbolic range, we do not clamp it.
118 // This could lead to some imprecision later on. 142 // This could lead to some imprecision later on.
119 return *this; 143 return *this;
120 } 144 }
121 145
122
123 bool IsSmiMinimumOrBelow() const { 146 bool IsSmiMinimumOrBelow() const {
124 return IsNegativeInfinity() || 147 return IsNegativeInfinity() ||
125 (IsConstant() && (ConstantValue() <= Smi::kMinValue)); 148 (IsConstant() && (ConstantValue() <= Smi::kMinValue));
126 } 149 }
127 150
128 bool IsSmiMaximumOrAbove() const { 151 bool IsSmiMaximumOrAbove() const {
129 return IsPositiveInfinity() || 152 return IsPositiveInfinity() ||
130 (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); 153 (IsConstant() && (ConstantValue() >= Smi::kMaxValue));
131 } 154 }
132 155
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 238
216 // Attempts to calculate a - b when: 239 // Attempts to calculate a - b when:
217 // a is a symbol and b is a constant 240 // a is a symbol and b is a constant
218 // returns true if it succeeds, output is in result. 241 // returns true if it succeeds, output is in result.
219 static bool SymbolicSub(const RangeBoundary& a, 242 static bool SymbolicSub(const RangeBoundary& a,
220 const RangeBoundary& b, 243 const RangeBoundary& b,
221 RangeBoundary* result); 244 RangeBoundary* result);
222 245
223 bool Equals(const RangeBoundary& other) const; 246 bool Equals(const RangeBoundary& other) const;
224 247
248 int64_t SmiUpperBound() const {
249 return UpperBound().Clamp(kRangeBoundarySmi).ConstantValue();
250 }
251
252 int64_t SmiLowerBound() const {
253 return LowerBound().Clamp(kRangeBoundarySmi).ConstantValue();
254 }
255
225 private: 256 private:
226 RangeBoundary(Kind kind, int64_t value, int64_t offset) 257 RangeBoundary(Kind kind, int64_t value, int64_t offset)
227 : kind_(kind), value_(value), offset_(offset) { } 258 : kind_(kind), value_(value), offset_(offset) { }
228 259
229 Kind kind_; 260 Kind kind_;
230 int64_t value_; 261 int64_t value_;
231 int64_t offset_; 262 int64_t offset_;
232 }; 263 };
233 264
234 265
235 class Range : public ZoneAllocated { 266 class Range : public ZoneAllocated {
236 public: 267 public:
237 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { } 268 Range() : min_(), max_() { }
238 269 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) {
239 static Range* Unknown() { 270 ASSERT(min_.IsUnknown() == max_.IsUnknown());
240 return new Range(RangeBoundary::MinConstant(),
241 RangeBoundary::MaxConstant());
242 } 271 }
243 272
244 static Range* UnknownSmi() { 273 Range(const Range& other)
245 return new Range(RangeBoundary::MinSmi(), 274 : ZoneAllocated(),
246 RangeBoundary::MaxSmi()); 275 min_(other.min_),
276 max_(other.max_) {
277 }
278
279 Range& operator=(const Range& other) {
280 min_ = other.min_;
281 max_ = other.max_;
282 return *this;
283 }
284
285 static bool IsUnknown(const Range* other) {
286 if (other == NULL) {
287 return true;
288 }
289 return other->min().IsUnknown();
290 }
291
292 static Range Full(RangeBoundary::RangeSize size) {
293 if (size == RangeBoundary::kRangeBoundarySmi) {
294 return Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi());
295 } else {
296 ASSERT(size == RangeBoundary::kRangeBoundaryInt64);
297 return Range(RangeBoundary::MinConstant(), RangeBoundary::MaxConstant());
298 }
247 } 299 }
248 300
249 void PrintTo(BufferFormatter* f) const; 301 void PrintTo(BufferFormatter* f) const;
250 static const char* ToCString(const Range* range); 302 static const char* ToCString(const Range* range);
251 303
304 bool Equals(const Range* other) {
305 ASSERT(min_.IsUnknown() == max_.IsUnknown());
306 if (other == NULL) {
307 return min_.IsUnknown();
308 }
309 return min_.Equals(other->min_) &&
310 max_.Equals(other->max_);
311 }
312
252 const RangeBoundary& min() const { return min_; } 313 const RangeBoundary& min() const { return min_; }
253 const RangeBoundary& max() const { return max_; } 314 const RangeBoundary& max() const { return max_; }
315 void set_min(const RangeBoundary& value) {
316 min_ = value;
317 }
318 void set_max(const RangeBoundary& value) {
319 max_ = value;
320 }
254 321
255 static RangeBoundary ConstantMinSmi(const Range* range) { 322 static RangeBoundary ConstantMinSmi(const Range* range) {
256 if (range == NULL) { 323 if (range == NULL) {
257 return RangeBoundary::MinSmi(); 324 return RangeBoundary::MinSmi();
258 } 325 }
259 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi); 326 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi);
260 } 327 }
261 328
262 static RangeBoundary ConstantMaxSmi(const Range* range) { 329 static RangeBoundary ConstantMaxSmi(const Range* range) {
263 if (range == NULL) { 330 if (range == NULL) {
(...skipping 30 matching lines...) Expand all
294 361
295 // Inclusive. 362 // Inclusive.
296 bool Overlaps(int64_t min_int, int64_t max_int) const; 363 bool Overlaps(int64_t min_int, int64_t max_int) const;
297 364
298 bool IsUnsatisfiable() const; 365 bool IsUnsatisfiable() const;
299 366
300 bool IsFinite() const { 367 bool IsFinite() const {
301 return !min_.IsInfinity() && !max_.IsInfinity(); 368 return !min_.IsInfinity() && !max_.IsInfinity();
302 } 369 }
303 370
371 Range Intersect(const Range* other) const {
372 return Range(RangeBoundary::IntersectionMin(min(), other->min()),
373 RangeBoundary::IntersectionMax(max(), other->max()));
374 }
375
304 // Clamp this to be within size. 376 // Clamp this to be within size.
305 void Clamp(RangeBoundary::RangeSize size); 377 void Clamp(RangeBoundary::RangeSize size);
306 378
307 static void Add(const Range* left_range, 379 static void Add(const Range* left_range,
308 const Range* right_range, 380 const Range* right_range,
309 RangeBoundary* min, 381 RangeBoundary* min,
310 RangeBoundary* max, 382 RangeBoundary* max,
311 Definition* left_defn); 383 Definition* left_defn);
312 384
313 static void Sub(const Range* left_range, 385 static void Sub(const Range* left_range,
(...skipping 24 matching lines...) Expand all
338 410
339 // Both the a and b ranges are >= 0. 411 // Both the a and b ranges are >= 0.
340 static bool OnlyPositiveOrZero(const Range& a, const Range& b); 412 static bool OnlyPositiveOrZero(const Range& a, const Range& b);
341 413
342 // Both the a and b ranges are <= 0. 414 // Both the a and b ranges are <= 0.
343 static bool OnlyNegativeOrZero(const Range& a, const Range& b); 415 static bool OnlyNegativeOrZero(const Range& a, const Range& b);
344 416
345 // Return the maximum absolute value included in range. 417 // Return the maximum absolute value included in range.
346 static int64_t ConstantAbsMax(const Range* range); 418 static int64_t ConstantAbsMax(const Range* range);
347 419
348 static Range* BinaryOp(const Token::Kind op, 420 static void BinaryOp(const Token::Kind op,
349 const Range* left_range, 421 const Range* left_range,
350 const Range* right_range, 422 const Range* right_range,
351 Definition* left_defn); 423 Definition* left_defn,
424 Range* result);
352 425
353 private: 426 private:
354 RangeBoundary min_; 427 RangeBoundary min_;
355 RangeBoundary max_; 428 RangeBoundary max_;
356 }; 429 };
357 430
358 431
359 // Range analysis for integer values. 432 // Range analysis for integer values.
360 class RangeAnalysis : public ValueObject { 433 class RangeAnalysis : public ValueObject {
361 public: 434 public:
362 explicit RangeAnalysis(FlowGraph* flow_graph) 435 explicit RangeAnalysis(FlowGraph* flow_graph)
363 : flow_graph_(flow_graph), 436 : flow_graph_(flow_graph),
364 marked_defns_(NULL) { } 437 smi_range_(Range::Full(RangeBoundary::kRangeBoundarySmi)) { }
365 438
366 // Infer ranges for all values and remove overflow checks from binary smi 439 // Infer ranges for all values and remove overflow checks from binary smi
367 // operations when proven redundant. 440 // operations when proven redundant.
368 void Analyze(); 441 void Analyze();
369 442
443 // Helper that should be used to access ranges of inputs during range
444 // inference.
445 // Returns meaningful results for uses of non-smi definitions that have smi
446 // as a reaching type.
447 const Range* GetRange(Value* value) const;
448
370 private: 449 private:
450 enum JoinOperator {
451 NONE,
452 WIDEN,
453 NARROW
454 };
455 static char OpPrefix(JoinOperator op);
456
371 // Collect all values that were proven to be smi in smi_values_ array and all 457 // Collect all values that were proven to be smi in smi_values_ array and all
372 // CheckSmi instructions in smi_check_ array. 458 // CheckSmi instructions in smi_check_ array.
373 void CollectValues(); 459 void CollectValues();
374 460
375 // Iterate over smi values and constrain them at branch successors. 461 // Iterate over smi values and constrain them at branch successors.
376 // Additionally constraint values after CheckSmi instructions. 462 // Additionally constraint values after CheckSmi instructions.
377 void InsertConstraints(); 463 void InsertConstraints();
378 464
379 // Iterate over uses of the given definition and discover branches that 465 // Iterate over uses of the given definition and discover branches that
380 // constrain it. Insert appropriate Constraint instructions at true 466 // constrain it. Insert appropriate Constraint instructions at true
381 // and false successor and rename all dominated uses to refer to a 467 // and false successor and rename all dominated uses to refer to a
382 // Constraint instead of this definition. 468 // Constraint instead of this definition.
383 void InsertConstraintsFor(Definition* defn); 469 void InsertConstraintsFor(Definition* defn);
384 470
385 // Create a constraint for defn, insert it after given instruction and 471 // Create a constraint for defn, insert it after given instruction and
386 // rename all uses that are dominated by it. 472 // rename all uses that are dominated by it.
387 ConstraintInstr* InsertConstraintFor(Definition* defn, 473 ConstraintInstr* InsertConstraintFor(Value* use,
474 Definition* defn,
388 Range* constraint, 475 Range* constraint,
389 Instruction* after); 476 Instruction* after);
390 477
391 void ConstrainValueAfterBranch(Definition* defn, Value* use); 478 void ConstrainValueAfterBranch(Value* use, Definition* defn);
392 void ConstrainValueAfterCheckArrayBound(Definition* defn, 479 void ConstrainValueAfterCheckArrayBound(Value* use, Definition* defn);
393 CheckArrayBoundInstr* check,
394 intptr_t use_index);
395 480
396 // Replace uses of the definition def that are dominated by instruction dom 481 // Replace uses of the definition def that are dominated by instruction dom
397 // with uses of other definition. 482 // with uses of other definition.
398 void RenameDominatedUses(Definition* def, 483 void RenameDominatedUses(Definition* def,
399 Instruction* dom, 484 Instruction* dom,
400 Definition* other); 485 Definition* other);
401 486
402 487
403 // Walk the dominator tree and infer ranges for smi values. 488 // Infer ranges for integer (smi or mint) definitions.
404 void InferRanges(); 489 void InferRanges();
405 void InferRangesRecursive(BlockEntryInstr* block);
406 490
407 enum Direction { 491 // Collect integer definition in the reverse postorder.
408 kUnknown, 492 void CollectDefinitions(BlockEntryInstr* block, BitVector* set);
409 kPositive,
410 kNegative,
411 kBoth
412 };
413 493
414 Range* InferInductionVariableRange(JoinEntryInstr* loop_header, 494 // Recompute ranges of all definitions until they stop changing.
415 PhiInstr* var); 495 // Apply the given JoinOperator when computing Phi ranges.
496 void Iterate(JoinOperator op, intptr_t max_iterations);
497 bool InferRange(JoinOperator op, Definition* defn, intptr_t iteration);
416 498
417 void ResetWorklist(); 499 // Based on computed ranges find and eliminate redundant CheckArrayBound
418 void MarkDefinition(Definition* defn); 500 // instructions.
501 void EliminateRedundantBoundsChecks();
419 502
420 static Direction ToDirection(Value* val); 503 // Find unsatisfiable constraints and mark corresponding blocks unreachable.
421 504 void MarkUnreachableBlocks();
422 static Direction Invert(Direction direction) {
423 return (direction == kPositive) ? kNegative : kPositive;
424 }
425
426 static void UpdateDirection(Direction* direction,
427 Direction new_direction) {
428 if (*direction != new_direction) {
429 if (*direction != kUnknown) new_direction = kBoth;
430 *direction = new_direction;
431 }
432 }
433 505
434 // Remove artificial Constraint instructions and replace them with actual 506 // Remove artificial Constraint instructions and replace them with actual
435 // unconstrained definitions. 507 // unconstrained definitions.
436 void RemoveConstraints(); 508 void RemoveConstraints();
437 509
438 Range* ConstraintRange(Token::Kind op, Definition* boundary); 510 Range* ConstraintSmiRange(Token::Kind op, Definition* boundary);
439 511
440 Isolate* isolate() const { return flow_graph_->isolate(); } 512 Isolate* isolate() const { return flow_graph_->isolate(); }
441 513
442 FlowGraph* flow_graph_; 514 FlowGraph* flow_graph_;
443 515
516 // Range object representing full Smi range.
517 Range smi_range_;
518
444 // Value that are known to be smi or mint. 519 // Value that are known to be smi or mint.
445 GrowableArray<Definition*> values_; 520 GrowableArray<Definition*> values_;
446 // All CheckSmi instructions. 521
447 GrowableArray<CheckSmiInstr*> smi_checks_; 522 // All CheckArrayBound instructions.
523 GrowableArray<CheckArrayBoundInstr*> bounds_checks_;
448 524
449 // All Constraints inserted during InsertConstraints phase. They are treated 525 // All Constraints inserted during InsertConstraints phase. They are treated
450 // as smi values. 526 // as smi values.
451 GrowableArray<ConstraintInstr*> constraints_; 527 GrowableArray<ConstraintInstr*> constraints_;
452 528
453 // Bitvector for a quick filtering of known smi or mint values. 529 // List of integer (smi or mint) definitions including constraints sorted
454 BitVector* definitions_; 530 // in the reverse postorder.
455 531 GrowableArray<Definition*> definitions_;
456 // Worklist for induction variables analysis.
457 GrowableArray<Definition*> worklist_;
458 BitVector* marked_defns_;
459 532
460 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); 533 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis);
461 }; 534 };
462 535
463 536
464 // Replaces Mint IL instructions with Uint32 IL instructions 537 // Replaces Mint IL instructions with Uint32 IL instructions
465 // when possible. Uses output of RangeAnalysis. 538 // when possible. Uses output of RangeAnalysis.
466 class IntegerInstructionSelector : public ValueObject { 539 class IntegerInstructionSelector : public ValueObject {
467 public: 540 public:
468 explicit IntegerInstructionSelector(FlowGraph* flow_graph); 541 explicit IntegerInstructionSelector(FlowGraph* flow_graph);
(...skipping 17 matching lines...) Expand all
486 BitVector* selected_uint32_defs_; 559 BitVector* selected_uint32_defs_;
487 560
488 FlowGraph* flow_graph_; 561 FlowGraph* flow_graph_;
489 Isolate* isolate_; 562 Isolate* isolate_;
490 }; 563 };
491 564
492 565
493 } // namespace dart 566 } // namespace dart
494 567
495 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ 568 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/flow_graph_range_analysis.cc » ('j') | runtime/vm/flow_graph_range_analysis.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698