| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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_ |
| OLD | NEW |