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

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

Issue 504143003: Support Int32 representation for selected binary operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 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
11 namespace dart { 11 namespace dart {
12 12
13 class RangeBoundary : public ValueObject { 13 class RangeBoundary : public ValueObject {
14 public: 14 public:
15 enum Kind { 15 enum Kind {
16 kUnknown, 16 kUnknown,
17 kNegativeInfinity, 17 kNegativeInfinity,
18 kPositiveInfinity, 18 kPositiveInfinity,
19 kSymbol, 19 kSymbol,
20 kConstant, 20 kConstant,
21 }; 21 };
22 22
23 enum RangeSize { 23 enum RangeSize {
24 kRangeBoundarySmi, 24 kRangeBoundarySmi,
25 kRangeBoundaryInt32,
25 kRangeBoundaryInt64, 26 kRangeBoundaryInt64,
26 }; 27 };
27 28
28 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { } 29 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { }
29 30
30 RangeBoundary(const RangeBoundary& other) 31 RangeBoundary(const RangeBoundary& other)
31 : ValueObject(), 32 : ValueObject(),
32 kind_(other.kind_), 33 kind_(other.kind_),
33 value_(other.value_), 34 value_(other.value_),
34 offset_(other.offset_) { } 35 offset_(other.offset_) { }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 // Construct a RangeBoundary for the constant MinSmi value. 68 // Construct a RangeBoundary for the constant MinSmi value.
68 static RangeBoundary MinSmi() { 69 static RangeBoundary MinSmi() {
69 return FromConstant(Smi::kMinValue); 70 return FromConstant(Smi::kMinValue);
70 } 71 }
71 72
72 // Construct a RangeBoundary for the constant MaxSmi value. 73 // Construct a RangeBoundary for the constant MaxSmi value.
73 static RangeBoundary MaxSmi() { 74 static RangeBoundary MaxSmi() {
74 return FromConstant(Smi::kMaxValue); 75 return FromConstant(Smi::kMaxValue);
75 } 76 }
76 77
77 // Construct a RangeBoundary for the constant kMin value. 78 // Construct a RangeBoundary for the constant kMin value.
78 static RangeBoundary MinConstant() { 79 static RangeBoundary MinConstant() {
79 return FromConstant(kMin); 80 return FromConstant(kMin);
80 } 81 }
81 82
82 // Construct a RangeBoundary for the constant kMax value. 83 // Construct a RangeBoundary for the constant kMax value.
83 static RangeBoundary MaxConstant() { 84 static RangeBoundary MaxConstant() {
84 return FromConstant(kMax); 85 return FromConstant(kMax);
85 } 86 }
86 87
88 // Construct a RangeBoundary for the constant kMin value.
89 static RangeBoundary MinConstant(RangeSize size) {
90 switch (size) {
91 case kRangeBoundarySmi:
92 return FromConstant(Smi::kMinValue);
93 case kRangeBoundaryInt32:
94 return FromConstant(kMinInt32);
95 case kRangeBoundaryInt64:
96 return FromConstant(kMinInt64);
97 }
98 UNREACHABLE();
99 return FromConstant(kMinInt64);
100 }
101
102 static RangeBoundary MaxConstant(RangeSize size) {
103 switch (size) {
104 case kRangeBoundarySmi:
105 return FromConstant(Smi::kMaxValue);
106 case kRangeBoundaryInt32:
107 return FromConstant(kMaxInt32);
108 case kRangeBoundaryInt64:
109 return FromConstant(kMaxInt64);
110 }
111 UNREACHABLE();
112 return FromConstant(kMaxInt64);
113 }
114
115
87 // Given two boundaries a and b, select one of them as c so that 116 // Given two boundaries a and b, select one of them as c so that
88 // 117 //
89 // inf {[a, ...) ^ [b, ...)} >= inf {c} 118 // inf {[a, ...) ^ [b, ...)} >= inf {c}
90 // 119 //
91 static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b); 120 static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b);
92 121
93 // Given two boundaries a and b, select one of them as c so that 122 // Given two boundaries a and b, select one of them as c so that
94 // 123 //
95 // sup {(..., a] ^ (..., b]} <= sup {c} 124 // sup {(..., a] ^ (..., b]} <= sup {c}
96 // 125 //
97 static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b); 126 static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b);
98 127
99 // Given two boundaries a and b compute boundary c such that 128 // Given two boundaries a and b compute boundary c such that
100 // 129 //
101 // inf {[a, ...) U [b, ...)} >= inf {c} 130 // inf {[a, ...) U [b, ...)} >= inf {c}
102 // 131 //
103 // Try to select c such that it is as close to inf {[a, ...) U [b, ...)} 132 // Try to select c such that it is as close to inf {[a, ...) U [b, ...)}
104 // as possible. 133 // as possible.
105 static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b); 134 static RangeBoundary JoinMin(RangeBoundary a,
135 RangeBoundary b,
136 RangeBoundary::RangeSize size);
106 137
107 // Given two boundaries a and b compute boundary c such that 138 // Given two boundaries a and b compute boundary c such that
108 // 139 //
109 // sup {(..., a] U (..., b]} <= sup {c} 140 // sup {(..., a] U (..., b]} <= sup {c}
110 // 141 //
111 // Try to select c such that it is as close to sup {(..., a] U (..., b]} 142 // Try to select c such that it is as close to sup {(..., a] U (..., b]}
112 // as possible. 143 // as possible.
113 static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b); 144 static RangeBoundary JoinMax(RangeBoundary a,
145 RangeBoundary b,
146 RangeBoundary::RangeSize size);
114 147
115 // Returns true when this is a constant that is outside of Smi range. 148 // Returns true when this is a constant that is outside of Smi range.
116 bool OverflowedSmi() const { 149 bool OverflowedSmi() const {
117 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); 150 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity();
118 } 151 }
119 152
153 bool Overflowed(RangeBoundary::RangeSize size) const {
154 ASSERT(IsConstantOrInfinity());
155 return !Equals(Clamp(size));
156 }
157
120 // Returns true if this outside mint range. 158 // Returns true if this outside mint range.
121 bool OverflowedMint() const { 159 bool OverflowedMint() const {
122 return IsInfinity(); 160 return IsInfinity();
123 } 161 }
124 162
125 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type. 163 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type.
126 RangeBoundary Clamp(RangeSize size) const { 164 RangeBoundary Clamp(RangeSize size) const {
127 if (IsNegativeInfinity()) { 165 if (IsNegativeInfinity()) {
128 return (size == kRangeBoundaryInt64) ? MinConstant() : MinSmi(); 166 return RangeBoundary::MinConstant(size);
129 } 167 }
168
130 if (IsPositiveInfinity()) { 169 if (IsPositiveInfinity()) {
131 return (size == kRangeBoundaryInt64) ? MaxConstant() : MaxSmi(); 170 return RangeBoundary::MaxConstant(size);
132 } 171 }
133 if ((size == kRangeBoundarySmi) && IsConstant()) { 172
134 if (ConstantValue() <= Smi::kMinValue) { 173 if (IsConstant()) {
135 return MinSmi(); 174 const RangeBoundary range_min = RangeBoundary::MinConstant(size);
175 const RangeBoundary range_max = RangeBoundary::MaxConstant(size);
176
177 if (ConstantValue() <= range_min.ConstantValue()) {
178 return range_min;
136 } 179 }
137 if (ConstantValue() >= Smi::kMaxValue) { 180 if (ConstantValue() >= range_max.ConstantValue()) {
138 return MaxSmi(); 181 return range_max;
139 } 182 }
140 } 183 }
184
141 // If this range is a symbolic range, we do not clamp it. 185 // If this range is a symbolic range, we do not clamp it.
142 // This could lead to some imprecision later on. 186 // This could lead to some imprecision later on.
143 return *this; 187 return *this;
144 } 188 }
145 189
146 bool IsSmiMinimumOrBelow() const { 190 bool IsMinimumOrBelow(RangeSize size) const {
147 return IsNegativeInfinity() || 191 return IsNegativeInfinity() ||
148 (IsConstant() && (ConstantValue() <= Smi::kMinValue)); 192 (IsConstant() &&
193 (ConstantValue() <= RangeBoundary::MinConstant(size).ConstantValue()));
149 } 194 }
150 195
151 bool IsSmiMaximumOrAbove() const { 196 bool IsMaximumOrAbove(RangeSize size) const {
152 return IsPositiveInfinity() || 197 return IsPositiveInfinity() ||
153 (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); 198 (IsConstant() &&
154 } 199 (ConstantValue() >= RangeBoundary::MaxConstant(size).ConstantValue()));
155
156 bool IsMinimumOrBelow() const {
157 return IsNegativeInfinity() || (IsConstant() && (ConstantValue() == kMin));
158 }
159
160 bool IsMaximumOrAbove() const {
161 return IsPositiveInfinity() || (IsConstant() && (ConstantValue() == kMax));
162 } 200 }
163 201
164 intptr_t kind() const { 202 intptr_t kind() const {
165 return kind_; 203 return kind_;
166 } 204 }
167 205
168 // Kind tests. 206 // Kind tests.
169 bool IsUnknown() const { return kind_ == kUnknown; } 207 bool IsUnknown() const { return kind_ == kUnknown; }
170 bool IsConstant() const { return kind_ == kConstant; } 208 bool IsConstant() const { return kind_ == kConstant; }
171 bool IsSymbol() const { return kind_ == kSymbol; } 209 bool IsSymbol() const { return kind_ == kSymbol; }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 276
239 // Attempts to calculate a - b when: 277 // Attempts to calculate a - b when:
240 // a is a symbol and b is a constant 278 // a is a symbol and b is a constant
241 // returns true if it succeeds, output is in result. 279 // returns true if it succeeds, output is in result.
242 static bool SymbolicSub(const RangeBoundary& a, 280 static bool SymbolicSub(const RangeBoundary& a,
243 const RangeBoundary& b, 281 const RangeBoundary& b,
244 RangeBoundary* result); 282 RangeBoundary* result);
245 283
246 bool Equals(const RangeBoundary& other) const; 284 bool Equals(const RangeBoundary& other) const;
247 285
286 int64_t UpperBound(RangeSize size) const {
287 return UpperBound().Clamp(size).ConstantValue();
288 }
289
290 int64_t LowerBound(RangeSize size) const {
291 return LowerBound().Clamp(size).ConstantValue();
292 }
293
248 int64_t SmiUpperBound() const { 294 int64_t SmiUpperBound() const {
249 return UpperBound().Clamp(kRangeBoundarySmi).ConstantValue(); 295 return UpperBound(kRangeBoundarySmi);
250 } 296 }
251 297
252 int64_t SmiLowerBound() const { 298 int64_t SmiLowerBound() const {
253 return LowerBound().Clamp(kRangeBoundarySmi).ConstantValue(); 299 return LowerBound(kRangeBoundarySmi);
254 } 300 }
255 301
256 private: 302 private:
257 RangeBoundary(Kind kind, int64_t value, int64_t offset) 303 RangeBoundary(Kind kind, int64_t value, int64_t offset)
258 : kind_(kind), value_(value), offset_(offset) { } 304 : kind_(kind), value_(value), offset_(offset) { }
259 305
260 Kind kind_; 306 Kind kind_;
261 int64_t value_; 307 int64_t value_;
262 int64_t offset_; 308 int64_t offset_;
263 }; 309 };
(...skipping 19 matching lines...) Expand all
283 } 329 }
284 330
285 static bool IsUnknown(const Range* other) { 331 static bool IsUnknown(const Range* other) {
286 if (other == NULL) { 332 if (other == NULL) {
287 return true; 333 return true;
288 } 334 }
289 return other->min().IsUnknown(); 335 return other->min().IsUnknown();
290 } 336 }
291 337
292 static Range Full(RangeBoundary::RangeSize size) { 338 static Range Full(RangeBoundary::RangeSize size) {
293 if (size == RangeBoundary::kRangeBoundarySmi) { 339 return Range(RangeBoundary::MinConstant(size),
294 return Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); 340 RangeBoundary::MaxConstant(size));
295 } else {
296 ASSERT(size == RangeBoundary::kRangeBoundaryInt64);
297 return Range(RangeBoundary::MinConstant(), RangeBoundary::MaxConstant());
298 }
299 } 341 }
300 342
301 void PrintTo(BufferFormatter* f) const; 343 void PrintTo(BufferFormatter* f) const;
302 static const char* ToCString(const Range* range); 344 static const char* ToCString(const Range* range);
303 345
304 bool Equals(const Range* other) { 346 bool Equals(const Range* other) {
305 ASSERT(min_.IsUnknown() == max_.IsUnknown()); 347 ASSERT(min_.IsUnknown() == max_.IsUnknown());
306 if (other == NULL) { 348 if (other == NULL) {
307 return min_.IsUnknown(); 349 return min_.IsUnknown();
308 } 350 }
309 return min_.Equals(other->min_) && 351 return min_.Equals(other->min_) &&
310 max_.Equals(other->max_); 352 max_.Equals(other->max_);
311 } 353 }
312 354
313 const RangeBoundary& min() const { return min_; } 355 const RangeBoundary& min() const { return min_; }
314 const RangeBoundary& max() const { return max_; } 356 const RangeBoundary& max() const { return max_; }
315 void set_min(const RangeBoundary& value) { 357 void set_min(const RangeBoundary& value) {
316 min_ = value; 358 min_ = value;
317 } 359 }
318 void set_max(const RangeBoundary& value) { 360 void set_max(const RangeBoundary& value) {
319 max_ = value; 361 max_ = value;
320 } 362 }
321 363
322 static RangeBoundary ConstantMinSmi(const Range* range) { 364 static RangeBoundary ConstantMinSmi(const Range* range) {
323 if (range == NULL) { 365 return ConstantMin(range, RangeBoundary::kRangeBoundarySmi);
324 return RangeBoundary::MinSmi();
325 }
326 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi);
327 } 366 }
328 367
329 static RangeBoundary ConstantMaxSmi(const Range* range) { 368 static RangeBoundary ConstantMaxSmi(const Range* range) {
330 if (range == NULL) { 369 return ConstantMax(range, RangeBoundary::kRangeBoundarySmi);
331 return RangeBoundary::MaxSmi();
332 }
333 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundarySmi);
334 } 370 }
335 371
336 static RangeBoundary ConstantMin(const Range* range) { 372 static RangeBoundary ConstantMin(const Range* range) {
337 if (range == NULL) { 373 return ConstantMin(range, RangeBoundary::kRangeBoundaryInt64);
338 return RangeBoundary::MinConstant();
339 }
340 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundaryInt64);
341 } 374 }
342 375
343 static RangeBoundary ConstantMax(const Range* range) { 376 static RangeBoundary ConstantMax(const Range* range) {
377 return ConstantMax(range, RangeBoundary::kRangeBoundaryInt64);
378 }
379
380 static RangeBoundary ConstantMin(const Range* range,
381 RangeBoundary::RangeSize size) {
344 if (range == NULL) { 382 if (range == NULL) {
345 return RangeBoundary::MaxConstant(); 383 return RangeBoundary::MinConstant(size);
346 } 384 }
347 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundaryInt64); 385 return range->min().LowerBound().Clamp(size);
348 } 386 }
349 387
388 static RangeBoundary ConstantMax(const Range* range,
389 RangeBoundary::RangeSize size) {
390 if (range == NULL) {
391 return RangeBoundary::MaxConstant(size);
392 }
393 return range->max().UpperBound().Clamp(size);
394 }
395
396
350 // [0, +inf] 397 // [0, +inf]
351 bool IsPositive() const; 398 bool IsPositive() const;
352 399
353 // [-inf, val]. 400 // [-inf, val].
354 bool OnlyLessThanOrEqualTo(int64_t val) const; 401 bool OnlyLessThanOrEqualTo(int64_t val) const;
355 402
356 // [val, +inf]. 403 // [val, +inf].
357 bool OnlyGreaterThanOrEqualTo(int64_t val) const; 404 bool OnlyGreaterThanOrEqualTo(int64_t val) const;
358 405
359 // Inclusive. 406 // Inclusive.
360 bool IsWithin(int64_t min_int, int64_t max_int) const; 407 bool IsWithin(int64_t min_int, int64_t max_int) const;
361 408
362 // Inclusive. 409 // Inclusive.
363 bool Overlaps(int64_t min_int, int64_t max_int) const; 410 bool Overlaps(int64_t min_int, int64_t max_int) const;
364 411
365 bool IsUnsatisfiable() const; 412 bool IsUnsatisfiable() const;
366 413
367 bool IsFinite() const { 414 bool IsFinite() const {
368 return !min_.IsInfinity() && !max_.IsInfinity(); 415 return !min_.IsInfinity() && !max_.IsInfinity();
369 } 416 }
370 417
371 Range Intersect(const Range* other) const { 418 Range Intersect(const Range* other) const {
372 return Range(RangeBoundary::IntersectionMin(min(), other->min()), 419 return Range(RangeBoundary::IntersectionMin(min(), other->min()),
373 RangeBoundary::IntersectionMax(max(), other->max())); 420 RangeBoundary::IntersectionMax(max(), other->max()));
374 } 421 }
375 422
423 bool Fits(RangeBoundary::RangeSize size) const {
424 return !min().LowerBound().Overflowed(size) &&
425 !max().UpperBound().Overflowed(size);
426 }
427
428 static bool Fits(Range* range, RangeBoundary::RangeSize size) {
429 return !IsUnknown(range) && range->Fits(size);
430 }
srdjan 2014/08/27 16:17:13 I think it is confusing to have a non-static and s
Vyacheslav Egorov (Google) 2014/08/28 20:48:37 Agreed. Moved into a separate AllStatic helper cla
431
376 // Clamp this to be within size. 432 // Clamp this to be within size.
377 void Clamp(RangeBoundary::RangeSize size); 433 void Clamp(RangeBoundary::RangeSize size);
378 434
379 static void Add(const Range* left_range, 435 static void Add(const Range* left_range,
380 const Range* right_range, 436 const Range* right_range,
381 RangeBoundary* min, 437 RangeBoundary* min,
382 RangeBoundary* max, 438 RangeBoundary* max,
383 Definition* left_defn); 439 Definition* left_defn);
384 440
385 static void Sub(const Range* left_range, 441 static void Sub(const Range* left_range,
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 void Iterate(JoinOperator op, intptr_t max_iterations); 552 void Iterate(JoinOperator op, intptr_t max_iterations);
497 bool InferRange(JoinOperator op, Definition* defn, intptr_t iteration); 553 bool InferRange(JoinOperator op, Definition* defn, intptr_t iteration);
498 554
499 // Based on computed ranges find and eliminate redundant CheckArrayBound 555 // Based on computed ranges find and eliminate redundant CheckArrayBound
500 // instructions. 556 // instructions.
501 void EliminateRedundantBoundsChecks(); 557 void EliminateRedundantBoundsChecks();
502 558
503 // Find unsatisfiable constraints and mark corresponding blocks unreachable. 559 // Find unsatisfiable constraints and mark corresponding blocks unreachable.
504 void MarkUnreachableBlocks(); 560 void MarkUnreachableBlocks();
505 561
562 // Convert mint operations that stay within int32 range into Int32 operations.
563 void NarrowMintToInt32();
564
506 // Remove artificial Constraint instructions and replace them with actual 565 // Remove artificial Constraint instructions and replace them with actual
507 // unconstrained definitions. 566 // unconstrained definitions.
508 void RemoveConstraints(); 567 void RemoveConstraints();
509 568
510 Range* ConstraintSmiRange(Token::Kind op, Definition* boundary); 569 Range* ConstraintSmiRange(Token::Kind op, Definition* boundary);
511 570
512 Isolate* isolate() const { return flow_graph_->isolate(); } 571 Isolate* isolate() const { return flow_graph_->isolate(); }
513 572
514 FlowGraph* flow_graph_; 573 FlowGraph* flow_graph_;
515 574
516 // Range object representing full Smi range. 575 // Range object representing full Smi range.
517 Range smi_range_; 576 Range smi_range_;
518 577
519 // Value that are known to be smi or mint. 578 // Value that are known to be smi or mint.
520 GrowableArray<Definition*> values_; 579 GrowableArray<Definition*> values_;
521 580
581 GrowableArray<BinaryMintOpInstr*> binary_mint_ops_;
582
583 GrowableArray<ShiftMintOpInstr*> shift_mint_ops_;
584
522 // All CheckArrayBound instructions. 585 // All CheckArrayBound instructions.
523 GrowableArray<CheckArrayBoundInstr*> bounds_checks_; 586 GrowableArray<CheckArrayBoundInstr*> bounds_checks_;
524 587
525 // All Constraints inserted during InsertConstraints phase. They are treated 588 // All Constraints inserted during InsertConstraints phase. They are treated
526 // as smi values. 589 // as smi values.
527 GrowableArray<ConstraintInstr*> constraints_; 590 GrowableArray<ConstraintInstr*> constraints_;
528 591
529 // List of integer (smi or mint) definitions including constraints sorted 592 // List of integer (smi or mint) definitions including constraints sorted
530 // in the reverse postorder. 593 // in the reverse postorder.
531 GrowableArray<Definition*> definitions_; 594 GrowableArray<Definition*> definitions_;
(...skipping 27 matching lines...) Expand all
559 BitVector* selected_uint32_defs_; 622 BitVector* selected_uint32_defs_;
560 623
561 FlowGraph* flow_graph_; 624 FlowGraph* flow_graph_;
562 Isolate* isolate_; 625 Isolate* isolate_;
563 }; 626 };
564 627
565 628
566 } // namespace dart 629 } // namespace dart
567 630
568 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ 631 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698