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

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

Issue 442293002: Consolidate all range analysis related code in a separate file. (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 | « runtime/vm/flow_graph_optimizer.cc ('k') | 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #ifndef VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
6 #define VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
7
8 #include "vm/flow_graph.h"
9 #include "vm/intermediate_language.h"
10
11 namespace dart {
12
13 class RangeBoundary : public ValueObject {
14 public:
15 enum Kind {
16 kUnknown,
17 kNegativeInfinity,
18 kPositiveInfinity,
19 kSymbol,
20 kConstant,
21 };
22
23 enum RangeSize {
24 kRangeBoundarySmi,
25 kRangeBoundaryInt64,
26 };
27
28 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { }
29
30 RangeBoundary(const RangeBoundary& other)
31 : ValueObject(),
32 kind_(other.kind_),
33 value_(other.value_),
34 offset_(other.offset_) { }
35
36 explicit RangeBoundary(int64_t val)
37 : kind_(kConstant), value_(val), offset_(0) { }
38
39 RangeBoundary& operator=(const RangeBoundary& other) {
40 kind_ = other.kind_;
41 value_ = other.value_;
42 offset_ = other.offset_;
43 return *this;
44 }
45
46 static const int64_t kMin = kMinInt64;
47 static const int64_t kMax = kMaxInt64;
48
49 // Construct a RangeBoundary for a constant value.
50 static RangeBoundary FromConstant(int64_t val) {
51 return RangeBoundary(val);
52 }
53
54 // Construct a RangeBoundary for -inf.
55 static RangeBoundary NegativeInfinity() {
56 return RangeBoundary(kNegativeInfinity, 0, 0);
57 }
58
59 // Construct a RangeBoundary for +inf.
60 static RangeBoundary PositiveInfinity() {
61 return RangeBoundary(kPositiveInfinity, 0, 0);
62 }
63
64 // Construct a RangeBoundary from a definition and offset.
65 static RangeBoundary FromDefinition(Definition* defn, int64_t offs = 0);
66
67 // Construct a RangeBoundary for the constant MinSmi value.
68 static RangeBoundary MinSmi() {
69 return FromConstant(Smi::kMinValue);
70 }
71
72 // Construct a RangeBoundary for the constant MaxSmi value.
73 static RangeBoundary MaxSmi() {
74 return FromConstant(Smi::kMaxValue);
75 }
76
77 // Construct a RangeBoundary for the constant kMin value.
78 static RangeBoundary MinConstant() {
79 return FromConstant(kMin);
80 }
81
82 // Construct a RangeBoundary for the constant kMax value.
83 static RangeBoundary MaxConstant() {
84 return FromConstant(kMax);
85 }
86
87 // Calculate the minimum of a and b within the given range.
88 static RangeBoundary Min(RangeBoundary a, RangeBoundary b, RangeSize size);
89 static RangeBoundary Max(RangeBoundary a, RangeBoundary b, RangeSize size);
90
91 // Returns true when this is a constant that is outside of Smi range.
92 bool OverflowedSmi() const {
93 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity();
94 }
95
96 // Returns true if this outside mint range.
97 bool OverflowedMint() const {
98 return IsInfinity();
99 }
100
101 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type.
102 RangeBoundary Clamp(RangeSize size) const {
103 if (IsNegativeInfinity()) {
104 return (size == kRangeBoundaryInt64) ? MinConstant() : MinSmi();
105 }
106 if (IsPositiveInfinity()) {
107 return (size == kRangeBoundaryInt64) ? MaxConstant() : MaxSmi();
108 }
109 if ((size == kRangeBoundarySmi) && IsConstant()) {
110 if (ConstantValue() <= Smi::kMinValue) {
111 return MinSmi();
112 }
113 if (ConstantValue() >= Smi::kMaxValue) {
114 return MaxSmi();
115 }
116 }
117 // If this range is a symbolic range, we do not clamp it.
118 // This could lead to some imprecision later on.
119 return *this;
120 }
121
122
123 bool IsSmiMinimumOrBelow() const {
124 return IsNegativeInfinity() ||
125 (IsConstant() && (ConstantValue() <= Smi::kMinValue));
126 }
127
128 bool IsSmiMaximumOrAbove() const {
129 return IsPositiveInfinity() ||
130 (IsConstant() && (ConstantValue() >= Smi::kMaxValue));
131 }
132
133 bool IsMinimumOrBelow() const {
134 return IsNegativeInfinity() || (IsConstant() && (ConstantValue() == kMin));
135 }
136
137 bool IsMaximumOrAbove() const {
138 return IsPositiveInfinity() || (IsConstant() && (ConstantValue() == kMax));
139 }
140
141 intptr_t kind() const {
142 return kind_;
143 }
144
145 // Kind tests.
146 bool IsUnknown() const { return kind_ == kUnknown; }
147 bool IsConstant() const { return kind_ == kConstant; }
148 bool IsSymbol() const { return kind_ == kSymbol; }
149 bool IsNegativeInfinity() const { return kind_ == kNegativeInfinity; }
150 bool IsPositiveInfinity() const { return kind_ == kPositiveInfinity; }
151 bool IsInfinity() const {
152 return IsNegativeInfinity() || IsPositiveInfinity();
153 }
154 bool IsConstantOrInfinity() const {
155 return IsConstant() || IsInfinity();
156 }
157
158 // Returns the value of a kConstant RangeBoundary.
159 int64_t ConstantValue() const;
160
161 // Returns the Definition associated with a kSymbol RangeBoundary.
162 Definition* symbol() const {
163 ASSERT(IsSymbol());
164 return reinterpret_cast<Definition*>(value_);
165 }
166
167 // Offset from symbol.
168 int64_t offset() const {
169 return offset_;
170 }
171
172 // Computes the LowerBound of this. Three cases:
173 // IsInfinity() -> NegativeInfinity().
174 // IsConstant() -> value().
175 // IsSymbol() -> lower bound computed from definition + offset.
176 RangeBoundary LowerBound() const;
177
178 // Computes the UpperBound of this. Three cases:
179 // IsInfinity() -> PositiveInfinity().
180 // IsConstant() -> value().
181 // IsSymbol() -> upper bound computed from definition + offset.
182 RangeBoundary UpperBound() const;
183
184 void PrintTo(BufferFormatter* f) const;
185 const char* ToCString() const;
186
187 static RangeBoundary Add(const RangeBoundary& a,
188 const RangeBoundary& b,
189 const RangeBoundary& overflow);
190
191 static RangeBoundary Sub(const RangeBoundary& a,
192 const RangeBoundary& b,
193 const RangeBoundary& overflow);
194
195 static RangeBoundary Shl(const RangeBoundary& value_boundary,
196 int64_t shift_count,
197 const RangeBoundary& overflow);
198
199 static RangeBoundary Shr(const RangeBoundary& value_boundary,
200 int64_t shift_count) {
201 ASSERT(value_boundary.IsConstant());
202 ASSERT(shift_count >= 0);
203 int64_t value = static_cast<int64_t>(value_boundary.ConstantValue());
204 int64_t result = value >> shift_count;
205 return RangeBoundary(result);
206 }
207
208 // Attempts to calculate a + b when:
209 // a is a symbol and b is a constant OR
210 // a is a constant and b is a symbol
211 // returns true if it succeeds, output is in result.
212 static bool SymbolicAdd(const RangeBoundary& a,
213 const RangeBoundary& b,
214 RangeBoundary* result);
215
216 // Attempts to calculate a - b when:
217 // a is a symbol and b is a constant
218 // returns true if it succeeds, output is in result.
219 static bool SymbolicSub(const RangeBoundary& a,
220 const RangeBoundary& b,
221 RangeBoundary* result);
222
223 bool Equals(const RangeBoundary& other) const;
224
225 private:
226 RangeBoundary(Kind kind, int64_t value, int64_t offset)
227 : kind_(kind), value_(value), offset_(offset) { }
228
229 Kind kind_;
230 int64_t value_;
231 int64_t offset_;
232 };
233
234
235 class Range : public ZoneAllocated {
236 public:
237 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { }
238
239 static Range* Unknown() {
240 return new Range(RangeBoundary::MinConstant(),
241 RangeBoundary::MaxConstant());
242 }
243
244 static Range* UnknownSmi() {
245 return new Range(RangeBoundary::MinSmi(),
246 RangeBoundary::MaxSmi());
247 }
248
249 void PrintTo(BufferFormatter* f) const;
250 static const char* ToCString(const Range* range);
251
252 const RangeBoundary& min() const { return min_; }
253 const RangeBoundary& max() const { return max_; }
254
255 static RangeBoundary ConstantMinSmi(const Range* range) {
256 if (range == NULL) {
257 return RangeBoundary::MinSmi();
258 }
259 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi);
260 }
261
262 static RangeBoundary ConstantMaxSmi(const Range* range) {
263 if (range == NULL) {
264 return RangeBoundary::MaxSmi();
265 }
266 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundarySmi);
267 }
268
269 static RangeBoundary ConstantMin(const Range* range) {
270 if (range == NULL) {
271 return RangeBoundary::MinConstant();
272 }
273 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundaryInt64);
274 }
275
276 static RangeBoundary ConstantMax(const Range* range) {
277 if (range == NULL) {
278 return RangeBoundary::MaxConstant();
279 }
280 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundaryInt64);
281 }
282
283 // [0, +inf]
284 bool IsPositive() const;
285
286 // [-inf, val].
287 bool OnlyLessThanOrEqualTo(int64_t val) const;
288
289 // [val, +inf].
290 bool OnlyGreaterThanOrEqualTo(int64_t val) const;
291
292 // Inclusive.
293 bool IsWithin(int64_t min_int, int64_t max_int) const;
294
295 // Inclusive.
296 bool Overlaps(int64_t min_int, int64_t max_int) const;
297
298 bool IsUnsatisfiable() const;
299
300 bool IsFinite() const {
301 return !min_.IsInfinity() && !max_.IsInfinity();
302 }
303
304 // Clamp this to be within size.
305 void Clamp(RangeBoundary::RangeSize size);
306
307 static void Add(const Range* left_range,
308 const Range* right_range,
309 RangeBoundary* min,
310 RangeBoundary* max,
311 Definition* left_defn);
312
313 static void Sub(const Range* left_range,
314 const Range* right_range,
315 RangeBoundary* min,
316 RangeBoundary* max,
317 Definition* left_defn);
318
319 static bool Mul(const Range* left_range,
320 const Range* right_range,
321 RangeBoundary* min,
322 RangeBoundary* max);
323 static void Shr(const Range* left_range,
324 const Range* right_range,
325 RangeBoundary* min,
326 RangeBoundary* max);
327
328 static void Shl(const Range* left_range,
329 const Range* right_range,
330 RangeBoundary* min,
331 RangeBoundary* max);
332
333 static bool And(const Range* left_range,
334 const Range* right_range,
335 RangeBoundary* min,
336 RangeBoundary* max);
337
338
339 // Both the a and b ranges are >= 0.
340 static bool OnlyPositiveOrZero(const Range& a, const Range& b);
341
342 // Both the a and b ranges are <= 0.
343 static bool OnlyNegativeOrZero(const Range& a, const Range& b);
344
345 // Return the maximum absolute value included in range.
346 static int64_t ConstantAbsMax(const Range* range);
347
348 static Range* BinaryOp(const Token::Kind op,
349 const Range* left_range,
350 const Range* right_range,
351 Definition* left_defn);
352
353 private:
354 RangeBoundary min_;
355 RangeBoundary max_;
356 };
357
358
359 // Range analysis for integer values.
360 class RangeAnalysis : public ValueObject {
361 public:
362 explicit RangeAnalysis(FlowGraph* flow_graph)
363 : flow_graph_(flow_graph),
364 marked_defns_(NULL) { }
365
366 // Infer ranges for all values and remove overflow checks from binary smi
367 // operations when proven redundant.
368 void Analyze();
369
370 private:
371 // Collect all values that were proven to be smi in smi_values_ array and all
372 // CheckSmi instructions in smi_check_ array.
373 void CollectValues();
374
375 // Iterate over smi values and constrain them at branch successors.
376 // Additionally constraint values after CheckSmi instructions.
377 void InsertConstraints();
378
379 // Iterate over uses of the given definition and discover branches that
380 // constrain it. Insert appropriate Constraint instructions at true
381 // and false successor and rename all dominated uses to refer to a
382 // Constraint instead of this definition.
383 void InsertConstraintsFor(Definition* defn);
384
385 // Create a constraint for defn, insert it after given instruction and
386 // rename all uses that are dominated by it.
387 ConstraintInstr* InsertConstraintFor(Definition* defn,
388 Range* constraint,
389 Instruction* after);
390
391 void ConstrainValueAfterBranch(Definition* defn, Value* use);
392 void ConstrainValueAfterCheckArrayBound(Definition* defn,
393 CheckArrayBoundInstr* check,
394 intptr_t use_index);
395
396 // Replace uses of the definition def that are dominated by instruction dom
397 // with uses of other definition.
398 void RenameDominatedUses(Definition* def,
399 Instruction* dom,
400 Definition* other);
401
402
403 // Walk the dominator tree and infer ranges for smi values.
404 void InferRanges();
405 void InferRangesRecursive(BlockEntryInstr* block);
406
407 enum Direction {
408 kUnknown,
409 kPositive,
410 kNegative,
411 kBoth
412 };
413
414 Range* InferInductionVariableRange(JoinEntryInstr* loop_header,
415 PhiInstr* var);
416
417 void ResetWorklist();
418 void MarkDefinition(Definition* defn);
419
420 static Direction ToDirection(Value* val);
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 }
433
434 // Remove artificial Constraint instructions and replace them with actual
435 // unconstrained definitions.
436 void RemoveConstraints();
437
438 Range* ConstraintRange(Token::Kind op, Definition* boundary);
439
440 Isolate* isolate() const { return flow_graph_->isolate(); }
441
442 FlowGraph* flow_graph_;
443
444 // Value that are known to be smi or mint.
445 GrowableArray<Definition*> values_;
446 // All CheckSmi instructions.
447 GrowableArray<CheckSmiInstr*> smi_checks_;
448
449 // All Constraints inserted during InsertConstraints phase. They are treated
450 // as smi values.
451 GrowableArray<ConstraintInstr*> constraints_;
452
453 // Bitvector for a quick filtering of known smi or mint values.
454 BitVector* definitions_;
455
456 // Worklist for induction variables analysis.
457 GrowableArray<Definition*> worklist_;
458 BitVector* marked_defns_;
459
460 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis);
461 };
462
463
464 // Replaces Mint IL instructions with Uint32 IL instructions
465 // when possible. Uses output of RangeAnalysis.
466 class IntegerInstructionSelector : public ValueObject {
467 public:
468 explicit IntegerInstructionSelector(FlowGraph* flow_graph);
469
470 void Select();
471
472 private:
473 bool IsPotentialUint32Definition(Definition* def);
474 void FindPotentialUint32Definitions();
475 bool IsUint32NarrowingDefinition(Definition* def);
476 void FindUint32NarrowingDefinitions();
477 bool AllUsesAreUint32Narrowing(Value* list_head);
478 bool CanBecomeUint32(Definition* def);
479 void Propagate();
480 Definition* ConstructReplacementFor(Definition* def);
481 void ReplaceInstructions();
482
483 Isolate* isolate() const { return isolate_; }
484
485 GrowableArray<Definition*> potential_uint32_defs_;
486 BitVector* selected_uint32_defs_;
487
488 FlowGraph* flow_graph_;
489 Isolate* isolate_;
490 };
491
492
493 } // namespace dart
494
495 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.cc ('k') | runtime/vm/flow_graph_range_analysis.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698