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

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

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

Powered by Google App Engine
This is Rietveld 408576698